home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / DOOM / EDITOR / DEU51 / SOURCE / DEU.C next >
C/C++ Source or Header  |  1994-04-26  |  27KB  |  871 lines

  1. /*
  2.    Doom Editor Utility, by Brendon Wyber and Raphaël Quinet.
  3.  
  4.    You are allowed to use any parts of this code in another program, as
  5.    long as you give credits to the authors in the documentation and in
  6.    the program itself.  Read the file README.1ST for more information.
  7.  
  8.    This program comes with absolutely no warranty.
  9.  
  10.    DEU.C - Main program execution routines.
  11.  
  12.    Compile with command
  13.       tcc -Z -mh -r -G -O -f -edeu *.c \tc\lib\graphics.lib
  14.  
  15.    Be sure to use the Huge memory model when you compile...
  16.  
  17. */
  18.  
  19. /* the includes */
  20. #include "deu.h"
  21. #include <time.h>
  22.  
  23. /* global variables */
  24. FILE *logfile = NULL;        /* filepointer to the error log */
  25. Bool Registered = FALSE;    /* registered or shareware game? */
  26. Bool Debug = FALSE;        /* are we debugging? */
  27. Bool SwapButtons = FALSE;    /* swap right and middle mouse buttons */
  28. Bool Quiet = FALSE;        /* don't play a sound when an object is selected */
  29. Bool Quieter = FALSE;        /* don't play any sound, even when an error occurs */
  30. Bool Expert = FALSE;        /* don't ask for confirmation for some operations */
  31. char *CfgFile = DEU_CONFIG_FILE;/* name of the configuration file */
  32. int  InitialScale = 8;        /* initial zoom factor for map */
  33. int  VideoMode = 2;        /* default video mode for VESA/SuperVGA */
  34. char *BGIDriver = "VESA";    /* default extended BGI driver */
  35. Bool FakeCursor = FALSE;    /* use a "fake" mouse cursor */
  36. Bool Colour2 = FALSE;        /* use the alternate set for things colors */
  37. Bool InfoShown = TRUE;        /* should we display the info bar? */
  38. Bool AdditiveSelBox = FALSE;    /* additive selection box or select in box only? */
  39. char *MainWad = "DOOM.WAD";    /* name of the main wad file */
  40. char **PatchWads = NULL;    /* list of patch wad files */
  41. OptDesc options[] =        /* description of the command line options */
  42. {
  43. /*   short & long names   type            message if true/changed       message if false              where to store the value */
  44.    { "d",  "debug",       OPT_BOOLEAN,    "Debug mode ON",        "Debug mode OFF",             &Debug          },
  45.    { "q",  "quiet",       OPT_BOOLEAN,    "Quiet mode ON",        "Quiet mode OFF",             &Quiet          },
  46.    { "qq", "quieter",     OPT_BOOLEAN,    "Quieter mode ON",        "Quieter mode OFF",           &Quieter        },
  47.    { "e",  "expert",      OPT_BOOLEAN,    "Expert mode ON",        "Expert mode OFF",            &Expert         },
  48.    { "sb", "swapbuttons", OPT_BOOLEAN,    "Mouse buttons swapped",    "Mouse buttons restored",     &SwapButtons    },
  49.    { "w",  "main",        OPT_STRING,     "Main WAD file",        NULL,                         &MainWad        },
  50.    { NULL, "file",        OPT_STRINGLIST, "Patch WAD file",        NULL,                         &PatchWads      },
  51.    { "pw", "pwad",        OPT_STRINGACC,  "Patch WAD file",        NULL,                         &PatchWads      },
  52.    { NULL, "config",      OPT_STRING,     "Config file",        NULL,                         &CfgFile        },
  53.    { "z",  "zoom",        OPT_INTEGER,    "Initial zoom factor",    NULL,                         &InitialScale   },
  54.    { "v",  "video",       OPT_INTEGER,    "Default video mode",        NULL,                         &VideoMode      },
  55.    { NULL, "bgi",         OPT_STRING,     "Default video driver",    NULL,                         &BGIDriver      },
  56.    { "fc", "fakecursor",  OPT_BOOLEAN,    "Fake cursor ON",        "Fake cursor OFF",            &FakeCursor     },
  57.    { "c",  "color2",      OPT_BOOLEAN,    "Alternate Things color set",    "Normal Things color set",    &Colour2        },
  58.    { "i",  "infobar",     OPT_BOOLEAN,    "Info bar shown",        "Info bar hidden",            &InfoShown      },
  59.    { "a",  "addselbox",   OPT_BOOLEAN,    "Additive selection box",    "Select objects in box only", &AdditiveSelBox },
  60.    { NULL, NULL,          OPT_NONE,       NULL,                NULL,                         NULL            }
  61. };
  62.  
  63.  
  64.  
  65. /*
  66.    the main program
  67. */
  68.  
  69. int main( int argc, char *argv[])
  70. {
  71.    int i;
  72.  
  73.    Credits( stdout);
  74.    argv++;
  75.    argc--;
  76.    /* InitSwap must be called before any call to GetMemory(), etc. */
  77.    InitSwap();
  78.    /* quick and dirty check for a "-config" option */
  79.    for (i = 0; i < argc - 1; i++)
  80.       if (!strcmp( argv[ i], "-config"))
  81.       {
  82.      CfgFile = argv[ i + 1];
  83.      break;
  84.       }
  85.    /* read config file and command line options */
  86.    ParseConfigFileOptions( CfgFile);
  87.    ParseCommandLineOptions( argc, argv);
  88.    if (Debug == TRUE)
  89.    {
  90.       logfile = fopen( DEU_LOG_FILE, "w");
  91.       if (logfile == NULL)
  92.      printf( "Warning: Could not open log file \"%s\"", DEU_LOG_FILE);
  93.       LogMessage(": Welcome to DEU!\n");
  94.    }
  95.    if (Quieter == TRUE)
  96.       Quiet = TRUE;
  97.    /* load the wad files */
  98.    OpenMainWad( MainWad);
  99.    if (PatchWads)
  100.       while (PatchWads[ 0])
  101.       {
  102.      OpenPatchWad( strupr( PatchWads[ 0]));
  103.      PatchWads++;
  104.       }
  105.    /* sanity check */
  106.    CloseUnusedWadFiles();
  107.    /* all systems go! */
  108.    MainLoop();
  109.    /* that's all, folks! */
  110.    CloseWadFiles();
  111.    LogMessage( ": The end!\n");
  112.    if (logfile != NULL)
  113.       fclose( logfile);
  114.    return 0;
  115. }
  116.  
  117.  
  118.  
  119. /*
  120.    Append a string to a null-terminated string list
  121. */
  122.  
  123. void AppendItemToList( char ***list, char *item)
  124. {
  125.    int i;
  126.  
  127.    i = 0;
  128.    if (*list != NULL)
  129.    {
  130.       /* count the number of elements in the list (last = null) */
  131.       while ((*list)[ i] != NULL)
  132.      i++;
  133.       /* expand the list */
  134.       *list = ResizeMemory( *list, (i + 2) * sizeof( char **));
  135.    }
  136.    else
  137.    {
  138.       /* create a new list */
  139.       *list = GetMemory( 2 * sizeof( char **));
  140.    }
  141.    /* append the new element */
  142.    (*list)[ i] = item;
  143.    (*list)[ i + 1] = NULL;
  144. }
  145.  
  146.  
  147.  
  148. /*
  149.    Handle command line options
  150. */
  151.  
  152. void ParseCommandLineOptions( int argc, char *argv[])
  153. {
  154.    int optnum;
  155.  
  156.    while (argc > 0)
  157.    {
  158.       if (argv[ 0][ 0] != '-' && argv[ 0][ 0] != '+')
  159.      ProgError( "options must start with '-' or '+'");
  160.       if (!strcmp( argv[ 0], "-?") || !stricmp( argv[ 0], "-h") || !stricmp( argv[ 0], "-help"))
  161.       {
  162.      Usage( stdout);
  163.      exit( 0);
  164.       }
  165.       for (optnum = 0; options[ optnum].opt_type != OPT_NONE; optnum++)
  166.       {
  167.      if (!stricmp( &(argv[ 0][ 1]), options[ optnum].short_name) || !stricmp( &(argv[ 0][ 1]), options[ optnum].long_name))
  168.      {
  169.         switch (options[ optnum].opt_type)
  170.         {
  171.         case OPT_BOOLEAN:
  172.            if (argv[ 0][ 0] == '-')
  173.            {
  174.           *((Bool *) (options[ optnum].data_ptr)) = TRUE;
  175.           if (options[ optnum].msg_if_true)
  176.              printf("%s.\n", options[ optnum].msg_if_true);
  177.            }
  178.            else
  179.            {
  180.           *((Bool *) (options[ optnum].data_ptr)) = FALSE;
  181.           if (options[ optnum].msg_if_false)
  182.              printf("%s.\n", options[ optnum].msg_if_false);
  183.            }
  184.            break;
  185.         case OPT_INTEGER:
  186.            if (argc <= 1)
  187.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  188.            argv++;
  189.            argc--;
  190.            *((int *) (options[ optnum].data_ptr)) = atoi( argv[ 0]);
  191.            if (options[ optnum].msg_if_true)
  192.           printf("%s: %d.\n", options[ optnum].msg_if_true, atoi( argv[ 0]));
  193.            break;
  194.         case OPT_STRING:
  195.            if (argc <= 1)
  196.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  197.            argv++;
  198.            argc--;
  199.            *((char **) (options[ optnum].data_ptr)) = argv[ 0];
  200.            if (options[ optnum].msg_if_true)
  201.           printf("%s: %s.\n", options[ optnum].msg_if_true, argv[ 0]);
  202.            break;
  203.         case OPT_STRINGACC:
  204.            if (argc <= 1)
  205.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  206.            argv++;
  207.            argc--;
  208.            AppendItemToList( (char ***) options[ optnum].data_ptr, argv[ 0]);
  209.            if (options[ optnum].msg_if_true)
  210.           printf("%s: %s.\n", options[ optnum].msg_if_true, argv[ 0]);
  211.            break;
  212.         case OPT_STRINGLIST:
  213.            if (argc <= 1)
  214.           ProgError( "missing argument after \"%s\"", argv[ 0]);
  215.            while (argc > 1 && argv[ 1][ 0] != '-' && argv[ 1][ 0] != '+')
  216.            {
  217.           argv++;
  218.           argc--;
  219.           AppendItemToList( (char ***) options[ optnum].data_ptr, argv[ 0]);
  220.           if (options[ optnum].msg_if_true)
  221.              printf("%s: %s.\n", options[ optnum].msg_if_true, argv[ 0]);
  222.            }
  223.            break;
  224.         default:
  225.            ProgError( "unknown option type (BUG!)");
  226.         }
  227.         break;
  228.      }
  229.       }
  230.       if (options[ optnum].opt_type == OPT_NONE)
  231.      ProgError( "invalid argument: \"%s\"", argv[ 0]);
  232.       argv++;
  233.       argc--;
  234.    }
  235. }
  236.  
  237.  
  238.  
  239. /*
  240.    read the config file
  241. */
  242.  
  243. void ParseConfigFileOptions( char *filename)
  244. {
  245.    FILE *cfgfile;
  246.    char  line[ 1024];
  247.    char *value;
  248.    char *option;
  249.    char *p;
  250.    int   optnum;
  251.  
  252.    if ((cfgfile = fopen (filename, "r")) == NULL)
  253.    {
  254.       printf( "Warning: Configuration file not found (%s)\n", filename);
  255.       return;
  256.    }
  257.    while (fgets (line, 1024, cfgfile) != NULL)
  258.    {
  259.       if (line[0] == '#' || strlen( line) < 2)
  260.      continue;
  261.       if (line[ strlen( line) - 1] == '\n')
  262.      line[ strlen( line) - 1] = '\0';
  263.       /* skip blanks before the option name */
  264.       option = line;
  265.       while (isspace( option[ 0]))
  266.      option++;
  267.       /* skip the option name */
  268.       value = option;
  269.       while (value[ 0] && value[ 0] != '=' && !isspace( value[ 0]))
  270.      value++;
  271.       if (!value[ 0])
  272.      ProgError( "invalid line in %s (ends prematurely)", filename);
  273.       if (value[ 0] == '=')
  274.       {
  275.      /* mark the end of the option name */
  276.      value[ 0] = '\0';
  277.       }
  278.       else
  279.       {
  280.      /* mark the end of the option name */
  281.      value[ 0] = '\0';
  282.      value++;
  283.      /* skip blanks after the option name */
  284.      while (isspace( value[ 0]))
  285.         value++;
  286.      if (value[ 0] != '=')
  287.         ProgError( "invalid line in %s (no '=')", filename);
  288.       }
  289.       value++;
  290.       /* skip blanks after the equal sign */
  291.       while (isspace( value[ 0]))
  292.      value++;
  293.       for (optnum = 0; options[ optnum].opt_type != OPT_NONE; optnum++)
  294.       {
  295.      if (!stricmp( option, options[ optnum].long_name))
  296.      {
  297.         switch (options[ optnum].opt_type)
  298.         {
  299.         case OPT_BOOLEAN:
  300.            if (!stricmp(value, "yes") || !stricmp(value, "true") || !stricmp(value, "on") || !stricmp(value, "1"))
  301.            {
  302.           *((Bool *) (options[ optnum].data_ptr)) = TRUE;
  303.           if (options[ optnum].msg_if_true)
  304.              printf("%s.\n", options[ optnum].msg_if_true);
  305.            }
  306.            else if (!stricmp(value, "no") || !stricmp(value, "false") || !stricmp(value, "off") || !stricmp(value, "0"))
  307.            {
  308.           *((Bool *) (options[ optnum].data_ptr)) = FALSE;
  309.           if (options[ optnum].msg_if_false)
  310.              printf("%s.\n", options[ optnum].msg_if_false);
  311.            }
  312.            else
  313.           ProgError( "invalid value for option %s: \"%s\"", option, value);
  314.            break;
  315.         case OPT_INTEGER:
  316.            *((int *) (options[ optnum].data_ptr)) = atoi( value);
  317.            if (options[ optnum].msg_if_true)
  318.           printf("%s: %d.\n", options[ optnum].msg_if_true, atoi( value));
  319.            break;
  320.         case OPT_STRING:
  321.            p = GetMemory( (strlen( value) + 1) * sizeof( char));
  322.            strcpy( p, value);
  323.            *((char **) (options[ optnum].data_ptr)) = p;
  324.            if (options[ optnum].msg_if_true)
  325.           printf("%s: %s.\n", options[ optnum].msg_if_true, value);
  326.            break;
  327.         case OPT_STRINGACC:
  328.            p = GetMemory( (strlen( value) + 1) * sizeof( char));
  329.            strcpy( p, value);
  330.            AppendItemToList( (char ***) options[ optnum].data_ptr, p);
  331.            if (options[ optnum].msg_if_true)
  332.           printf("%s: %s.\n", options[ optnum].msg_if_true, value);
  333.            break;
  334.         case OPT_STRINGLIST:
  335.            while (value[ 0])
  336.            {
  337.           option = value;
  338.           while (option[ 0] && !isspace( option[ 0]))
  339.              option++;
  340.           option[ 0] = '\0';
  341.           option++;
  342.           while (isspace( option[ 0]))
  343.              option++;
  344.           p = GetMemory( (strlen( value) + 1) * sizeof( char));
  345.           strcpy( p, value);
  346.           AppendItemToList( (char ***) options[ optnum].data_ptr, p);
  347.           if (options[ optnum].msg_if_true)
  348.              printf("%s: %s.\n", options[ optnum].msg_if_true, value);
  349.           value = option;
  350.            }
  351.            break;
  352.         default:
  353.            ProgError( "unknown option type (BUG!)");
  354.         }
  355.         break;
  356.      }
  357.       }
  358.       if (options[ optnum].opt_type == OPT_NONE)
  359.      ProgError( "Invalid option in %s: \"%s\"", filename, option);
  360.    }
  361.    fclose( cfgfile);
  362. }
  363.  
  364.  
  365. /*
  366.    output the program usage to the specified file
  367. */
  368.  
  369. void Usage( FILE *where)
  370. {
  371.    fprintf( where, "Usage:\n");
  372.    fprintf( where, "DEU [-w <main_wad_file>] [-d] [-sb] [-c] [-q] [-qq] [-e] [-a] [-i] [-z <zoom>] [-bgi <driver>] [-v <mode>] [-fc] [-config <ini_file>] [-pw <pwad_file>] [-file <pwad_files>...]\n");
  373.    fprintf( where, "   -w    Gives the name of the main wad file. (also -main)  Default is DOOM.WAD\n");
  374.    fprintf( where, "   -d    Enter debug mode. (also -debug)\n");
  375.    fprintf( where, "   -c    Use the alternate Things color set (also -color2)\n");
  376.    fprintf( where, "   -q    Suppresses some sounds. (also -quiet)\n");
  377.    fprintf( where, "   -qq   Suppresses all sounds. (also -quieter)\n");
  378.    fprintf( where, "   -e    Stops prompts for confirmation. (also -expert)\n");
  379.    fprintf( where, "   -a    To have an additive selection box (also -addselbox)\n");
  380.    fprintf( where, "   -i    Show the info bar in the editors (also -infobar)\n");
  381.    fprintf( where, "   -z    Set the initial zoom factor for the editors. (also -zoom)\n");
  382.    fprintf( where, "   -v    Set the default video mode number (also -video)\n");
  383.    fprintf( where, "   -bgi  Set the default video driver (*.BGI file)\n");
  384.    fprintf( where, "   -fc   Use a \"fake\" mouse cursor (also -fakecursor)\n");
  385.    fprintf( where, "   -sb   Swaps the mouse buttons. (also -swapbuttons)\n");
  386.    fprintf( where, "   -pw   To add one patch wad file to be loaded (may be repeated). (also -pwad)\n");
  387.    fprintf( where, "   -file To add a list of patch wad files to be loaded.\n");
  388.    fprintf( where, "   -config Gives the name of the config file.\n");
  389.    fprintf( where, "Put a '+' instead of a '-' before boolean options to reverse their effect.\n");
  390. }
  391.  
  392.  
  393.  
  394. /*
  395.    output the credits of the program to the specified file
  396. */
  397.  
  398. void Credits( FILE *where)
  399. {
  400.    fprintf( where, "DEU: Doom Editor Utilities, ver %s.\n", DEU_VERSION);
  401.    fprintf( where, " By Raphaël Quinet (quinet@montefiore.ulg.ac.be),\n");
  402.    fprintf( where, "and Brendon J Wyber (b.wyber@csc.canterbury.ac.nz).\n\n");
  403. }
  404.  
  405.  
  406.  
  407. /*
  408.    play a fascinating tune
  409. */
  410.  
  411. void Beep()
  412. {
  413.    if (Quieter == FALSE)
  414.    {
  415.       sound( 640);
  416.       delay( 100);
  417.       nosound();
  418.    }
  419. }
  420.  
  421.  
  422.  
  423. /*
  424.    play a sound
  425. */
  426.  
  427. void PlaySound( int freq, int msec)
  428. {
  429.    if (Quiet == FALSE)
  430.    {
  431.       sound( freq);
  432.       delay( msec);
  433.       nosound();
  434.    }
  435. }
  436.  
  437.  
  438.  
  439. /*
  440.    terminate the program reporting an error
  441. */
  442.  
  443. void ProgError( char *errstr, ...)
  444. {
  445.    va_list args;
  446.  
  447.    Beep();
  448.    Beep();
  449.    if (GfxMode)
  450.    {
  451.       sleep( 1);
  452.       TermGfx();
  453.    }
  454.    va_start( args, errstr);
  455.    printf( "\nProgram Error: *** ");
  456.    vprintf( errstr, args);
  457.    printf( " ***\n");
  458.    if (Debug == TRUE && logfile != NULL)
  459.    {
  460.       fprintf( logfile, "\nProgram Error: *** ");
  461.       vfprintf( logfile, errstr, args);
  462.       fprintf( logfile, " ***\n");
  463.    }
  464.    va_end( args);
  465.    /* clean up things and free swap space */
  466.    ForgetLevelData();
  467.    ForgetWTextureNames();
  468.    ForgetFTextureNames();
  469.    CloseWadFiles();
  470.    exit( 5);
  471. }
  472.  
  473.  
  474.  
  475. /*
  476.    write a message in the log file
  477. */
  478.  
  479. void LogMessage( char *logstr, ...)
  480. {
  481.    va_list  args;
  482.    time_t   tval;
  483.    char    *tstr;
  484.  
  485.    if (Debug == TRUE && logfile != NULL)
  486.    {
  487.       va_start( args, logstr);
  488.       /* if the messsage begins with ":", output the current date & time first */
  489.       if (logstr[ 0] == ':')
  490.       {
  491.      time( &tval);
  492.      tstr = ctime( &tval);
  493.      tstr[ strlen( tstr) - 1] = '\0';
  494.      fprintf(logfile, "%s", tstr);
  495.       }
  496.       vfprintf( logfile, logstr, args);
  497.       va_end( args);
  498.    }
  499. }
  500.  
  501.  
  502.  
  503. /*
  504.    the main program menu loop
  505. */
  506.  
  507. void MainLoop()
  508. {
  509.    char input[ 120];
  510.    char *com, *out;
  511.    FILE *file, *raw;
  512.    WadPtr wad;
  513.    int episode, level;
  514.  
  515.    for (;;)
  516.    {
  517.       /* get the input */
  518.       printf( "\n[? for help]> ");
  519.       gets( input);
  520.       printf( "\n");
  521.       strupr( input);
  522.  
  523.       /* eat the white space and get the first command word */
  524.       com = strtok( input, " ");
  525.  
  526.       /* user just hit return */
  527.       if (com == NULL)
  528.      printf( "[Please enter a command.]\n");
  529.  
  530.       /* user inputting for help */
  531.       else if (!strcmp( com, "?"))
  532.       {
  533.      printf( "?                                 -- to display this text\n");
  534.      printf( "B[uild] <WadFile>                 -- to build a new main WAD file\n");
  535.      printf( "C[reate] [episode [level]]        -- to create and edit a new (empty) level\n");
  536.      printf( "D[ump] <DirEntry> [outfile]       -- to dump a directory entry in hex\n");
  537.      printf( "E[dit] [episode [level]]          -- to edit a game level saving results to\n");
  538.      printf( "                                          a patch wad file\n");
  539.      printf( "G[roup] <WadFile>                 -- to group all patch wads in a file\n");
  540.      printf( "I[nsert] <RawFile> <DirEntry>     -- to insert a raw file in a patch wad file\n");
  541.      printf( "L[ist] <WadFile> [outfile]        -- to list the directory of a wadfile\n");
  542.      printf( "M[aster] [outfile]                -- to list the master directory\n");
  543.      printf( "Q[uit]                            -- to quit\n");
  544.      printf( "R[ead] <WadFile>                  -- to read a new wad patch file\n");
  545.      printf( "S[ave] <DirEntry> <WadFile>       -- to save one object to a separate file\n");
  546.      printf( "V[iew] [SpriteName]               -- to display the sprites\n");
  547.      printf( "W[ads]                            -- to display the open wads\n");
  548.      printf( "X[tract] <DirEntry> <RawFile>     -- to save (extract) one object to a raw file\n");
  549.       }
  550.  
  551.       /* user asked for list of open WAD files */
  552.       else if (!strcmp( com, "WADS") || !strcmp( com, "W"))
  553.       {
  554.      printf( "%-20s  IWAD  (Main wad file)\n", WadFileList->filename);
  555.      for (wad = WadFileList->next; wad; wad = wad->next)
  556.      {
  557.         if (wad->directory[ 0].name[ 0] == 'E' && wad->directory[ 0].name[ 2] == 'M')
  558.            printf( "%-20s  PWAD  (Patch wad file for episode %c level %c)\n", wad->filename, wad->directory[ 0].name[ 1], wad->directory[ 0].name[ 3]);
  559.         else
  560.         {
  561.            /* kluge */
  562.            strncpy( input, wad->directory[ 0].name, 8);
  563.            input[ 8] = '\0';
  564.            printf( "%-20s  PWAD  (Patch wad file for %s)\n", wad->filename, input);
  565.         }
  566.      }
  567.       }
  568.  
  569.       /* user asked to quit */
  570.       else if (!strcmp( com, "QUIT") || !strcmp( com, "Q"))
  571.       {
  572.      if (! Registered)
  573.         printf("Remember to register your copy of DOOM!\n");
  574.      printf( "Goodbye...\n");
  575.      break;
  576.       }
  577.  
  578.       /* user asked to edit a level */
  579.       else if (!strcmp( com, "EDIT") || !strcmp( com, "E") || !strcmp( com, "CREATE") || !strcmp( com, "C"))
  580.       {
  581.      episode = 0;
  582.      level = 0;
  583.      com = strtok( NULL, " ");
  584.      if (com != NULL)
  585.      {
  586.         episode = atoi( com);
  587.         if (episode < 1 || episode > 3)
  588.         {
  589.            printf( "[Invalid game episode number (%s).]\n", com);
  590.            continue;
  591.         }
  592.         com = strtok( NULL, " ");
  593.         if (com != NULL)
  594.         {
  595.            level = atoi( com);
  596.            if (level < 1 || level> 9)
  597.            {
  598.           printf( "[Invalid game level number (%s).]\n", com);
  599.           continue;
  600.            }
  601.         }
  602.      }
  603.      com = strtok( input, " ");
  604.      EditLevel( episode, level, !strcmp( com, "CREATE") || !strcmp( com, "C"));
  605.       }
  606.  
  607.       /* user asked to build a new main WAD file */
  608.       else if (!strcmp( com, "BUILD") || !strcmp( com, "B"))
  609.       {
  610.      com = strtok( NULL, " ");
  611.      if (com == NULL)
  612.      {
  613.         printf( "[Wad file name argument missing.]\n");
  614.         continue;
  615.      }
  616.      for (wad = WadFileList; wad; wad = wad->next)
  617.         if (!stricmp( com, wad->filename))
  618.            break;
  619.      if (wad)
  620.      {
  621.         printf( "[File \"%s\" is opened and cannot be overwritten.]\n", com);
  622.         continue;
  623.      }
  624.      BuildNewMainWad( com, FALSE);
  625.       }
  626.  
  627.       /* user asked to build a compound patch WAD file */
  628.       else if (!strcmp( com, "GROUP") || !strcmp( com, "G"))
  629.       {
  630.      if (WadFileList->next == NULL || WadFileList->next->next == NULL)
  631.      {
  632.         printf( "[You need at least two open wad files if you want to group them.]\n");
  633.         continue;
  634.      }
  635.      com = strtok( NULL, " ");
  636.      if (com == NULL)
  637.      {
  638.         printf( "[Wad file name argument missing.]\n");
  639.         continue;
  640.      }
  641.      for (wad = WadFileList; wad; wad = wad->next)
  642.         if (!stricmp( com, wad->filename))
  643.            break;
  644.      if (wad)
  645.      {
  646.         printf( "[File \"%s\" is opened and cannot be overwritten.]\n", com);
  647.         continue;
  648.      }
  649.      BuildNewMainWad( com, TRUE);
  650.       }
  651.  
  652.       /* user ask for a listing of a WAD file */
  653.       else if (!strcmp( com, "LIST") || !strcmp( com, "L"))
  654.       {
  655.      com = strtok( NULL, " ");
  656.      if (com == NULL)
  657.      {
  658.         printf( "[Wad file name argument missing.]\n");
  659.         continue;
  660.      }
  661.      for (wad = WadFileList; wad; wad = wad->next)
  662.         if (!stricmp( com, wad->filename))
  663.            break;
  664.      if (wad == NULL)
  665.      {
  666.         printf( "[Wad file \"%s\" is not open.]\n", com);
  667.         continue;
  668.      }
  669.      out = strtok( NULL, " ");
  670.      if (out)
  671.      {
  672.         printf( "Outputting directory of \"%s\" to \"%s\".\n", wad->filename, out);
  673.         if ((file = fopen( out, "wt")) == NULL)
  674.            ProgError( "error opening output file \"%s\"", com);
  675.         Credits( file);
  676.         ListFileDirectory( file, wad);
  677.         fprintf( file, "\nEnd of file.\n");
  678.         fclose( file);
  679.      }
  680.      else
  681.         ListFileDirectory( stdout, wad);
  682.       }
  683.  
  684.       /* user asked for the list of the master directory */
  685.       else if (!strcmp( com, "MASTER") || !strcmp( com, "M"))
  686.       {
  687.      out = strtok( NULL, " ");
  688.      if (out)
  689.      {
  690.         printf( "Outputting master directory to \"%s\".\n", out);
  691.         if ((file = fopen( out, "wt")) == NULL)
  692.            ProgError( "error opening output file \"%s\"", com);
  693.         Credits( file);
  694.         ListMasterDirectory( file);
  695.         fprintf( file, "\nEnd of file.\n");
  696.         fclose( file);
  697.      }
  698.      else
  699.         ListMasterDirectory( stdout);
  700.       }
  701.  
  702.       /* user asked to read a new patch WAD file */
  703.       else if (!strcmp( com, "READ") || !strcmp( com, "R"))
  704.       {
  705.      com = strtok( NULL, " ");
  706.      if (com == NULL)
  707.      {
  708.         printf( "[Wad file name argument missing.]\n");
  709.         continue;
  710.      }
  711.      out = strtok( NULL, " ");
  712.      if (out)
  713.        *out = '\0';
  714.      out = GetMemory( (strlen( com) + 1) * sizeof( char));
  715.      strcpy( out, com);
  716.      OpenPatchWad( out);
  717.      CloseUnusedWadFiles();
  718.       }
  719.  
  720.       /* user asked to dump the contents of a WAD file */
  721.       else if (!strcmp( com, "DUMP") || !strcmp( com, "D"))
  722.       {
  723.      com = strtok( NULL, " ");
  724.      if (com == NULL)
  725.      {
  726.         printf( "[Object name argument missing.]\n");
  727.         continue;
  728.      }
  729.      out = strtok( NULL, " ");
  730.      if (out)
  731.      {
  732.         printf( "Outputting directory entry data to \"%s\".\n", out);
  733.         if ((file = fopen( out, "wt")) == NULL)
  734.            ProgError( "error opening output file \"%s\"", com);
  735.         Credits( file);
  736.         DumpDirectoryEntry( file, com);
  737.         fprintf( file, "\nEnd of file.\n");
  738.         fclose( file);
  739.      }
  740.      else
  741.         DumpDirectoryEntry( stdout, com);
  742.       }
  743.  
  744.       /* user asked to view the sprites */
  745.       else if (!strcmp( com, "VIEW") || !strcmp( com, "V"))
  746.       {
  747.      InitGfx();
  748.      com = strtok( NULL, " ");
  749.      ChooseSprite( -1, -1, "Sprite viewer", com);
  750.      TermGfx();
  751.       }
  752.  
  753.       /* user asked to save an object to a separate PWAD file */
  754.       else if (!strcmp( com, "SAVE") || !strcmp( com, "S"))
  755.       {
  756.      com = strtok( NULL, " ");
  757.      if (com == NULL)
  758.      {
  759.         printf( "[Object name argument missing.]\n");
  760.         continue;
  761.      }
  762.      if (strlen( com) > 8 || strchr( com, '.') != NULL)
  763.      {
  764.         printf( "[Invalid object name.]\n");
  765.         continue;
  766.      }
  767.      out = strtok( NULL, " ");
  768.      if (out == NULL)
  769.      {
  770.         printf( "[Wad file name argument missing.]\n");
  771.         continue;
  772.      }
  773.      for (wad = WadFileList; wad; wad = wad->next)
  774.         if (!stricmp( out, wad->filename))
  775.            break;
  776.      if (wad)
  777.      {
  778.         printf( "[This Wad file is already in use.  You may not overwrite it.]\n");
  779.         continue;
  780.      }
  781.      printf( "Saving directory entry data to \"%s\".\n", out);
  782.      if ((file = fopen( out, "wb")) == NULL)
  783.         ProgError( "error opening output file \"%s\"", out);
  784.      SaveDirectoryEntry( file, com);
  785.      fclose( file);
  786.       }
  787.  
  788.       /* user asked to encapsulate a raw file in a PWAD file */
  789.       else if (!strcmp( com, "INSERT") || !strcmp( com, "I"))
  790.       {
  791.      com = strtok( NULL, " ");
  792.      if (com == NULL)
  793.      {
  794.         printf( "[Raw file name argument missing.]\n");
  795.         continue;
  796.      }
  797.      out = strtok( NULL, " ");
  798.      if (out == NULL)
  799.      {
  800.         printf( "[Object name argument missing.]\n");
  801.         continue;
  802.      }
  803.      if (strlen( out) > 8 || strchr( out, '.') != NULL)
  804.      {
  805.         printf( "[Invalid object name.]\n");
  806.         continue;
  807.      }
  808.      if ((raw = fopen( com, "rb")) == NULL)
  809.         ProgError( "error opening input file \"%s\"", com);
  810.      /* kluge */
  811.      strcpy( input, out);
  812.      strcat( input, ".WAD");
  813.      for (wad = WadFileList; wad; wad = wad->next)
  814.         if (!stricmp( input, wad->filename))
  815.            break;
  816.      if (wad)
  817.      {
  818.         printf( "[This Wad file is already in use (%s).  You may not overwrite it.]\n", input);
  819.         continue;
  820.      }
  821.      printf( "Including new object %s in \"%s\".\n", out, input);
  822.      if ((file = fopen( input, "wb")) == NULL)
  823.         ProgError( "error opening output file \"%s\"", input);
  824.      SaveEntryFromRawFile( file, raw, out);
  825.      fclose( raw);
  826.      fclose( file);
  827.       }
  828.  
  829.       /* user asked to extract an object to a raw binary file */
  830.       else if (!strcmp( com, "XTRACT") || !strcmp( com, "EXTRACT") || !strcmp( com, "X"))
  831.       {
  832.      com = strtok( NULL, " ");
  833.      if (com == NULL)
  834.      {
  835.         printf( "[Object name argument missing.]\n");
  836.         continue;
  837.      }
  838.      if (strlen( com) > 8 || strchr( com, '.') != NULL)
  839.      {
  840.         printf( "[Invalid object name.]\n");
  841.         continue;
  842.      }
  843.      out = strtok( NULL, " ");
  844.      if (out == NULL)
  845.      {
  846.         printf( "[Raw file name argument missing.]\n");
  847.         continue;
  848.      }
  849.      for (wad = WadFileList; wad; wad = wad->next)
  850.         if (!stricmp( out, wad->filename))
  851.            break;
  852.      if (wad)
  853.      {
  854.         printf( "[You may not overwrite an opened Wad file with raw data.]\n");
  855.         continue;
  856.      }
  857.      printf( "Saving directory entry data to \"%s\".\n", out);
  858.      if ((file = fopen( out, "wb")) == NULL)
  859.         ProgError( "error opening output file \"%s\"", out);
  860.      SaveEntryToRawFile( file, com);
  861.      fclose( file);
  862.       }
  863.  
  864.       /* unknown command */
  865.       else
  866.      printf( "[Unknown command \"%s\"!]\n", com);
  867.    }
  868. }
  869.  
  870. /* end of file */
  871.