ref: 350fb1e60c6761d7171df663035846bacc2b8fde
dir: /src/m_argv.c/
// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef __plan9__ #include "SDL.h" #else #include "SDL_stdinc.h" #endif #include "doomtype.h" #include "d_iwad.h" #include "i_system.h" #include "m_misc.h" #include "m_argv.h" // haleyjd 20110212: warning fix int myargc; char** myargv; // // M_CheckParm // Checks for the given parameter // in the program's command line arguments. // Returns the argument number (1 to argc-1) // or 0 if not present // int M_CheckParmWithArgs(const char *check, int num_args) { int i; for (i = 1; i < myargc - num_args; i++) { if (!strcasecmp(check, myargv[i])) return i; } return 0; } // // M_ParmExists // // Returns true if the given parameter exists in the program's command // line arguments, false if not. // boolean M_ParmExists(const char *check) { return M_CheckParm(check) != 0; } int M_CheckParm(const char *check) { return M_CheckParmWithArgs(check, 0); } #define MAXARGVS 100 static void LoadResponseFile(int argv_index, const char *filename) { FILE *handle; int size; char *infile; char *file; char **newargv; int newargc; int i, k; // Read the response file into memory handle = M_fopen(filename, "rb"); if (handle == NULL) { printf ("\nNo such response file!"); exit(1); } printf("Found response file %s!\n", filename); size = M_FileLength(handle); // Read in the entire file // Allocate one byte extra - this is in case there is an argument // at the end of the response file, in which case a '\0' will be // needed. file = malloc(size + 1); i = 0; while (i < size) { k = fread(file + i, 1, size - i, handle); if (k < 0) { I_Error("Failed to read full contents of '%s'", filename); } i += k; } fclose(handle); // Create new arguments list array newargv = malloc(sizeof(char *) * MAXARGVS); newargc = 0; memset(newargv, 0, sizeof(char *) * MAXARGVS); // Copy all the arguments in the list up to the response file for (i=0; i<argv_index; ++i) { newargv[i] = myargv[i]; myargv[i] = NULL; ++newargc; } infile = file; k = 0; while(k < size) { // Skip past space characters to the next argument while(k < size && isspace(infile[k])) { ++k; } if (k >= size) { break; } // If the next argument is enclosed in quote marks, treat // the contents as a single argument. This allows long filenames // to be specified. if (infile[k] == '\"') { char *argstart; // Skip the first character(") ++k; argstart = &infile[k]; // Read all characters between quotes while (k < size && infile[k] != '\"' && infile[k] != '\n') { ++k; } if (k >= size || infile[k] == '\n') { I_Error("Quotes unclosed in response file '%s'", filename); } // Cut off the string at the closing quote infile[k] = '\0'; ++k; newargv[newargc++] = M_StringDuplicate(argstart); } else { char *argstart; // Read in the next argument until a space is reached argstart = &infile[k]; while(k < size && !isspace(infile[k])) { ++k; } // Cut off the end of the argument at the first space infile[k] = '\0'; ++k; newargv[newargc++] = M_StringDuplicate(argstart); } } // Add arguments following the response file argument for (i=argv_index + 1; i<myargc; ++i) { newargv[newargc] = myargv[i]; myargv[i] = NULL; ++newargc; } // Free any old strings in myargv which were not moved to newargv for (i = 0; i < myargc; ++i) { if (myargv[i] != NULL) { free(myargv[i]); myargv[i] = NULL; } } free(myargv); myargv = newargv; myargc = newargc; free(file); #if 0 // Disabled - Vanilla Doom does not do this. // Display arguments printf("%d command-line args:\n", myargc); for (k=1; k<myargc; k++) { printf("'%s'\n", myargv[k]); } #endif } // // Find a Response File // void M_FindResponseFile(void) { int i; for (i = 1; i < myargc; i++) { if (myargv[i][0] == '@') { LoadResponseFile(i, myargv[i] + 1); } } for (;;) { //! // @arg <filename> // // Load extra command line arguments from the given response file. // Arguments read from the file will be inserted into the command // line replacing this argument. A response file can also be loaded // using the abbreviated syntax '@filename.rsp'. // i = M_CheckParmWithArgs("-response", 1); if (i <= 0) { break; } // Replace the -response argument so that the next time through // the loop we'll ignore it. Since some parameters stop reading when // an argument beginning with a '-' is encountered, we keep something // that starts with a '-'. free(myargv[i]); myargv[i] = M_StringDuplicate("-_"); LoadResponseFile(i + 1, myargv[i + 1]); } } #if defined(_WIN32) enum { FILETYPE_UNKNOWN = 0x0, FILETYPE_IWAD = 0x2, FILETYPE_PWAD = 0x4, FILETYPE_DEH = 0x8, }; static int GuessFileType(const char *name) { int ret = FILETYPE_UNKNOWN; const char *base; char *lower; static boolean iwad_found = false; base = M_BaseName(name); lower = M_StringDuplicate(base); M_ForceLowercase(lower); // only ever add one argument to the -iwad parameter if (iwad_found == false && D_IsIWADName(lower)) { ret = FILETYPE_IWAD; iwad_found = true; } else if (M_StringEndsWith(lower, ".wad") || M_StringEndsWith(lower, ".lmp")) { ret = FILETYPE_PWAD; } else if (M_StringEndsWith(lower, ".deh") || // M_StringEndsWith(lower, ".bex") || M_StringEndsWith(lower, ".hhe") || M_StringEndsWith(lower, ".seh")) { ret = FILETYPE_DEH; } free(lower); return ret; } typedef struct { char *str; int type, stable; } argument_t; static int CompareByFileType(const void *a, const void *b) { const argument_t *arg_a = (const argument_t *) a; const argument_t *arg_b = (const argument_t *) b; const int ret = arg_a->type - arg_b->type; return ret ? ret : (arg_a->stable - arg_b->stable); } void M_AddLooseFiles(void) { int i, types = 0; char **newargv; argument_t *arguments; if (myargc < 2) { return; } // allocate space for up to three additional regular parameters arguments = malloc((myargc + 3) * sizeof(*arguments)); memset(arguments, 0, (myargc + 3) * sizeof(*arguments)); // check the command line and make sure it does not already // contain any regular parameters or response files // but only fully-qualified LFS or UNC file paths for (i = 1; i < myargc; i++) { char *arg = myargv[i]; int type; if (strlen(arg) < 3 || arg[0] == '-' || arg[0] == '@' || ((!isalpha(arg[0]) || arg[1] != ':' || arg[2] != '\\') && (arg[0] != '\\' || arg[1] != '\\'))) { free(arguments); return; } type = GuessFileType(arg); arguments[i].str = arg; arguments[i].type = type; arguments[i].stable = i; types |= type; } // add space for one additional regular parameter // for each discovered file type in the new argument list // and sort parameters right before their corresponding file paths if (types & FILETYPE_IWAD) { arguments[myargc].str = M_StringDuplicate("-iwad"); arguments[myargc].type = FILETYPE_IWAD - 1; myargc++; } if (types & FILETYPE_PWAD) { arguments[myargc].str = M_StringDuplicate("-merge"); arguments[myargc].type = FILETYPE_PWAD - 1; myargc++; } if (types & FILETYPE_DEH) { arguments[myargc].str = M_StringDuplicate("-deh"); arguments[myargc].type = FILETYPE_DEH - 1; myargc++; } newargv = malloc(myargc * sizeof(*newargv)); // sort the argument list by file type, except for the zeroth argument // which is the executable invocation itself SDL_qsort(arguments + 1, myargc - 1, sizeof(*arguments), CompareByFileType); newargv[0] = myargv[0]; for (i = 1; i < myargc; i++) { newargv[i] = arguments[i].str; } free(arguments); myargv = newargv; } #endif // Return the name of the executable used to start the program: const char *M_GetExecutableName(void) { return M_BaseName(myargv[0]); } char *exedir = NULL; void M_SetExeDir(void) { char *dirname; dirname = M_DirName(myargv[0]); exedir = M_StringJoin(dirname, DIR_SEPARATOR_S, NULL); free(dirname); }