home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3157 < prev    next >
Internet Message Format  |  1991-04-01  |  11KB

  1. From: linhart@cream.rutgers.edu (Mike Threepoint)
  2. Newsgroups: rec.games.misc,alt.sources,misc.misc
  3. Subject: Infocom vocabulary lister source, Release 3
  4. Message-ID: <Apr.2.00.11.25.1991.1303@cream.rutgers.edu>
  5. Date: 2 Apr 91 05:11:28 GMT
  6. Approved: nobody@remus.rutgers.edu
  7.  
  8. I previously posted this program over spring break, then received mail
  9. informing me that some people with short mail spools missed it.  I had
  10. made some portability fixes anyway, so here's Release 3.
  11.  
  12. This program extracts and translates the vocabulary list from the
  13. Infocom adventure game data files.  The data files should be the same
  14. format on any system.  The program should compile with only minor
  15. tweaks on any ANSI C compiler.
  16.  
  17. Thanks to everyone who responded, especially to the two hackers who
  18. wrote me about their C programs for ZIL interpreters, a project I
  19. myself was planning to undertake.  (And may still, since neither is
  20. complete to the point of supporting the opcodes in the newer
  21. Interactive Fiction Plus games, or the ones with Visiclues.)  Rather
  22. than expose them to a flood of unexpected email, I'll let them post
  23. about their respective projects if they wish.
  24.  
  25. Enjoy...
  26.  
  27. <-- snip, snip
  28. #define INFO "\
  29. vocab -- A data dumper\n\
  30. Copyleft (c) 1991 by Mike Threepoint.  All rights reversed.\n\
  31. Release 3 / Serial number 910401\n\
  32. \n\
  33. Display a vocabulary list of an Infocom(tm) adventure game data file.\n\
  34. \n\
  35. Usage:  vocab [-1] [-w] [-#] [-f] file...\n\
  36. \n\
  37. \t-1   one-column list\n\
  38. \t-w   wide list (default)\n\
  39. \t-#   toggle word numbers\n\
  40. \t-f   toggle flags\n\
  41. \n"
  42.  
  43. /* Now you can:
  44.  *    make sure you've seen every last Encyclopedia Frobizzica entry,
  45.  *    learned every spell in the Enchanter series,
  46.  *    know all the magic wand's F-words,
  47.  *    discover obscure synonyms (like calling the Zorkian elvish sword
  48.  *     Glamdring, the dragon Smaug, and the robot R2D2)
  49.  *    learn trivia about the game's internal operations (like the internal
  50.  *     `intnum' noun in several games, used when you type a number)
  51.  *    play with curious debugging commands hidden in some games (Stu Galley's
  52.  *     works are good for this)
  53.  *
  54.  * I doubt Infocom's employees will complain, either of them.  Alas, Infocom.
  55.  * I wore a black armband when you went under.    If only you'd stayed solvent.
  56.  * (At least till I could buy Sherlock and Arthur!  Can't purchase them
  57.  * anywhere anymore...)
  58.  *
  59.  * Email correspondence to linhart@remus.rutgers.edu.
  60.  *
  61.  * Disclaimer:    This program works for me, at the moment.  I've never seen
  62.  *        any Infocom source code(*), and nobody within the company
  63.  *        told me any technical details.    I'm just an independent
  64.  *        public domain software author.    If I-Need-Magic sues, I'll
  65.  *        cheerfully turn over all zero profits I made on this program.
  66.  *
  67.  * * (Well, maybe one function.  I noticed the Beyond Zork MS-DOS interpreter
  68.  *    was in MSC, so I mailed them a MSC function to get the screen size from
  69.  *    the BIOS instead of the stupid SETUP.EXE method, so the interpreter
  70.  *    could figure out when my VGA was in 50 line mode.  Some time later, a
  71.  *    new text game was released, with VisiClues.  I started it in 50-line
  72.  *    mode, but the screen was reset to 25-line CGA color mode.  And then the
  73.  *    text ran off the bottom of the screen and scrolled as if it were still
  74.  *    50 lines long.  I'd mail another helpful letter, but it's too late now.)
  75.  */
  76.  
  77. #define MAXCOL 79
  78.  
  79. #if !defined(__STDC__) && !defined(__TURBOC__)
  80. #error This is an ANSI-complaint.  It looks like you are not ANSI-compliant.
  81. #endif
  82.  
  83. #include <stdio.h>
  84. #include <stdlib.h>
  85. #include <stdarg.h>
  86. #include <string.h>
  87. #include <ctype.h>
  88.  
  89. #define S_BLANK     1
  90. #define S_MACRO1    2
  91. #define S_MACRO2    3
  92. #define S_MACRO3    4
  93. #define S_CAPS        5
  94. #define S_PUNC        6
  95. #define S_FILLER    6
  96. #define S_OFF        7
  97.  
  98. struct text {
  99.     unsigned ch3  : 5;
  100.     unsigned ch2  : 5;
  101.     unsigned ch1  : 5;
  102.     unsigned last : 1;
  103. };
  104.  
  105. /* the 5-bit character set */
  106. const char err_chars[7] = {
  107.     /* null thrown in for string handling */
  108.     '\0',
  109.     /* special codes above */
  110.     ' ', '1', '2', '3', '^', '@',
  111.     /* followed by: */
  112. };
  113.  
  114. typedef const char alfabet[26];
  115.  
  116. alfabet
  117. lower = {
  118.     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  119.     'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
  120.     },
  121. upper = {
  122.     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  123.     'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
  124.     },
  125. punct = {
  126.     '\0' /* ASCII literal */, '\n',
  127.     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  128.     '.', ',', '!', '?', '_', '#', '\'', '\"', '/', '\\', '-', ':', '(', ')'
  129.     };
  130.  
  131. typedef unsigned char    byte;
  132. typedef unsigned    z_word;
  133.  
  134. struct info_header {
  135.         byte    z_version;
  136.         byte    flags;
  137.     z_word    release;
  138.     z_word    resident_size;
  139.     z_word    game_offset;
  140.     z_word    vocab_offset;
  141.     z_word    object_offset;
  142.     z_word    variable_offset;
  143.     z_word    save_area_size;
  144.     z_word    script_status;
  145.     char    rev_date[6];
  146.     z_word    macro_offset;
  147.     z_word    verify_length;
  148.     z_word    verify_checksum;
  149.     z_word    reserved[17];
  150. };
  151.  
  152. FILE    *infile;
  153. short   column = 0,
  154.         columns = 0;
  155. char    show_flags = 0,
  156.     numbers = 0,
  157.     did_file = 0;
  158.  
  159. unsigned
  160. unzword ( z_word z )
  161. {
  162.     byte *zp = (byte *)&z;
  163.     return (zp[0] << 8) + zp[1];
  164. }
  165.  
  166. void
  167. newline ( void )
  168. {
  169.     putchar('\n');
  170.     column = 0;
  171. }
  172.  
  173. char *
  174. expand ( struct text *chars )
  175. {
  176.     static char buf[4] = {0, 0, 0, 0};
  177.  
  178.     buf[0] = chars->ch1 + 1;
  179.     buf[1] = chars->ch2 + 1;
  180.     buf[2] = chars->ch3 + 1;
  181.  
  182.     return buf;
  183. }
  184.  
  185. char *
  186. decode ( char *s )
  187. {
  188.     int        len = strlen(s);
  189.     static char    new[MAXCOL+1];
  190.     unsigned    newlen = 0;
  191.  
  192.     while (s[len-1] == S_FILLER)
  193.         s[--len] = '\0';
  194.  
  195.     while (*s) {
  196.         switch (*s) {
  197.             case S_MACRO1:
  198.             case S_MACRO2:
  199.             case S_MACRO3:
  200.                 /* shouldn't appear in vocabulary list */
  201.                 new [ newlen++ ] = err_chars[*s];
  202.                 break;
  203.             case S_CAPS:
  204.                 if (*(s+1) >= S_OFF)
  205.                     new [ newlen++ ] = upper[*++s - S_OFF];
  206.                 else
  207.                     new [ newlen++ ] = err_chars[S_CAPS];
  208.                 break;
  209.             case S_PUNC:
  210.                 if (*(s+1) >= S_OFF)
  211.                     if (*++s == S_OFF) {
  212.                         new [ newlen ] = ((*++s - 1) & 0x03) << 5;
  213.                         new [ newlen++ ] += *++s - 1;
  214.                     } else
  215.                         new [ newlen++ ] = punct[*s - S_OFF];
  216.                 else
  217.                     new [ newlen++ ] = err_chars[S_PUNC];
  218.                 break;
  219.             case S_BLANK:
  220.                 new [ newlen++ ] = ' ';
  221.                 break;
  222.             default:
  223.                 new [ newlen++ ] = lower[*s - S_OFF];
  224.         }
  225.         s++;
  226.     }
  227.  
  228.     new [ newlen ] = '\0';
  229.  
  230.     return new;
  231. }
  232.  
  233. void
  234. disp_ch ( char x )
  235. {
  236.     putchar(x);
  237.     column++;
  238. }
  239.  
  240. void
  241. disp_str ( char *fmt, ... )
  242. {
  243.     va_list     argptr;
  244.     static char    buf[16];
  245.     short        len;
  246.  
  247.     va_start(argptr, fmt);
  248.     vsprintf(buf, fmt, argptr);
  249.     va_end(argptr);
  250.  
  251.     len = strlen(buf);
  252.         printf(buf);
  253.     column += len;
  254. }
  255.  
  256. void
  257. disp_bits ( char c )
  258. {
  259.     unsigned b;
  260.  
  261.     disp_ch(' ');
  262.     for (b = 0x80; b; b >>= 1)
  263.         disp_ch(c & b ? '1' : '0');
  264. }
  265.  
  266. void
  267. error ( char *fmt, ... )
  268. {
  269.     va_list     argptr;
  270.  
  271.     fprintf(stderr, "\nError: ");
  272.  
  273.     va_start(argptr, fmt);
  274.     vfprintf(stderr, fmt, argptr);
  275.     va_end(argptr);
  276.  
  277.     exit(1);
  278. }
  279.  
  280. void
  281. read_error ( void )
  282. {
  283.     error("Can't read file at offset %04X.\n", ftell(infile));
  284. }
  285.  
  286. void
  287. dump_vocab ( unsigned long pos )
  288. {
  289.     register unsigned    count = 0, index;
  290.     unsigned        words;
  291.     int            vocab_entry_size;
  292.     byte            letters_per_word,
  293.                 zwords_per_word;
  294.         short                   entry_width,
  295.                                 entries_per_line;
  296.     char            format[sizeof("%%-%ds")];
  297.     char *            buf;
  298.  
  299. #ifdef DEBUG
  300.     printf("Vocabulary table at offset %04X\n", pos);
  301. #endif
  302.  
  303.     if (fseek(infile, pos, SEEK_SET) != 0)
  304.         error("Can't seek offset %04X.\n", pos);
  305.  
  306.     /* skip leading info */
  307.     if ((pos = getc(infile)) == EOF)
  308.         read_error();
  309.  
  310.     if (fseek(infile, pos, SEEK_CUR) != 0)
  311.         error("Can't skip %ld bytes from offset %04X.\n", pos, ftell(infile));
  312.  
  313.     if ((vocab_entry_size = getc(infile)) == EOF)
  314.         read_error();
  315.  
  316.     if (fread(&words, sizeof(words), 1, infile) < 1)
  317.         read_error();
  318.     words = unzword(words);
  319.     if (!numbers)
  320.                 printf("%u vocabulary entries\n", words);
  321.  
  322.     letters_per_word = (vocab_entry_size - 3) / 2 * 3;
  323.     zwords_per_word = letters_per_word / 3;
  324.  
  325.         entry_width = letters_per_word + 2;
  326.         if (numbers)
  327.                 entry_width += 5;
  328.         if (show_flags)
  329.                 entry_width += 3 * (columns == 1 ? 8 : 2) + 3;
  330.         entries_per_line = columns ? columns : (MAXCOL + 2) / entry_width;
  331.         
  332.     buf = malloc(letters_per_word + 1);
  333.     sprintf(format, "%%-%ds", letters_per_word);
  334.  
  335.     while ( count < words ) {
  336.         byte    flags[3];
  337.  
  338.         ++count;
  339.         if (numbers)
  340.             disp_str("%04d ", count);
  341.  
  342.         for (index = 0; index < zwords_per_word; index++) {
  343.             unsigned    z;
  344.  
  345.             if (fread(&z, sizeof(z), 1, infile) < 1)
  346.                 read_error();
  347.             z = unzword(z);
  348.             if (index)
  349.                                 strcat(buf, expand((struct text *)&z));
  350.             else
  351.                                 strcpy(buf, expand((struct text *)&z));
  352.         }
  353.  
  354.                 disp_str(format, decode(buf));
  355.  
  356.         if (fread(flags, sizeof(char), 3, infile) < 3)
  357.             read_error();
  358.  
  359.                 if (show_flags)
  360.                         if (columns == 1) {
  361.                 disp_ch(' ');
  362.                 disp_bits(flags[1]);
  363.                 disp_bits(flags[2]);
  364.                 disp_bits(flags[3]);
  365.                         } else
  366.                                 disp_str("  %02x %02x %02x", flags[1], flags[2], flags[3]);
  367.  
  368.                 if (entries_per_line > 1 && (count % entries_per_line))
  369.             disp_str("  ");
  370.         else
  371.             newline();
  372.     }
  373.  
  374.     free(buf);
  375.  
  376.     if (column)
  377.         newline();
  378. }
  379.  
  380. void
  381. frob_file ( const char *filename )
  382. {
  383.     struct info_header    header;
  384.  
  385.     if((infile = fopen(filename, "rb")) == NULL)
  386.         error("Can't open file \"%s\".\n", filename);
  387.  
  388.     printf("%s:\n", filename);
  389.  
  390.     if (fread(&header, sizeof(header), 1, infile) < 1)
  391.         read_error();
  392.     printf("Release %u / Serial number %.6s\n", unzword(header.release), &header.rev_date[0]);
  393.  
  394.     dump_vocab(unzword(header.vocab_offset));
  395.  
  396.     fclose(infile);
  397. }
  398.  
  399. #ifndef LINT
  400. const char sccsid[] = "@(#) " __FILE__ " by Mike Threepoint compiled " __DATE__;
  401. #endif
  402.  
  403. void
  404. info ( void )
  405. {
  406.     puts(INFO);
  407.     exit(0);
  408. }
  409.  
  410. void
  411. parse_opt ( char p )
  412. {
  413.     switch (p) {
  414.         case 'w':
  415.                         columns = 0;
  416.             break;
  417.         case '#':
  418.         case 'n':
  419.             numbers = !numbers;
  420.             break;
  421.                 case 'f':
  422.                 case 'b':
  423.                         show_flags = !show_flags;
  424.             break;
  425.                 case 'h':
  426.         case '?':
  427.             info();
  428.                         break;
  429.                 default:
  430.                         if (isdigit(p))
  431.                                 columns = (p - '0');
  432.     }
  433. }
  434.  
  435. void
  436. parse ( char *parm )
  437. {
  438.     switch (*parm) {
  439.         case '/':
  440.             parse_opt(*++parm);
  441.             break;
  442.         case '-':
  443.             while (*++parm) parse_opt(*parm);
  444.             break;
  445.         default:
  446.             if (did_file) newline();
  447.             frob_file(parm);
  448.             did_file = 1;
  449.     }
  450. }
  451.  
  452. int
  453. main ( const unsigned argc, char *argv[] )
  454. {
  455.     if (argc > 1) {
  456.         register count;
  457.  
  458.         if (strcmp(argv[1], "?") == 0)
  459.             info();
  460.  
  461.         for (count = 1; count < argc; count++)
  462.             parse(argv[count]);
  463.  
  464.         if (did_file) return 0;
  465.     }
  466.  
  467.     info();
  468.     return 1;
  469. }
  470.