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!”
--version
or --copyright
.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.
-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.)STRING(regex)
to hold regular
expressions, so I can have a potentially
unlimited number of them.Cprintf()
write directly into the
destination Cstring instead of using
malloced memory and a copy.xmalloc()
and xrealloc()
so that
failed memory allocations will properly
error out.basename()
if a reentrant
basename can’t be found.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!