% Secho -- The ultimate echo, actually useful, but no one wants it. % Jessica L. Parsons % Sat Apr 5 13:17:00 PDT 2008 #Secho# ->![Aaaiiieeee](Munch_The_Scream_lithography.jpg =99x141)<- **Secho** was inspired by a post to the [Plan 9][] mailing list, where, after a round of bashing on the Unix implementation of [`echo`][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!_" ##Source Code## * * * =[v0.06](secho-0.06.tar.gz)= 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](secho-0.05.tar.gz)= It just isn't the full modern Unix experience unless the program accepts long options. =[v0.04](secho-0.04.tar.gz)= 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](secho-0.03.tar.gz)= 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](secho-0.02.tar.gz)= 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](secho-0.01.tar.gz)= 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.) ##Trivia * * * Like every other piece of code I'm writing these days, I'm [keeping track of code bloat](bloat.gif). You can too! [Plan 9]: http://plan9.bell-labs.com/plan9/ [echo]: http://en.wikipedia.org/wiki/Echo_%28computing%29 [Henry Spencer]: http://en.wikipedia.org/wiki/Henry_Spencer [regex]: http://www.google.com/search?q=Henry+Spencer+regex