9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* [9fans] seq with hex, octal formats
@ 2010-02-27 19:01 erik quanstrom
  2010-02-28  0:12 ` Russ Cox
  0 siblings, 1 reply; 5+ messages in thread
From: erik quanstrom @ 2010-02-27 19:01 UTC (permalink / raw)
  To: 9fans

[-- Attachment #1: Type: text/plain, Size: 594 bytes --]

i've attached a little program that extends
seq to print sequences in hex or octal.  for example,

	;  seq.rc -f %.4x 0x3b1 0x3b2
	03b1
	03b2

i did it in rc (really awk) because it was too tedious
to get the details right in c.

as such, formats are as in printf(2) not as in print(2).
this is a bug, but i don't see a reasonable workaround.

even using awk and adding functionality, the new
program is *way* faster than seq:

	; >/dev/null time seq 1 100000
	1.90u 0.09s 1.99r 	 seq 1 100000
	; >/dev/null time seq.rc 1 100000
	0.28u 0.00s 0.29r 	 seq.rc 1 100000

- erik

[-- Attachment #2: seq.rc --]
[-- Type: text/plain, Size: 2291 bytes --]

#!/bin/rc

awk '
function hex(s,        base, r, n, i, k, c)
{
	base = 16;
	if(s ~ /^0[xX][0-9a-fA-F]+/)
		s = substr(str, 3);
	n = length(s)
  	r = 0
	for (i = 1; i <= n; i++) {
		c = tolower(substr(s, i, 1))
		k = index("0123456789abcdef", c) - 1;
		r = r * base + k
	}
     	return r
}

function mystrtonum(str0,        neg, base, str, r, n, i, k, c)
{
	base = 0;
	neg = 0;
	str = str0;
	if(str ~ /^\+/)
		str = substr(str, 2)
	if(str ~ /^-/){
		str = substr(str, 2)
		neg = 1
	}
	if(str ~ /^0[0-7]*$/)
		base = 8
	if(str ~ /^0[xX][0-9a-fA-F]+/){
		str = substr(str, 3);
		base = 16;
	}
	if(base != 0){
		n = length(str)
  		r = 0
		for (i = 1; i <= n; i++) {
			c = tolower(substr(str, i, 1))
			k = index("0123456789abcdef", c) - 1;
			r = r * base + k
		}
	}else if(str ~ /^[0-9]*([.][0-9]*)?([Ee][-+]?[0-9]+)?$/)
		r = str0 + 0
	else
		r = "NaN"
     	return r
}

function usage()
{
	print "usage: seq [-w] [-f fmt] min [inc] max" > "/fd/2"
	exit(1);
}

function EARGF()
{
	if(j + 1 < length(a))
		return substr(a, j+1, 100);
	i++;
	if(i >= ARGC)
		usage();
	return ARGV[i];
}

function args()
{
	for(i = 1; i < ARGC; i++){
		a = ARGV[i]
		if(a !~ /^-..*/)
			break;
		for(j = 2; j <= length(a); j++){
			c = substr(a, j, 1);
			if(c == "w")
				flagw = 1
			else if(c == "f"){
				format = EARGF()
				if(format !~ /\n$/)
					format = format "\n"
			}else
				usage()
		}
	}
	n = ARGC - i
	if(n != 2 && n != 3)
		usage()
	min = mystrtonum(ARGV[i++])
	incr = 1
	if(n == 3)
		incr = mystrtonum(ARGV[i++])
	max = mystrtonum(ARGV[i++])
}

function buildfmt()
{
	if(length(format) > 0)
		return;
	format = "%g\n";
	if(!flagw)
		return;
	maxw = 0;
	maxp = 0;
	for(val = min; val <= max; val += incr){
		buf = sprintf("%g", val)
		if(buf ~ /e/)
			return
		parts = split(buf, ary, "\.");
		w = length(ary[1]);
		p = length(ary[2]) + parts==2;
		if(w>maxw)
			maxw = w;
		if(p>maxp)
			maxp = p;
	}
	if(maxp > 0)
		maxw += maxp+1;
	format = sprintf("%%0%d.%df\n", maxw, maxp);
}

BEGIN{
	args();
	buildfmt()

	for(val = min;; val += incr){
		if(incr > 0 && val > max)
			break;
		if(incr < 0 && val < max)
			break;
		printf(format, val)
	}

	exit(0);
}' $*

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9fans] seq with hex, octal formats
  2010-02-27 19:01 [9fans] seq with hex, octal formats erik quanstrom
@ 2010-02-28  0:12 ` Russ Cox
  2010-02-28  1:59   ` erik quanstrom
  0 siblings, 1 reply; 5+ messages in thread
From: Russ Cox @ 2010-02-28  0:12 UTC (permalink / raw)
  To: Fans of the OS Plan 9 from Bell Labs

diff -r 3024d1ef1140 src/cmd/seq.c
--- a/src/cmd/seq.c	Wed Sep 30 11:01:45 2009 -0700
+++ b/src/cmd/seq.c	Sat Feb 27 16:11:56 2010 -0800
@@ -47,6 +47,39 @@
 	format = fmt;
 }

+extern int __ifmt(Fmt*);	// _ifmt on Plan 9
+
+static int
+doifmt(Fmt *f, ...)
+{
+	int rv;
+	va_list argsav;
+
+	f->flags |= FmtVLong;
+	va_copy(argsav, f->args);
+	va_end(f->args);
+	va_start(f->args, f);
+	rv = __ifmt(f);
+	va_end(f->args);
+	va_copy(f->args, argsav);
+	va_end(argsav);
+	return rv;
+}
+
+static int
+ifmt(Fmt *f)
+{
+	int rv;
+	static int running;
+
+	if(running)
+		return __ifmt(f);
+	running = 1;
+	rv = doifmt(f, (vlong)va_arg(f->args, double));
+	running = 0;
+	return rv;
+}
+
 void
 main(int argc, char *argv[]){
 	int j, n;
@@ -79,7 +112,11 @@
 		fprint(2, "seq: zero increment\n");
 		exits("zero increment");
 	}
-	if(!format)
+	if(format){
+		fmtinstall('d', ifmt);
+		fmtinstall('o', ifmt);
+		fmtinstall('x', ifmt);
+	}else
 		buildfmt();
 	if(incr > 0){
 		for(val = min; val <= max; val += incr){


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9fans] seq with hex, octal formats
  2010-02-28  0:12 ` Russ Cox
