home *** CD-ROM | disk | FTP | other *** search
- /***
- **** QuBE Version 0.2a
- ****
- **** Cheap Quake Binary Editor
- ****
- **** Copyright 1996 by Sean Werkema
- ****
- **** Main startup file, command line parsing, etc. --- get the ball rolling.
- ****
- **** Compilation notes... QUBE_MSDOS and QUBE_UNIX have special meaning
- **** in this thing. Each indicates the appropriate operating system. More
- **** can be added as necessary later.
- ****
- **** Another nice addition would be QUBE_BIG and QUBE_LITTLE for specifying
- **** little-endian vs. big-endian... Anyone willing to code this mess?
- ****
- **** I make no guarantees on the quality of this code. You can freely use
- **** it, modify it, tweak it, whatever you want, just as long as you obey
- **** one basic command: Whatever you create, don't call it QuBE. QuBE is
- **** my name for this morass of code, and it stays mine. Other than that
- **** you can do anything you damn well please.
- ****
- **** This code is copyrighted only so that nobody else will copyright it;
- **** I wrote it, and I don't want to be restricted from my own code.
- ****
- **** Contributors:
- **** Sean Werkema Started QuBE, wrote 99% of it so far.
- ****
- **** I am deeply indebted to whoever it was that originally posted the .PAK
- **** extracter on the Net, because that gave me enough clues to start this.
- **** The .PAK extraction routines are based roughly on the original .PAK
- **** posting, with some new error checking and reformatting. Whoever wrote
- **** the .PAK thing, would you please contact me so I can throw in your name
- **** as a contributor? Thanks.
- ****
- **** Enough comments. Let's do this thing.
- ***/
-
- #include "qube.h"
- #include <errno.h>
- #include <stdarg.h>
-
- #include "image.h"
- #include "gfx.h"
- #include "entities.h"
- #include "tree.h"
- #include "pak.h"
- #include "vertex.h"
- #include "edge.h"
-
- /* Automatically casted name of an Action function */
-
- #define A(n) ((void (*)(int argnum, char **argv))(n))
-
- /* The input file in all its glory */
-
- struct headertag header;
- FILE *fi;
- int filenamearg;
- int justcreated;
- int verbose;
-
- /* This is an action. It's what to do with a command-line switch */
-
- typedef struct {
- char *option;
- long int count;
- void (*action)(int argnum, char **argv);
- char *cmdline;
- char *name;
- char *info;
- } Action;
-
- typedef struct {
- Action *act;
- int arg;
- } CommandArgument;
-
- /* Everything that can be should be kept static, especially private
- functions and data, like the switch-list and its manipulators. This
- isn't OOP code, but we can try to make it close. */
-
- static void ShowFormat(void);
- static int switchcmp(char *option, char *string);
- static void Verbosity(void);
-
- static CommandArgument CommandArg[256];
- static int CommandCount;
-
- /* Command line args go here. This is where everything starts. */
-
- static Action ActionList[] = {
-
- { "-b", 0, A(TreeList), "[-b]", "BSP", "Display the BSP tree in a .BSP file" },
- { "-dl", 0, A(EdgeList), "[-dl]", "EdgeList", "Display the list of edges" },
- { "-el", 0, A(EntList), "[-el]", "EntList", "Display entities in a .BSP file as a printed list" },
- { "-er", 1, A(EntReplace), "[-er filename]", "EntReplace", "Replace *all* entities in a .BSP file from a text file" },
- { "-ex", 1, A(EntXtract), "[-ex filename]", "EntXtract", "Extract entities in a .BSP file to a text file" },
- { "-f", 0, A(ShowHeader), "[-f]", "FileHeader", "Display BSP file header information" },
- { "-g", 0, A(DoGraphics), "[-g]", "Graph", "Display the level in a .BSP file (SVGA/X-Win only)" },
- { "-h", 0, A(ShowFormat), "[-h]", "Help", "You're looking at it, buddy" },
- { "-ka", 1, A(PakAdd), "[-ka filename]", "PakAdd", "Create/add/replace file(s) into a .PAK file" },
- { "-kd", 1, A(PakDelete), "[-kd filename]", "PakDelete", "Delete file(s) from a .PAK file" },
- { "-kl", 0, A(PakList), "[-kl]", "PakList", "List all the files stored in a .PAK file" },
- { "-kx", 1, A(PakXtract2), "[-kx filename]", "PakXtract", "Extract one or more files from a .PAK file" },
- { "-kX", 0, A(PakXtract), "[-kX]", "PakXtract", "Extract a .PAK file into all its constituent files" },
- { "-pa", 1, A(NULL), "[-pa filename]", "PicAdd", "Add a picture to a .BSP file from a .BMP file (not yet)" },
- { "-pd", 1, A(NULL), "[-pd filename]", "PicDelete", "Delete a picture from a .BSP file (not yet)" },
- { "-pl", 0, A(PicList), "[-pl]", "PicList", "List all the pictures stored in a .BSP file" },
- { "-px", 2, A(PicXtract), "[-px filename size]", "PicXtract", "Extract a picture from a .BSP file into a .BMP file" },
- { "-pX", 0, A(PicXtract2), "[-pX]", "PicXtract", "Extract all pictures from a .BSP file" },
- { "-v", 0, A(Verbosity), "[-v]", "Verbose", "Describe everything while doing it (good for debugging)" },
- { "-xl", 0, A(VertexList), "[-xl]", "VertexList", "Display the list of vertices" },
- { "-!", 1, A(XtractAll), "[-! filename]", "XtractAll", "Extract *ALL* data in a .BSP file to separate files" },
- { NULL, 0, A(NULL), NULL, NULL, NULL },
-
- };
-
- /*
- ** Main.
- */
-
- int main(int argc, char **argv)
- {
- int i, j;
- int filenum = 0;
- int createok = 0;
-
- verbose = 0;
- justcreated = 0;
- fi = NULL;
-
- fprintf(stderr, "QuBE: Version 0.2a - 3/8/1996 - Freeware - Sean Werkema\n");
-
- /* Start parsing in the command line, and open a file if one exists */
-
- for (i = 1, CommandCount = 0; i < argc; i++) {
- for (j = 0; ActionList[j].option != NULL; j++) {
- if (switchcmp(ActionList[j].option, argv[i])) {
- CommandArg[CommandCount].arg = i;
- CommandArg[CommandCount++].act = ActionList + j;
- if (ActionList[j].action == A(ShowFormat)) ShowFormat();
- if (ActionList[j].action == A(PakAdd)) createok = 1;
- i += ActionList[j].count;
- break;
- }
- }
- if (ActionList[j].option == NULL) {
- if (filenum != 0)
- Error("Hey, that's too much stuff to do - try \"qube -h\".");
- filenum = i;
- }
- }
-
- if (filenum) {
- if ((fi = fopen(argv[filenum], "rb")) == NULL) {
- if (!createok) Error(strerror(errno));
- fi = fopen(argv[filenum], "wb");
- fclose(fi);
- fi = fopen(argv[filenum], "r+b");
- justcreated = 1;
- }
- else fread(&header, 4, sizeof(header), fi);
- setvbuf(fi, NULL, _IOFBF, 32768);
- filenamearg = filenum;
- }
- else Error("Sorry, Mac, I don't know what to do - try \"qube -h\".");
-
- /* Start acting on the stuff that was found on the command line */
-
- for (i = 0; i < CommandCount; i++) {
- if (CommandArg[i].act->action != NULL) {
- void (*action)(int argnum, char **argv) = CommandArg[i].act->action;
-
- (*action)(CommandArg[i].arg, argv);
- }
- else Error("Sorry, but this feature hasn't been written yet.");
- }
-
- if (fi != NULL) fclose(fi);
-
- return(1);
- }
-
- /*
- ** Verbosity. Turn on the verbose flag.
- */
-
- static void Verbosity(void)
- {
- verbose = 1;
- }
-
- /*
- ** Error. Display an error and shut down. Should use vsprintf to make
- ** everything nice, but that's a bit of effort for now.
- */
-
- void Error(char *format, ...)
- {
- char temp[1024];
- va_list arg_ptr;
- va_start(arg_ptr, format);
- vsprintf(temp, format, arg_ptr);
-
- if (fi != NULL) fclose(fi);
-
- fprintf(stderr, "QuBE: %s\n", temp);
-
- #ifdef QUBE_UNIX
- /* One extra CR is needed to make things look right in UNIX */
- fprintf(stderr, "\n");
- #endif
-
- exit(0);
- }
-
- /*
- ** ShowFormat. Extacts the format from the ActionList, displays it, and exits.
- */
-
- static void ShowFormat(void)
- {
- int line = 0, column = 0;
- int i;
- int lc = 2;
-
- fprintf(stderr, "Display and change things in Quake BSP/PAK files.\n");
- lc++;
-
- /* Display the top command line */
-
- for (i = 0; ActionList[i].option != NULL; i++) {
- if (column + strlen(ActionList[i].cmdline) > 78) column = 0;
- if (column == 0) {
- if (line++ == 0) fprintf(stderr, "\nqube");
- else fprintf(stderr, "\n ");
- column = 4;
- lc++;
- }
- fprintf(stderr, " %s", ActionList[i].cmdline);
- column += strlen(ActionList[i].cmdline) + 1;
- }
-
- /* Remind them they need to add a filename */
-
- if (column == 0 || column > 70) {
- if (line++ == 0) fprintf(stderr, "\nQuBE");
- else fprintf(stderr, "\n ");
- lc++;
- }
- fprintf(stderr, " filename\n\n");
-
- /* Display the command line options, long form */
-
- for (i = 0; ActionList[i].option != NULL; i++) {
- if (strlen(ActionList[i].name) != 0) {
- fprintf(stderr, " %-6s%-15s%s\n", ActionList[i].option, ActionList[i].name, ActionList[i].info);
- lc++;
- if (lc == 23) {
- fprintf(stderr, "<More>");
- #ifdef QUBE_MSDOS
- ReadKeyScan();
- fprintf(stderr, "\r");
- #endif
- #ifdef QUBE_UNIX
- scanf("%c", &line);
- #endif
- lc = 1;
- }
- }
- }
-
- #ifdef QUBE_UNIX
- /* Again, one extra CR is needed to make things look right in UNIX */
- fprintf(stderr, "\n");
- #endif
-
- exit(0);
- }
-
- /*
- ** switchcmp. Behaves kind of like strncmp, only faster and friendlier.
- */
-
- static int switchcmp(char *option, char *string)
- {
- if (*option == '\0') return(0);
-
- while (*option && *option == *string) {
- option++;
- string++;
- }
-
- if (*option == '\0') return(1);
- else return(0);
- }
-
- /*
- ** MatchName. Wildcard matcher. Now handles the wildcards fully, in
- ** pathname format (with proper / interpretation).
- **
- ** Note that this is rather loosely derived from the fnmatch()
- ** function from the GNU C library, which means that at least this
- ** part of the code can have no restrictions on distribution.
- **
- ** However, since the rest of the code can't have any restrictions
- ** either (by my choice), I guess that's a moot point.
- */
-
- int MatchName(char *expr, char *string)
- {
- char c;
-
- while ((c = *expr++) != '\0') {
- switch (c) {
- case '?':
- if (*string == '\0') return(0);
- break;
- case '*':
- while ((c = *expr++) == '?' || c == '*') {
- if (c == '?' && *string == '\0') return(0);
- string++;
- }
- if (c == '\0') return(1);
- expr--;
- while (*string != '\0') {
- if ((*string == c) && MatchName(expr, string)) return(1);
- string++;
- }
- return(0);
- default:
- if (c != *string) return(0);
- break;
- }
- string++;
- }
-
- if (*string == '\0') return(1);
- else return(0);
- }
-
- void *Qmalloc(long int size)
- {
- void *temp = malloc(size);
-
- if (temp == NULL) {
- fprintf(stderr, "Unable to allocate enough memory. %ld bytes not available.\n", size);
- exit(0);
- }
-
- return(temp);
- }
-
- void *Qrealloc(void *buffer, long int size)
- {
- void *temp = realloc(buffer, size);
-
- if (temp == NULL) {
- fprintf(stderr, "Unable to allocate enough memory. %ld bytes not available.\n", size);
- exit(0);
- }
-
- return(temp);
- }
-
- void Qfree(void *buffer)
- {
- free(buffer);
- }
-