Secho was inspired by a post to the Plan 9 mailing list,
where, after a round of bashing on the Unix implementation of echo
,
the discussion went to bashing a hypothetical FSF-style implementation of echo
and eventually to:
NAME
echo: echo arguments
SYNOPSIS
echo [-1abCDEeilmNnOqrtuVvwXx] [-B base] [-c cmd] [-d char] [-f file] [-L len] [-o file] [-S voice] [-s char] [args…]
DESCRIPTION
echo outputs its arguments. It takes the following switches:
=-1= One argument per line. =-a= Output in ASCII. The default. =-B base= Output in given base, 2..32. Unless
-u
also given, base > 10 shows lowercase. =-b= Output in binary. =-C= Don’t echo anything, just print the number of fields. =-c cmd= Run cmd on each argument, replacing$?
with the argument itself. =-D= Output in decimal. =-d char= Field delimiter. Default is end of argument. =-E= Print to standard error instead of to standard output. =-e= Allow escape sequences =-f file= Read from file, then from command line (if any). =-i= Read arguments from standard input. =-L len= Line width set to len. Default is to ignore line lengths. =-l= Turn uppercase to lowercase. =-m= Multi-column output. =-N= One field per line, numbering each field. =-n= Suppress newline. =-O= Output in octal. =-o file= Write to file instead of standard output. =-q= “Quiet mode:” redirect output to/dev/null
if not to a file. =-r= Print every string that matches each regular expression. Regular expressions cannot contain+
or*
modifiers. =-S voice= Send to speaker, having the given voice say it. If voice is a null string, use the default voice. =-s char= Separate fields with char, default space. =-t= Separate fields with tabs. =-u= Convert lowercase to uppercase. With-B
, output in uppercase letters for base > 10. =-V= Strip non-printing characters. =-v= Make non-printing characters visible. =-w= If-L
is given, word wrap instead of character wrap. Otherwise, ignored. =-X= Output in uppercase hexadecimal. =-x= Output in lowercase hexadecimal.Test for everyone: write this echo in as little code as possible. C or rc is permitted. The rules:
- for C: either Standard C (no other libraries) or only libc (no other Plan 9 libraries)
- for rc: only use programs in the core Plan 9 distribution - no programs that I have to get myself
- match the behavior EXACTLY as above
- shortest code and fastest run time wins
Winner gets something cool.
“Oh ho,” said I, “A challenge!”
=v0.06=
How silly of me; I go to all this trouble to put long options in
and I forgot to add --version
or --copyright
.
=v0.05= It just isn’t the full modern Unix experience unless the program accepts long options.
=v0.04= Time to add a new feature!
The `-R` option prints out the ascii codes for each character,
but to improve readability it does it in roman numerals.
=v0.03=
Oh, look, the code wasn’t “portable” to FreeBSD 4.10. Tch, tch,
I’ll have to fix that. And while I’m at it, let me fix the
feature that stopped -r
from working when you specified non-ascii
output (I was running the re on the formatted buffer, which may
be useful if you’ve memorized ascii->base13 conversions, but is
not so useful if you’re a mortal.)
=v0.02=
Oh, what the hell, let’s make this code “portable” and
add a few more features:
1. Implement -L & -w.
2. Use a STRING(regex)
to hold regular
expressions, so I can have a potentially
unlimited number of them.
3. Have Cprintf()
write directly into the
destination Cstring instead of using
malloced memory and a copy.
4. Use xmalloc()
and xrealloc()
so that
failed memory allocations will properly
error out.
5. Use configure.sh to make this code “portable”.
6. use a built-in basename()
if a reentrant
basename can’t be found.
7. Add a copyright notice.
8. And some comments.
=v0.01=
Three hours of coding resulted in v0.01, which implements
most of the flags in the challenge. V0.01 doesn’t implement
-L
, -w
, -m
, and -S
, plus it doesn’t implement -r
exactly as specified (I use Henry Spencer’s regex for
the regular expressions, and it implements *
, so I’d need to
hack it to not support that feature and it’s not that important
to be feature-complete.)
To make up for losing these features, I've added `-0` (when
taking input from a file or stdin, fields are separated by
nulls), `-9` ([Plan 9][] compatability -- if no arguments
are given, don't print the trailing newline.), and `-?` (spit
out a usage message.)
Like every other piece of code I’m writing these days, I’m keeping track of code bloat. You can too!