home *** CD-ROM | disk | FTP | other *** search
/ Quake++ for Quake / Quake++.iso / quake / qube / qube.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-29  |  10.4 KB  |  319 lines

  1. /***
  2. ****  QuBE Version 0.1
  3. ****
  4. ****  Cheap Quake Binary Editor
  5. ****
  6. ****  Copyright 1996 by Sean Werkema
  7. ****
  8. ****  Main startup file, command line parsing, etc. --- get the ball rolling.
  9. ****
  10. ****  Compilation notes...  QUBE_MSDOS and QUBE_UNIX have special meaning
  11. ****  in this thing.  Each indicates the appropriate operating system.    More
  12. ****  can be added as necessary later.
  13. ****
  14. ****  Another nice addition would be QUBE_BIG and QUBE_LITTLE for specifying
  15. ****  little-endian vs. big-endian...  Anyone willing to code this mess?
  16. ****
  17. ****  I make no guarantees on the quality of this code.  You can freely use
  18. ****  it, modify it, tweak it, whatever you want, just as long as you obey
  19. ****  one basic command:  Whatever you create, don't call it QuBE.  QuBE is
  20. ****  my name for this morass of code, and it stays mine.  Other than that
  21. ****  you can do anything you damn well please.
  22. ****
  23. ****  This code is copyrighted only so that nobody else will copyright it;
  24. ****  I wrote it, and I don't want to be restricted from my own code.
  25. ****
  26. ****  Contributors:
  27. ****    Sean Werkema            Started QuBE, wrote 99% of it so far.
  28. ****
  29. ****  I am deeply indebted to whoever it was that originally posted the .PAK
  30. ****  extracter on the Net, because that gave me enough clues to start this.
  31. ****  The .PAK extraction routines are based roughly on the original .PAK
  32. ****  posting, with some new error checking and reformatting.  Whoever wrote
  33. ****  the .PAK thing, would you please contact me so I can throw in your name
  34. ****  as a contributor?  Thanks.
  35. ****
  36. ****  Enough comments.    Let's do this thing.
  37. ***/
  38.  
  39. #include "qube.h"
  40. #include <errno.h>
  41. #include <stdarg.h>
  42.  
  43. #include "image.h"
  44. #include "gfx.h"
  45. #include "thing.h"
  46. #include "tree.h"
  47. #include "pak.h"
  48.  
  49. /* Automatically casted name of an Action function */
  50.  
  51. #define A(n) ((void (*)(int argnum, char **argv))(n))
  52.  
  53. /* The input file in all its glory */
  54.  
  55. struct headertag header;
  56. FILE *fi;
  57. int filenamearg;
  58. int justcreated;
  59. int verbose;
  60.  
  61. /* This is an action.  It's what to do with a command-line switch */
  62.  
  63. typedef struct {
  64.     char *option;
  65.     long int count;
  66.     void (*action)(int argnum, char **argv);
  67.         char *cmdline;
  68.     char *name;
  69.     char *info;
  70. } Action;
  71.  
  72. typedef struct {
  73.     Action *act;
  74.     int arg;
  75. } CommandArgument;
  76.  
  77. /* Everything that can be should be kept static, especially private
  78.    functions and data, like the switch-list and its manipulators.  This
  79.    isn't OOP code, but we can try to make it close.  */
  80.  
  81. static void ShowFormat(void);
  82. static int switchcmp(char *option, char *string);
  83. static void Verbosity(void);
  84.  
  85. static CommandArgument CommandArg[256];
  86. static int CommandCount;
  87.  
  88. /* Command line args go here.  This is where everything starts.  */
  89.  
  90. static Action ActionList[] = {
  91.  
  92. { "-b",  0,     A(TreeList),    "[-b]",                 "BSP",          "Display the BSP tree in a .BSP file"                           },
  93. { "-g",  0,     A(DoGraphics),  "[-g]",                 "Graph",        "Display the level in a .BSP file (SVGA/X-Win only)"            },
  94. { "-h",  0,     A(ShowFormat),  "[-h]",                 "Help",         "You're looking at it, buddy"                                   },
  95. { "-ka", 1,     A(PakAdd),      "[-ka filename]",       "PakAdd",       "Create/add/replace file(s) into a .PAK file"                   },
  96. { "-kd", 1,     A(PakDelete),   "[-kd filename]",       "PakDelete",    "Delete file(s) from a .PAK file"                               },
  97. { "-kl", 0,     A(PakList),     "[-kl]",                "PakList",      "List all the files stored in a .PAK file"                      },
  98. { "-kx", 1,     A(PakXtract2),  "[-kx filename]",       "PakXtract",    "Extract one or more files from a .PAK file"                    },
  99. { "-kX", 0,     A(PakXtract),   "[-kX]",                "PakXtract",    "Extract a .PAK file into all its constituent files"            },
  100. { "-pa", 1,     A(NULL),        "[-pa filename]",       "PicAdd",       "Add a picture to a .BSP file from a .BMP file (not yet)"       },
  101. { "-pd", 1,     A(NULL),        "[-pd filename]",       "PicDelete",    "Delete a picture from a .BSP file (not yet)"                   },
  102. { "-pl", 0,     A(PicList),     "[-pl]",                "PicList",      "List all the pictures stored in a .BSP file"                   },
  103. { "-px", 2,     A(PicXtract),   "[-px filename size]",  "PicXtract",    "Extract a picture from a .BSP file into a .BMP file"           },
  104. { "-pX", 0,     A(PicXtract2),  "[-pX]",                "PicXtract",    "Extract all pictures from a .BSP file"                         },
  105. { "-tl", 0,     A(ThingList),   "[-tl]",                "ThingList",    "Display things in a .BSP file as a printed list"               },
  106. { "-tx", 1,     A(ThingXtract), "[-tx filename]",       "ThingXtract",  "Extract things in a .BSP file to a text file"                  },
  107. { "-tr", 1,     A(ThingReplace),"[-tr filename]",       "ThingReplace", "Replace *all* things in a .BSP file from a text file"          },
  108. { "-v",  0,     A(Verbosity),   "[-v]",                 "Verbose",      "Describe everything while doing it (good for debugging)"       },
  109. { NULL,  0,     A(NULL),        NULL,                   NULL,           NULL                                                            },
  110.  
  111. };
  112.  
  113. /*
  114. **  Main.
  115. */
  116.  
  117. int main(int argc, char **argv)
  118. {
  119.     int i, j;
  120.     int filenum = 0;
  121.     int createok = 0;
  122.  
  123.     verbose = 0;
  124.         justcreated = 0;
  125.     fi = NULL;
  126.  
  127.     fprintf(stderr, "QuBE: Version 0.1 - 2/28/1996 - Freeware - Sean Werkema\n");
  128.  
  129.     /* Start parsing in the command line, and open a file if one exists */
  130.  
  131.         for (i = 1, CommandCount = 0; i < argc; i++) {
  132.                 for (j = 0; ActionList[j].option != NULL; j++) {
  133.                         if (switchcmp(ActionList[j].option, argv[i])) {
  134.                 CommandArg[CommandCount].arg = i;
  135.                 CommandArg[CommandCount++].act = ActionList + j;
  136.                 if (ActionList[j].action == A(ShowFormat)) ShowFormat();
  137.                 if (ActionList[j].action == A(PakAdd)) createok = 1;
  138.                                 i += ActionList[j].count;
  139.                                 break;
  140.                         }
  141.                 }
  142.         if (ActionList[j].option == NULL) {
  143.             if (filenum != 0)
  144.                 Error("Hey, that's too much stuff to do - try \"qube -h\".");
  145.             filenum = i;
  146.                 }
  147.         }
  148.  
  149.     if (filenum) {
  150.         if ((fi = fopen(argv[filenum], "rb")) == NULL) {
  151.             if (!createok) Error(strerror(errno));
  152.             fi = fopen(argv[filenum], "wb");
  153.             fclose(fi);
  154.             fi = fopen(argv[filenum], "r+b");
  155.                         justcreated = 1;
  156.                 }
  157.                 else fread(&header, 4, 0x50, fi);
  158.         setvbuf(fi, NULL, _IOFBF, 32768);
  159.                 filenamearg = filenum;
  160.     }
  161.     else Error("Sorry, Mac, I don't know what to do - try \"qube -h\".");
  162.  
  163.     /* Start acting on the stuff that was found on the command line */
  164.  
  165.     for (i = 0; i < CommandCount; i++) {
  166.         if (CommandArg[i].act->action != NULL) {
  167.             void (*action)(int argnum, char **argv) = CommandArg[i].act->action;
  168.  
  169.                         (*action)(CommandArg[i].arg, argv);
  170.         }
  171.                 else Error("Sorry, but this feature hasn't been written yet.");
  172.         }
  173.  
  174.     if (fi != NULL) fclose(fi);
  175.  
  176.     return(1);
  177. }
  178.  
  179. /*
  180. **  Verbosity.    Turn on the verbose flag.
  181. */
  182.  
  183. static void Verbosity(void)
  184. {
  185.     verbose = 1;
  186. }
  187.  
  188. /*
  189. **  Error.  Display an error and shut down.  Should use vsprintf to make
  190. **    everything nice, but that's a bit of effort for now.
  191. */
  192.  
  193. void Error(char *format, ...)
  194. {
  195.     char temp[1024];
  196.     va_list arg_ptr;
  197.     va_start(arg_ptr, format);
  198.     vsprintf(temp, format, arg_ptr);
  199.  
  200.         if (fi != NULL) fclose(fi);
  201.  
  202.     fprintf(stderr, "QuBE: %s\n", temp);
  203.  
  204. #ifdef QUBE_UNIX
  205.     /* One extra CR is needed to make things look right in UNIX */
  206.         fprintf(stderr, "\n");  
  207. #endif
  208.  
  209.     exit(0);
  210. }
  211.  
  212. /*
  213. **  ShowFormat.  Extacts the format from the ActionList, displays it, and exits.
  214. */
  215.  
  216. static void ShowFormat(void)
  217. {
  218.     int line = 0, column = 0;
  219.     int i;
  220.  
  221.     fprintf(stderr, "Display and change things in Quake BSP/PAK files.\n");
  222.  
  223.     /* Display the top command line */
  224.  
  225.     for (i = 0; ActionList[i].option != NULL; i++) {
  226.         if (column + strlen(ActionList[i].cmdline) > 78) column = 0;
  227.                 if (column == 0) {
  228.             if (line++ == 0) fprintf(stderr, "\nQuBE");
  229.             else         fprintf(stderr, "\n    ");
  230.             column = 4;
  231.                 }
  232.         fprintf(stderr, " %s", ActionList[i].cmdline);
  233.         column += strlen(ActionList[i].cmdline) + 1;
  234.         }
  235.  
  236.     /* Remind them they need to add a filename */
  237.  
  238.     if (column == 0 || column > 70) {
  239.         if (line++ == 0) fprintf(stderr, "\nQuBE");
  240.         else         fprintf(stderr, "\n    ");
  241.     }
  242.     fprintf(stderr, " filename\n\n");
  243.  
  244.     /* Display the command line options, long form */
  245.  
  246.     for (i = 0; ActionList[i].option != NULL; i++)
  247.         if (strlen(ActionList[i].name) != 0)
  248.             fprintf(stderr, "  %-6s%-15s%s\n", ActionList[i].option, ActionList[i].name, ActionList[i].info);
  249.  
  250. #ifdef QUBE_UNIX
  251.     /* Again, one extra CR is needed to make things look right in UNIX */
  252.         fprintf(stderr, "\n");  
  253. #endif
  254.  
  255.     exit(0);
  256. }
  257.  
  258. /*
  259. **  switchcmp.    Behaves kind of like strncmp, only faster and friendlier.
  260. */
  261.  
  262. static int switchcmp(char *option, char *string)
  263. {
  264.     if (*option == '\0') return(0);
  265.  
  266.     while (*option && *option == *string) {
  267.         option++;
  268.         string++;
  269.     }
  270.  
  271.     if (*option == '\0') return(1);
  272.     else return(0);
  273. }
  274.  
  275. /*
  276. **  MatchName.    Wildcard matcher.  Now handles the wildcards fully, in
  277. **    pathname format (with proper / interpretation).
  278. **
  279. **    Note that this is rather loosely derived from the fnmatch()
  280. **    function from the GNU C library, which means that at least this
  281. **    part of the code can have no restrictions on distribution.
  282. **
  283. **    However, since the rest of the code can't have any restrictions
  284. **    either (by my choice), I guess that's a moot point.
  285. */
  286.  
  287. int MatchName(char *expr, char *string)
  288. {
  289.     char c;
  290.  
  291.     while ((c = *expr++) != '\0') {
  292.         switch (c) {
  293.         case '?':
  294.             if (*string == '\0') return(0);
  295.                         break;
  296.         case '*':
  297.             while ((c = *expr++) == '?' || c == '*') {
  298.                 if (c == '?' && *string == '\0') return(0);
  299.                 string++;
  300.             }
  301.                         if (c == '\0') return(1);
  302.             expr--;
  303.             while (*string != '\0') {
  304.                 if ((*string == c) && MatchName(expr, string)) return(1);
  305.                                 string++;
  306.             }
  307.                         return(0);
  308.         default:
  309.             if (c != *string) return(0);
  310.             break;
  311.         }
  312.         string++;
  313.         }
  314.  
  315.     if (*string == '\0') return(1);
  316.     else return(0);
  317. }
  318.  
  319.