@ 2010-02-28  1:59   ` erik quanstrom
  2010-02-28  2:07     ` Lyndon Nerenberg (VE6BBM/VE7TFX)
  0 siblings, 1 reply; 5+ messages in thread
From: erik quanstrom @ 2010-02-28  1:59 UTC (permalink / raw)
  To: 9fans

very nice!

one problem, ifmt can crash with the argument -f %g.
fomatting %g will mean that !running to be true when
calling ifmt, thus ifmt will try to va_arg a double cast to
vlong when formatting an integer:

/sys/src/libc/fmt/fltfmt.c:136: 		sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
/sys/src/libc/fmt/fltfmt.c:142: 			sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
/sys/src/libc/fmt/fltfmt.c:155: 		sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);

(actually, on testing, this version spins rather than crashes
on plan 9:
; ps -a | grep 1308769
quanstro    1308769    1:30   0:00       28K Running  8.seqrsc -f %g 1 5
)

using awk is still faster, and more
fundamentally, avoids crashing on bogus
formats like %g%g.

(also, -w doesn't work with either version
with a %x format because 'e' is a valid hex
digit and not an exponent.)

- erik



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9fans] seq with hex, octal formats
  2010-02-28  1:59   ` erik quanstrom
@ 2010-02-28  2:07     ` Lyndon Nerenberg (VE6BBM/VE7TFX)
  2010-02-28  2:15       ` erik quanstrom
  0 siblings, 1 reply; 5+ messages in thread
From: Lyndon Nerenberg (VE6BBM/VE7TFX) @ 2010-02-28  2:07 UTC (permalink / raw)
  To: 9fans

> using awk is still faster

For the curious and lazy ... why is that?




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9fans] seq with hex, octal formats
  2010-02-28  2:07     ` Lyndon Nerenberg (VE6BBM/VE7TFX)
@ 2010-02-28  2:15       ` erik quanstrom
  0 siblings, 0 replies; 5+ messages in thread
From: erik quanstrom @ 2010-02-28  2:15 UTC (permalink / raw)
  To: 9fans

On Sat Feb 27 21:08:17 EST 2010, lyndon@orthanc.ca wrote:
> > using awk is still faster
>
> For the curious and lazy ... why is that?

it is curious!

it appears that the ape strtod is much faster,
though it isn't quite correct:

both of these are in /sys/src/libc/port/strtod.c

  %     Time     Calls  Name
43.8    3.492  4385186	fpcmp
35.0    2.788 62445696	frnorm

- erik



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2010-02-28  2:15 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-02-27 19:01 [9fans] seq with hex, octal formats erik quanstrom
2010-02-28  0:12 ` Russ Cox
2010-02-28  1:59   ` erik quanstrom
2010-02-28  2:07     ` Lyndon Nerenberg (VE6BBM/VE7TFX)
2010-02-28  2:15       ` erik quanstrom

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).