Monday, January 09, 2012
99 ways to program a hex, Part 1: The Standard
For Christmas, Hoade gave me 99 Ways To Tell A Story: Excercises in Style, an interesting book whereby the same story (an eight panel cartoon about a guy walking to the refrigerator and forgetting what he was going to look for) ninety-nine different ways; a different style, a different genre, different number of panels, whatever. Ninety-nine different ways.
It got me to thinking. While the book was about different ways to present a story, what about programming? Okay, other than sounding completely insane, could a program be written ninety-nine different ways?
An easy way is a different computer language for each version. Sure, there's CPL, BCPL, B, C (four variations there—K&R, C89, C99, C11), C++ (C++, C++9x, C++2x), Objective-C, D, Fortran (many versions over the years), BASIC (just about every computer made between 1975 and 1985 came with its own dialect of BASIC, along with the original Dartmouth version), Algol (Agol 60, Algol 68), Pascal (Pascal, Turbo Pascal, Delphi), Assembly (basically each CPU architecture has its own form, for instance the 6502, 6800, 6809, 68000 (which has variant), 8080, Z80, 8086 (all the way up to the latest Pentium 4), MIPS (which has variants), SPARC (and variants), ARM (and variants), PDP-1, PHP-7, PHP-8, PHP-10, PHP-11, VAX) Forth (just as many dialects as BASIC), Modula (Modula and Modula-II), SNOBOL, ICON, Hope, bash, sh, csh, ksh, VIth, Alice, Pilot, COBOL, Intercal, Perl (several major variations), Piet, Python (Python 1, Python 2, Python 3), PHP (practically every version ever released), awk, Ruby (nearly every version ever released), Lua (several versions), Malbolge, Java (several major revisions), Lisp (Lisp, Lisp 1.5, MACLISP, Common Lisp, Scheme (I know! I know! It's not Lisp, even though it has the same syntax and pretty much the same command set, it's a LISP1 and Common Lisp is a LISP2 (and if you have to ask, you'll have to take a few graduate programming courses to understand))), Erlang, Prolog, Haskel, ML, Oberon, LOLCODE, Befunge, Chef, BrainXXXX and that alone will probably get us to 99 versions right there.
But I don't have access to a lot of these languages. Heck, most of them are dead, obscure or esoteric and trying to even find examples would be difficult. Especially since what I want to do is more than just a simple “Hello World” program. I want to write a program that is actually useful, but not so long as to make this insane project … um … insaner.
So I'm going to try just a few languages (which still leaves me with plenty to choose from; my home system alone comes with C, Ruby 1.8, Perl 5.8, Python 2.3, Python 2.6, PHP 5.1, Lua 5.1, C++, sh, bash, awk, 68000 assembler, x86 assembler and probably a few I'm forgetting about. I might not hit all of these, or maybe I will. We'll see.
And the program I selected for this insanity silly treatment
is a small utility I wrote back in the early 90s when I first learned
C—it's a program that dumps data in hexadecimal:
/************************************************************************* * * Copyright 1991 by Sean Conner. All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Comments, questions and criticisms can be sent to: sean@conman.org * *************************************************************************/ /* Style: Original Version, C89 */ #include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> #define LINESIZE 16 static void do_dump (FILE *,FILE *); /****************************************************************/ int main(int argc,char *argv[]) { if (argc == 1) do_dump(stdin,stdout); else { int i; for (i = 1 ; i < argc ; i++) { FILE *fp; fp = fopen(argv[i],"rb"); if (fp == NULL) { perror(argv[i]); continue; } printf("-----%s-----\n",argv[i]); do_dump(fp,stdout); fclose(fp); } } return EXIT_SUCCESS; } /******************************************************************/ static void do_dump(FILE *fpin,FILE *fpout) { unsigned char buffer[BUFSIZ]; unsigned char *pbyte; size_t offset; size_t bread; size_t j; char ascii[LINESIZE + 1]; offset = 0; while((bread = fread(buffer,1,BUFSIZ,fpin)) > 0) { pbyte = buffer; while (bread > 0) { fprintf(fpout,"%08lX: ",(unsigned long)offset); j = 0; do { fprintf(fpout,"%02X ",*pbyte); if (isprint(*pbyte)) ascii [j] = *pbyte; else ascii [j] = '.'; pbyte ++; offset ++; j ++; bread --; } while ((j < LINESIZE) && (bread > 0)); ascii [j] = '\0'; if (j < LINESIZE) { size_t i; for (i = j ; i < LINESIZE ; i++) fprintf(fpout," "); } fprintf(fpout,"%s\n",ascii); } if (fflush(fpout) == EOF) { perror("output"); exit(EXIT_FAILURE); } } } /***************************************************************/
This is the current version of the program, written in C89. There's not much to say about this—it's straight forward, does one thing, does it well, and we'll see just how far I can take this version.