home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3872 < prev    next >
Encoding:
Text File  |  1991-08-22  |  11.6 KB  |  559 lines

  1. Xref: wupost rec.games.misc:14996 rec.arts.int-fiction:561 alt.sources:3872 misc.misc:8050
  2. Path: wupost!zaphod.mps.ohio-state.edu!mips!dimacs.rutgers.edu!aramis.rutgers.edu!remus.rutgers.edu!ratt.rutgers.edu!linhart
  3. From: linhart@ratt.rutgers.edu (Mike Threepoint)
  4. Newsgroups: rec.games.misc,rec.arts.int-fiction,alt.sources,misc.misc
  5. Subject: Infocom vocabulary lister source, Release 6
  6. Summary: ANSI C source for an Infocom vocabulary lister
  7. Keywords: Infocom adventure game vocabulary list, C source
  8. Message-ID: <Aug.20.16.38.03.1991.3402@ratt.rutgers.edu>
  9. Date: 20 Aug 91 20:38:04 GMT
  10. Followup-To: rec.games.misc
  11. Organization: Frobozz Magic Amulet of Yendor Company
  12. Lines: 544
  13. Approved: nobody@remus.rutgers.edu
  14.  
  15. A few people sent email telling me about problems with integer sizes
  16. and byte sex with the last version I posted.  I made several fixes to
  17. get it to work under both MS-DOS and UNIX.
  18.  
  19. This program extracts and translates the vocabulary list from the
  20. Infocom adventure game data files.  The data files should be the same
  21. format on any system.  The program should compile with only minor
  22. tweaks on any ANSI C compiler.
  23.  
  24. Thanks to everyone who responded.  Some of the replies I sent were
  25. returned, sorry if you didn't get a response.
  26.  
  27. Enjoy...
  28.  
  29. <-- snip, snip
  30. #define INFO "\
  31. vocab -- A data dumper\n\
  32. Copyleft (c) 1991 by Mike Threepoint.  All rights reversed.\n\
  33. Release 6 / Serial number 910608\n\
  34. \n\
  35. Display a vocabulary list of an Infocom(tm) adventure game data file.\n\
  36. \n\
  37. Usage:  vocab [-1] [-w] [-#] [-f] file...\n\
  38. \n\
  39. \t-1   one-column list\n\
  40. \t-w   wide list (default)\n\
  41. \t-#   toggle word numbers\n\
  42. \t-f   toggle flags\n\
  43. \n"
  44.  
  45. /* Now you can:
  46.  *    make sure you've seen every last Encyclopedia Frobizzica entry,
  47.  *    learned every spell in the Enchanter series,
  48.  *    know all the magic wand's F-words,
  49.  *    discover obscure synonyms (like calling the Zorkian elvish sword
  50.  *     Glamdring, the dragon Smaug, and the robot R2D2)
  51.  *    learn trivia about the game's internal operations (like the internal
  52.  *     `intnum' noun in several games, used when you type a number)
  53.  *    play with curious debugging commands hidden in some games (Stu Galley's
  54.  *     works are good for this)
  55.  *
  56.  * I doubt Infocom's employees will complain, either of them.  Alas, Infocom.
  57.  * I wore a black armband when you went under.  If only you'd stayed solvent.
  58.  * (At least till I could buy Sherlock and Arthur!  Can't purchase them
  59.  * anywhere anymore...)
  60.  *
  61.  * Email correspondence to linhart@remus.rutgers.edu.
  62.  *
  63.  * Disclaimer:    This program works for me, at the moment.  I've never seen
  64.  *        any Infocom source code(*).  Nobody within the company told
  65.  *        me any technical details.   I'm just an independent public
  66.  *        domain software author.  If I-Need-Magic sues, I'll
  67.  *        cheerfully turn over all zero profits I made on this program.
  68.  *
  69.  * * (Well, maybe one function.  I noticed the Beyond Zork MS-DOS interpreter
  70.  *    was in MSC, so I mailed them a MSC function to get the screen size from
  71.  *    the BIOS instead of the stupid SETUP.EXE method, so the interpreter
  72.  *    could figure out when my VGA was in 50 line mode.  Some time later, a
  73.  *    new text game was released, with VisiClues.  I started it in 50-line
  74.  *    mode, but the screen was reset to 25-line CGA color mode.  And then the
  75.  *    text ran off the bottom of the screen and scrolled as if it were still
  76.  *    50 lines long.  I'd mail another helpful letter, but it's too late now.)
  77.  */
  78.  
  79. #define MAXCOL    79
  80. #define BUFSIZ    512
  81.  
  82. #if !defined(__STDC__) && !defined(__GNUC__) && !defined(__TURBOC__)
  83. #error This is an ANSI-complaint.  It looks like you are not ANSI-compliant.
  84. #endif
  85.  
  86. #include <stdio.h>
  87. #include <stdlib.h>
  88. #include <stdarg.h>
  89. #include <string.h>
  90. #include <ctype.h>
  91.  
  92. #ifndef SEEK_SET
  93. #define SEEK_SET    0
  94. #endif
  95.  
  96. #define S_BLANK     1
  97. #define S_MACRO1    2
  98. #define S_MACRO2    3
  99. #define S_MACRO3    4
  100. #define S_CAPS        5
  101. #define S_PUNC        6
  102. #define S_FILLER    6
  103. #define S_OFF        7
  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. char *macros[3][32];
  132.  
  133. typedef unsigned char    byte;
  134. typedef unsigned short    word;
  135. typedef unsigned short    z_word;
  136.  
  137. struct info_header {
  138.     byte    z_version;
  139.     byte    flags;
  140.     z_word    release;
  141.     z_word    resident_size;
  142.     z_word    game_offset;
  143.     z_word    vocab_offset;
  144.     z_word    object_offset;
  145.     z_word    variable_offset;
  146.     z_word    save_area_size;
  147.     z_word    script_status;
  148.     char    rev_date[6];
  149.     z_word    macro_offset;
  150.     z_word    verify_length;
  151.     z_word    verify_checksum;
  152.     z_word    reserved[17];
  153. };
  154.  
  155. FILE    *infile;
  156. short    column = 0,
  157.     columns = 0;
  158. char    show_flags = 0,
  159.     numbers = 0,
  160.     macro_dump = 0,
  161.     did_file = 0;
  162.  
  163. unsigned
  164. unzword ( z_word z )
  165. {
  166.     byte *zp = (byte *)&z;
  167.     return (zp[0] << 8) + zp[1];
  168. }
  169.  
  170. void
  171. newline ( void )
  172. {
  173.     putchar('\n');
  174.     column = 0;
  175. }
  176.  
  177. short
  178. end_of_text ( word chars )
  179. {
  180.     return chars >> 15;
  181. }
  182.  
  183. char *
  184. expand ( word chars )
  185. {
  186.     static char buf[4] = {0, 0, 0, 0};
  187.  
  188.     buf[2] = (chars & 0x1F) + 1;
  189.     chars >>= 5;
  190.     buf[1] = (chars & 0x1F) + 1;
  191.     chars >>= 5;
  192.     buf[0] = (chars & 0x1F) + 1;
  193.  
  194.     return buf;
  195. }
  196.  
  197. char *
  198. decode ( char *s )
  199. {
  200.     int        len = strlen(s);
  201.     static char    new[BUFSIZ];
  202.     unsigned    newlen = 0;
  203.  
  204.     while (s[len-1] == S_FILLER)
  205.         s[--len] = '\0';
  206.  
  207.     while (*s) {
  208.         switch (*s) {
  209.             case S_MACRO1:
  210.             case S_MACRO2:
  211.             case S_MACRO3:
  212. #ifdef VOCAB_ALONE
  213.                 /* shouldn't appear in vocabulary list */
  214.                 new [ newlen++ ] = err_chars[*s];
  215. #else
  216.                 {
  217.                     char *tmp = macros[(*s)-2][(*(s+1))-1];
  218.                     s++;
  219.                     if (tmp) {
  220.                         strcpy(&new [ newlen ], tmp);
  221.                         newlen += strlen(tmp);
  222.                     }
  223.                 }
  224. #endif
  225.                 break;
  226.             case S_CAPS:
  227.                 if (*(s+1) >= S_OFF)
  228.                     new [ newlen++ ] = upper[*++s - S_OFF];
  229.                 else
  230.                     new [ newlen++ ] = err_chars[S_CAPS];
  231.                 break;
  232.             case S_PUNC:
  233.                 if (*(s+1) >= S_OFF)
  234.                     if (*++s == S_OFF) {
  235.                         new [ newlen ] = ((*++s - 1) & 0x03) << 5;
  236.                         new [ newlen++ ] += *++s - 1;
  237.                     } else
  238.                         new [ newlen++ ] = punct[*s - S_OFF];
  239.                 else
  240.                     new [ newlen++ ] = err_chars[S_PUNC];
  241.                 break;
  242.             case S_BLANK:
  243.                 new [ newlen++ ] = ' ';
  244.                 break;
  245.             default:
  246.                 new [ newlen++ ] = lower[*s - S_OFF];
  247.         }
  248.         s++;
  249.     }
  250.  
  251.     new [ newlen ] = '\0';
  252.  
  253.     return new;
  254. }
  255.  
  256. void
  257. disp_ch ( char x )
  258. {
  259.     putchar(x);
  260.     column++;
  261. }
  262.  
  263. void
  264. disp_str ( char *fmt, ... )
  265. {
  266.     va_list     argptr;
  267.     static char    buf[16];
  268.     short        len;
  269.  
  270.     va_start(argptr, fmt);
  271.     vsprintf(buf, fmt, argptr);
  272.     va_end(argptr);
  273.  
  274.     len = strlen(buf);
  275.     printf(buf);
  276.     column += len;
  277. }
  278.  
  279. void
  280. disp_bits ( char c )
  281. {
  282.     unsigned b;
  283.  
  284.     disp_ch(' ');
  285.     for (b = 0x80; b; b >>= 1)
  286.         disp_ch(c & b ? '1' : '0');
  287. }
  288.  
  289. void
  290. error ( char *fmt, ... )
  291. {
  292.     va_list     argptr;
  293.  
  294.     fprintf(stderr, "\nError: ");
  295.  
  296.     va_start(argptr, fmt);
  297.     vfprintf(stderr, fmt, argptr);
  298.     va_end(argptr);
  299.  
  300.     exit(1);
  301. }
  302.  
  303. void
  304. read_error ( void )
  305. {
  306.     error("Can't read file at offset %04X.\n", ftell(infile));
  307. }
  308.  
  309. void
  310. seek_pos ( unsigned long pos )
  311. {
  312.     if (fseek(infile, pos, SEEK_SET) != 0)
  313.         error("Can't seek offset %04lX.\n", pos);
  314. }
  315.  
  316. void
  317. dump_vocab ( unsigned long pos )
  318. {
  319.     register unsigned    count = 0, index;
  320.     word            words;
  321.     int            vocab_entry_size;
  322.     byte            letters_per_word,
  323.                 zwords_per_word;
  324.     short            entry_width,
  325.                 entries_per_line;
  326.     char            format[sizeof("%%-%ds")];
  327.     int            punct;
  328.     char *            buf;
  329.  
  330. #ifdef DEBUG
  331.     printf("Vocabulary table at offset %04X\n", pos);
  332. #endif
  333.  
  334.     seek_pos(pos);
  335.  
  336.     /* list of punctuation characters */
  337.     if ((punct = getc(infile)) == EOF)
  338.         read_error();
  339.     if (punct) {
  340.         printf("Punctuation: ");
  341.         for (; punct; punct--)
  342.             putchar(getc(infile));
  343.         putchar('\n');
  344.     }
  345.  
  346.     /* size of each vocabulary entry */
  347.     if ((vocab_entry_size = getc(infile)) == EOF)
  348.         read_error();
  349.  
  350.     /* number of entries */
  351.     if (fread(&words, sizeof(words), 1, infile) < 1)
  352.         read_error();
  353.     words = unzword(words);
  354.     if (!numbers)
  355.         printf("%u vocabulary entries\n", words);
  356.  
  357.     letters_per_word = (vocab_entry_size - 3) / 2 * 3;
  358.     zwords_per_word = letters_per_word / 3;
  359.  
  360.     entry_width = letters_per_word + 2;
  361.     if (numbers)
  362.         entry_width += 5;
  363.     if (show_flags)
  364.         entry_width += 3 * (columns == 1 ? 9 : 3) + 1;
  365.     entries_per_line = columns ? columns : (MAXCOL + 2) / entry_width;
  366.  
  367.     buf = malloc(letters_per_word + 1);
  368.     sprintf(format, "%%-%ds", letters_per_word);
  369.  
  370.     while ( count < words ) {
  371.         byte    flags[3];
  372.  
  373.         ++count;
  374.         if (numbers)
  375.             disp_str("%04d ", count);
  376.  
  377.         for (index = 0; index < zwords_per_word; index++) {
  378.             word    z;
  379.  
  380.             if (fread(&z, sizeof(z), 1, infile) < 1)
  381.                 read_error();
  382.             z = unzword(z);
  383.             if (index)
  384.                 strcat(buf, expand(z));
  385.             else
  386.                 strcpy(buf, expand(z));
  387.         }
  388.  
  389.         disp_str(format, decode(buf));
  390.  
  391.         if (fread(flags, sizeof(char), 3, infile) < 3)
  392.             read_error();
  393.  
  394.         if (show_flags) {
  395.             register short n;
  396.  
  397.             disp_ch(' ');
  398.             for (n = 1; n <= 3; n++)
  399.                 if (columns == 1)
  400.                     disp_bits(flags[n]);
  401.                 else
  402.                     disp_str(" %02x", flags[n]);
  403.         }
  404.  
  405.         if (entries_per_line > 1 && (count % entries_per_line))
  406.             disp_str("  ");
  407.         else
  408.             newline();
  409.     }
  410.  
  411.     free(buf);
  412.  
  413.     if (column)
  414.         newline();
  415. }
  416.  
  417. #ifndef VOCAB_ALONE
  418. void
  419. read_macros ( unsigned long pos )
  420. {
  421.     register short    table, elem;
  422.     z_word        macro_offsets[3][32];
  423.  
  424.     seek_pos(pos);
  425.  
  426.     fread(macro_offsets, sizeof(z_word), 3 * 32, infile);
  427.  
  428.     for (table = 0; table < 3; table++)
  429.         for (elem = 0; elem < 32; elem++) {
  430.             macros[table][elem] = NULL;
  431.             if (macro_dump)
  432.                 printf("Macro %d-%02d: ", table, elem);
  433.             if ((pos = unzword(macro_offsets[table][elem])) != 0) {
  434.                 char    macro[BUFSIZ];
  435.                 z_word    z;
  436.                 char    *text;
  437.  
  438.                 seek_pos(pos *= sizeof(z_word));
  439.  
  440.                 macro[0] = '\0';
  441.                 do {
  442.                     if (fread(&z, sizeof(z), 1, infile) < 1)
  443.                         read_error();
  444.                     z = unzword(z);
  445.                     if (macro[0])
  446.                         strcat(macro, expand(z));
  447.                     else
  448.                         strcpy(macro, expand(z));
  449.                 } while (!end_of_text(z));
  450.  
  451.                 text = decode(macro);
  452.                 macros[table][elem] = malloc(strlen(text) + 1);
  453.                 strcpy(macros[table][elem], text);
  454.  
  455.                 if (macro_dump)
  456.                     printf("\"%s\"\n", text);
  457.             }
  458.         }
  459. }
  460. #endif
  461.  
  462. void
  463. frob_file ( const char *filename )
  464. {
  465.     struct info_header    header;
  466.  
  467.     if((infile = fopen(filename, "rb")) == NULL)
  468.         error("Can't open file \"%s\".\n", filename);
  469.  
  470.     printf("%s:\n", filename);
  471.  
  472.     if (fread(&header, sizeof(header), 1, infile) < 1)
  473.         read_error();
  474.     printf("Release %u / Serial number %.6s\n", unzword(header.release), &header.rev_date[0]);
  475.  
  476.     if (macro_dump)
  477.         read_macros(unzword(header.macro_offset));
  478.     dump_vocab(unzword(header.vocab_offset));
  479.  
  480.     fclose(infile);
  481. }
  482.  
  483. #ifndef LINT
  484. const char sccsid[] = "@(#) " __FILE__ " by Mike Threepoint compiled " __DATE__;
  485. #endif
  486.  
  487. void
  488. info ( void )
  489. {
  490.     puts(INFO);
  491.     exit(0);
  492. }
  493.  
  494. void
  495. parse_opt ( char p )
  496. {
  497.     switch (p) {
  498.         case 'w':
  499.             columns = 0;
  500.             break;
  501.         case '#':
  502.         case 'n':
  503.             numbers = !numbers;
  504.             break;
  505.         case 'f':
  506.         case 'b':
  507.             show_flags = !show_flags;
  508.             break;
  509. #ifndef VOCAB_ALONE
  510.         case 'm':
  511.             macro_dump = !macro_dump;
  512.             break;
  513. #endif
  514.         case 'h':
  515.         case '?':
  516.             info();
  517.             break;
  518.         default:
  519.             if (isdigit(p))
  520.                 columns = (p - '0');
  521.     }
  522. }
  523.  
  524. void
  525. parse ( char *parm )
  526. {
  527.     switch (*parm) {
  528.         case '/':
  529.             parse_opt(*++parm);
  530.             break;
  531.         case '-':
  532.             while (*++parm) parse_opt(*parm);
  533.             break;
  534.         default:
  535.             if (did_file) newline();
  536.             frob_file(parm);
  537.             did_file = 1;
  538.     }
  539. }
  540.  
  541. int
  542. main ( const unsigned argc, char *argv[] )
  543. {
  544.     if (argc > 1) {
  545.         register count;
  546.  
  547.         if (strcmp(argv[1], "?") == 0)
  548.             info();
  549.  
  550.         for (count = 1; count < argc; count++)
  551.             parse(argv[count]);
  552.  
  553.         if (did_file) return 0;
  554.     }
  555.  
  556.     info();
  557.     return 1;
  558. }
  559.