/* * Actual loading subsystem, this finds the ini or cfg file, and properly * loads it and executes it to set compiler options. */ void opts_ini_init(const char *file) { /* * Possible matches are: * gmqcc.ini * gmqcc.cfg */ char *error = NULL; char *parse_file = NULL; size_t line; fs_file_t *ini; if (!file) { /* try ini */ if (!(ini = fs_file_open((file = "gmqcc.ini"), "r"))) /* try cfg */ if (!(ini = fs_file_open((file = "gmqcc.cfg"), "r"))) return; } else if (!(ini = fs_file_open(file, "r"))) return; con_out("found ini file `%s`\n", file); parse_file = util_strdup(file); if ((line = opts_ini_parse(ini, &opts_ini_load, &error, &parse_file)) != 0) { /* there was a parse error with the ini file */ con_printmsg(LVL_ERROR, parse_file, line, 0 /*TODO: column for ini error*/, "error", error); vec_free(error); } mem_d(parse_file); fs_file_close(ini); }
bool code_write(code_t *code, const char *filename, const char *lnofile) { prog_header_t code_header; fs_file_t *fp = NULL; code_create_header(code, &code_header, filename, lnofile); if (lnofile) { uint32_t version = 1; fp = fs_file_open(lnofile, "wb"); if (!fp) return false; util_endianswap(&version, 1, sizeof(version)); util_endianswap(code->linenums, vec_size(code->linenums), sizeof(code->linenums[0])); util_endianswap(code->columnnums, vec_size(code->columnnums), sizeof(code->columnnums[0])); if (fs_file_write("LNOF", 4, 1, fp) != 1 || fs_file_write(&version, sizeof(version), 1, fp) != 1 || fs_file_write(&code_header.defs.length, sizeof(code_header.defs.length), 1, fp) != 1 || fs_file_write(&code_header.globals.length, sizeof(code_header.globals.length), 1, fp) != 1 || fs_file_write(&code_header.fields.length, sizeof(code_header.fields.length), 1, fp) != 1 || fs_file_write(&code_header.statements.length, sizeof(code_header.statements.length), 1, fp) != 1 || fs_file_write(code->linenums, sizeof(code->linenums[0]), vec_size(code->linenums), fp) != vec_size(code->linenums) || fs_file_write(code->columnnums, sizeof(code->columnnums[0]), vec_size(code->columnnums), fp) != vec_size(code->columnnums)) { con_err("failed to write lno file\n"); } fs_file_close(fp); fp = NULL; } fp = fs_file_open(filename, "wb"); if (!fp) return false; if (1 != fs_file_write(&code_header, sizeof(prog_header_t) , 1 , fp) || vec_size(code->statements) != fs_file_write(code->statements, sizeof(prog_section_statement_t), vec_size(code->statements), fp) || vec_size(code->defs) != fs_file_write(code->defs, sizeof(prog_section_def_t) , vec_size(code->defs) , fp) || vec_size(code->fields) != fs_file_write(code->fields, sizeof(prog_section_field_t) , vec_size(code->fields) , fp) || vec_size(code->functions) != fs_file_write(code->functions, sizeof(prog_section_function_t) , vec_size(code->functions) , fp) || vec_size(code->globals) != fs_file_write(code->globals, sizeof(int32_t) , vec_size(code->globals) , fp) || vec_size(code->chars) != fs_file_write(code->chars, 1 , vec_size(code->chars) , fp)) { fs_file_close(fp); return false; } fs_file_close(fp); code_stats(filename, lnofile, code, &code_header); return true; }
/* * This is clever, say you want to change the console to use two * files for out/err. You pass in two strings, it will properly * close the existing handles (if they're not std* handles) and * open them. Now say you want TO use stdout and stderr, this * allows you to do that so long as you cast them to (char*). * Say you need stdout for out, but want a file for error, you can * do this too, just cast the stdout for (char*) and stick to a * string for the error file. */ int con_change(const char *out, const char *err) { con_close(); if (!out) out = (const char *)((!console.handle_out) ? (fs_file_t*)stdout : console.handle_out); if (!err) err = (const char *)((!console.handle_err) ? (fs_file_t*)stderr : console.handle_err); if (GMQCC_IS_DEFINE(out)) { console.handle_out = (fs_file_t*)(GMQCC_IS_STDOUT(out) ? stdout : stderr); con_enablecolor(); } else if (!(console.handle_out = fs_file_open(out, "w"))) return 0; if (GMQCC_IS_DEFINE(err)) { console.handle_err = (fs_file_t*)(GMQCC_IS_STDOUT(err) ? stdout : stderr); con_enablecolor(); } else if (!(console.handle_err = fs_file_open(err, "w"))) return 0; return 1; }
static pak_file_t *pak_open_read(const char *file) { pak_file_t *pak; size_t itr; if (!(pak = (pak_file_t*)mem_a(sizeof(pak_file_t)))) return NULL; if (!(pak->handle = fs_file_open(file, "rb"))) { mem_d(pak); return NULL; } pak->directories = NULL; pak->insert = false; /* read doesn't allow insert */ memset (&pak->header, 0, sizeof(pak_header_t)); fs_file_read (&pak->header, sizeof(pak_header_t), 1, pak->handle); util_endianswap(&pak->header.magic, 1, sizeof(pak->header.magic)); util_endianswap(&pak->header.diroff, 1, sizeof(pak->header.diroff)); util_endianswap(&pak->header.dirlen, 1, sizeof(pak->header.dirlen)); /* * Every PAK file has "PACK" stored as FOURCC data in the * header. If this data cannot compare (as checked here), it's * probably not a PAK file. */ if (pak->header.magic != PAK_FOURCC) { fs_file_close(pak->handle); mem_d (pak); return NULL; } /* * Time to read in the directory handles and prepare the directories * vector. We're going to be reading some the file inwards soon. */ fs_file_seek(pak->handle, pak->header.diroff, FS_FILE_SEEK_SET); /* * Read in all directories from the PAK file. These are considered * to be the "file entries". */ for (itr = 0; itr < pak->header.dirlen / 64; itr++) { pak_directory_t dir; fs_file_read (&dir, sizeof(pak_directory_t), 1, pak->handle); /* Don't translate name - it's just an array of bytes. */ util_endianswap(&dir.pos, 1, sizeof(dir.pos)); util_endianswap(&dir.len, 1, sizeof(dir.len)); vec_push(pak->directories, dir); } return pak; }
/* * Extraction abilities. These work as you expect them to. */ static bool pak_extract_one(pak_file_t *pak, const char *file, const char *outdir) { pak_directory_t *dir = NULL; unsigned char *dat = NULL; char *local = NULL; FILE *out = NULL; if (!pak_exists(pak, file, &dir)) { return false; } if (!(dat = (unsigned char *)mem_a(dir->len))) goto err; /* * Generate the directory structure / tree that will be required * to store the extracted file. */ pak_tree_build(file); /* TODO portable path seperators */ util_asprintf(&local, "%s/%s", outdir, file); /* * Now create the file, if this operation fails. Then abort * It shouldn't fail though. */ if (!(out = fs_file_open(local, "wb"))) goto err; /* free memory for directory string */ mem_d(local); /* read */ if (fs_file_seek (pak->handle, dir->pos, SEEK_SET) != 0) goto err; fs_file_read (dat, 1, dir->len, pak->handle); fs_file_write(dat, 1, dir->len, out); fs_file_close(out); mem_d(dat); return true; err: if (dat) mem_d(dat); if (out) fs_file_close(out); return false; }
static pak_file_t *pak_open_write(const char *file) { pak_file_t *pak; if (!(pak = (pak_file_t*)mem_a(sizeof(pak_file_t)))) return NULL; /* * Generate the required directory structure / tree for * writing this PAK file too. */ pak_tree_build(file); if (!(pak->handle = fs_file_open(file, "wb"))) { /* * The directory tree that was created, needs to be * removed entierly if we failed to open a file. */ /* TODO backup directory clean */ mem_d(pak); return NULL; } memset(&(pak->header), 0, sizeof(pak_header_t)); /* * We're in "insert" mode, we need to do things like header * "patching" and writing the directories at the end of the * file. */ pak->insert = true; pak->header.magic = PAK_FOURCC; /* on BE systems we need to swap the byte order of the FOURCC */ util_endianswap(&pak->header.magic, 1, sizeof(uint32_t)); /* * We need to write out the header since files will be wrote out to * this even with directory entries, and that not wrote. The header * will need to be patched in later with a file_seek, and overwrite, * we could use offsets and other trickery. This is just easier. */ fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle); return pak; }
int do_exec(char *path, char **argv, char **env, int shebanged /* oh my */) { unsigned int i=0; addr_t end, eip; unsigned int argc=0, envc=0; char **backup_argv=0, **backup_env=0; /* Sanity */ if(!path || !*path) return -EINVAL; /* Load the file, and make sure that it is valid and accessible */ if(EXEC_LOG == 2) printk(0, "[%d]: Checking executable file (%s)\n", current_process->pid, path); struct file *efil; int err_open; efil = fs_file_open(path, _FREAD, 0, &err_open); if(!efil) return err_open; /* are we allowed to execute it? */ if(!vfs_inode_check_permissions(efil->inode, MAY_EXEC, 0)) { file_put(efil); return -EACCES; } /* is it a valid elf? */ int header_size = 0; #if CONFIG_ARCH == TYPE_ARCH_X86_64 header_size = sizeof(elf64_header_t); #elif CONFIG_ARCH == TYPE_ARCH_X86 header_size = sizeof(elf32_header_t); #endif /* read in the ELF header, and check if it's a shebang */ if(header_size < 2) header_size = 2; unsigned char mem[header_size]; fs_file_pread(efil, 0, mem, header_size); if(__is_shebang(mem)) return loader_do_shebang(efil, argv, env); int other_bitsize=0; if(!is_valid_elf(mem, 2) && !other_bitsize) { file_put(efil); return -ENOEXEC; } if(EXEC_LOG == 2) printk(0, "[%d]: Copy data\n", current_process->pid); /* okay, lets back up argv and env so that we can * clear out the address space and not lose data... * If this call if coming from a shebang, then we don't check the pointers, * since they won't be from userspace */ size_t total_args_len = 0; if((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, argv, 0)) && argv) { while((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, argv[argc], 0)) && argv[argc] && *argv[argc]) argc++; backup_argv = (char **)kmalloc(sizeof(addr_t) * argc); for(i=0;i<argc;i++) { backup_argv[i] = (char *)kmalloc(strlen(argv[i]) + 1); _strcpy(backup_argv[i], argv[i]); total_args_len += strlen(argv[i])+1 + sizeof(char *); } } if((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, env, 0)) && env) { while((shebanged || mm_is_valid_user_pointer(SYS_EXECVE, env[envc], 0)) && env[envc] && *env[envc]) envc++; backup_env = (char **)kmalloc(sizeof(addr_t) * envc); for(i=0;i<envc;i++) { backup_env[i] = (char *)kmalloc(strlen(env[i]) + 1); _strcpy(backup_env[i], env[i]); total_args_len += strlen(env[i])+1 + sizeof(char *); } } total_args_len += 2 * sizeof(char *); /* and the path too! */ char *path_backup = (char *)kmalloc(strlen(path) + 1); _strcpy((char *)path_backup, path); path = path_backup; /* Preexec - This is the point of no return. Here we close out unneeded * file descs, free up the page directory and clear up the resources * of the task */ if(EXEC_LOG) printk(0, "Executing (p%dt%d, cpu %d, tty %d): %s\n", current_process->pid, current_thread->tid, current_thread->cpu->knum, current_process->pty ? current_process->pty->num : 0, path); preexec(); /* load in the new image */ strncpy((char *)current_process->command, path, 128); if(!loader_parse_elf_executable(mem, efil, &eip, &end)) eip=0; /* do setuid and setgid */ if(efil->inode->mode & S_ISUID) { current_process->effective_uid = efil->inode->uid; } if(efil->inode->mode & S_ISGID) { current_process->effective_gid = efil->inode->gid; } /* we don't need the file anymore, close it out */ file_put(efil); file_close_cloexec(); if(!eip) { printk(5, "[exec]: Tried to execute an invalid ELF file!\n"); free_dp(backup_argv, argc); free_dp(backup_env, envc); kfree(path); tm_thread_exit(0); } if(EXEC_LOG == 2) printk(0, "[%d]: Updating task values\n", current_process->pid); /* Setup the task with the proper values (libc malloc stack) */ addr_t end_l = end; end = ((end-1)&PAGE_MASK) + PAGE_SIZE; total_args_len += PAGE_SIZE; /* now we need to copy back the args and env into userspace * writeable memory...yippie. */ addr_t args_start = end + PAGE_SIZE; addr_t env_start = args_start; addr_t alen = 0; mm_mmap(end, total_args_len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0, 0); if(backup_argv) { memcpy((void *)args_start, backup_argv, sizeof(addr_t) * argc); alen += sizeof(addr_t) * argc; *(addr_t *)(args_start + alen) = 0; /* set last argument value to zero */ alen += sizeof(addr_t); argv = (char **)args_start; for(i=0;i<argc;i++) { char *old = argv[i]; char *new = (char *)(args_start+alen); unsigned len = strlen(old) + 4; argv[i] = new; _strcpy(new, old); kfree(old); alen += len; } kfree(backup_argv); } env_start = args_start + alen; alen = 0; if(backup_env) { memcpy((void *)env_start, backup_env, sizeof(addr_t) * envc); alen += sizeof(addr_t) * envc; *(addr_t *)(env_start + alen) = 0; /* set last argument value to zero */ alen += sizeof(addr_t); env = (char **)env_start; for(i=0;i<envc;i++) { char *old = env[i]; char *new = (char *)(env_start+alen); unsigned len = strlen(old) + 1; env[i] = new; _strcpy(new, old); kfree(old); alen += len; } kfree(backup_env); } end = (env_start + alen) & PAGE_MASK; current_process->env = env; current_process->argv = argv; kfree(path); /* set the heap locations, and map in the start */ current_process->heap_start = current_process->heap_end = end + PAGE_SIZE*2; addr_t ret = mm_mmap(end + PAGE_SIZE, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0, 0); /* now, we just need to deal with the syscall return stuff. When the syscall * returns, it'll just jump into the entry point of the new process */ tm_thread_lower_flag(current_thread, THREAD_SCHEDULE); /* the kernel cares if it has executed something or not */ if(!(kernel_state_flags & KSF_HAVEEXECED)) set_ksf(KSF_HAVEEXECED); arch_loader_exec_initializer(argc, eip); if(EXEC_LOG == 2) printk(0, "[%d]: Performing call\n", current_process->pid); return 0; }
/* * This executes the QCVM task for a specificly compiled progs.dat * using the template passed into it for call-flags and user defined * messages IF the procedure type is -execute, otherwise it matches * the preprocessor output. */ static bool task_trymatch(size_t i, char ***line) { bool success = true; bool process = true; int retval = EXIT_SUCCESS; fs_file_t *execute; char buffer[4096]; task_template_t *tmpl = task_tasks[i].tmpl; memset (buffer,0,sizeof(buffer)); if (!strcmp(tmpl->proceduretype, "-execute")) { /* * Drop the execution flags for the QCVM if none where * actually specified. */ if (!strcmp(tmpl->executeflags, "$null")) { util_snprintf(buffer, sizeof(buffer), "%s %s", task_bins[TASK_EXECUTE], tmpl->tempfilename ); } else { util_snprintf(buffer, sizeof(buffer), "%s %s %s", task_bins[TASK_EXECUTE], tmpl->executeflags, tmpl->tempfilename ); } execute = (fs_file_t*)popen(buffer, "r"); if (!execute) return false; } else if (!strcmp(tmpl->proceduretype, "-pp")) { /* * we're preprocessing, which means we need to read int * the produced file and do some really weird shit. */ if (!(execute = fs_file_open(tmpl->tempfilename, "r"))) return false; process = false; } else { /* * we're testing diagnostic output, which means it will be * in runhandles[2] (stderr) since that is where the compiler * puts it's errors. */ if (!(execute = fs_file_open(task_tasks[i].stderrlogfile, "r"))) return false; process = false; } /* * Now lets read the lines and compare them to the matches we expect * and handle accordingly. */ { char *data = NULL; size_t size = 0; size_t compare = 0; while (fs_file_getline(&data, &size, execute) != FS_FILE_EOF) { if (!strcmp(data, "No main function found\n")) { con_err("test failure: `%s` (No main function found) [%s]\n", tmpl->description, tmpl->rulesfile ); if (!process) fs_file_close(execute); else pclose((FILE*)execute); return false; } /* * Trim newlines from data since they will just break our * ability to properly validate matches. */ if (strrchr(data, '\n')) *strrchr(data, '\n') = '\0'; /* * We remove the file/directory and stuff from the error * match messages when testing diagnostics. */ if(!strcmp(tmpl->proceduretype, "-diagnostic")) { if (strstr(data, "there have been errors, bailing out")) continue; /* ignore it */ if (strstr(data, ": error: ")) { char *claim = util_strdup(data + (strstr(data, ": error: ") - data) + 9); mem_d(data); data = claim; } } /* * We need to ignore null lines for when -pp is used (preprocessor), since * the preprocessor is likely to create empty newlines in certain macro * instantations, otherwise it's in the wrong nature to ignore empty newlines. */ if (!strcmp(tmpl->proceduretype, "-pp") && !*data) continue; if (vec_size(tmpl->comparematch) > compare) { if (strcmp(data, tmpl->comparematch[compare++])) { success = false; } } else { success = false; } /* * Copy to output vector for diagnostics if execution match * fails. */ vec_push(*line, data); /* reset */ data = NULL; size = 0; } if (compare != vec_size(tmpl->comparematch)) success = false; mem_d(data); data = NULL; } if (process) retval = pclose((FILE*)execute); else fs_file_close(execute); return success && retval == EXIT_SUCCESS; }
/* * Read a directory and searches for all template files in it * which is later used to run all tests. */ static bool task_propagate(const char *curdir, size_t *pad, const char *defs) { bool success = true; fs_dir_t *dir; fs_dirent_t *files; struct stat directory; char buffer[4096]; size_t found = 0; char **directories = NULL; char *claim = util_strdup(curdir); size_t i; vec_push(directories, claim); dir = fs_dir_open(claim); /* * Generate a list of subdirectories since we'll be checking them too * for tmpl files. */ while ((files = fs_dir_read(dir))) { util_asprintf(&claim, "%s/%s", curdir, files->d_name); if (stat(claim, &directory) == -1) { fs_dir_close(dir); mem_d(claim); return false; } if (S_ISDIR(directory.st_mode) && files->d_name[0] != '.') { vec_push(directories, claim); } else { mem_d(claim); claim = NULL; } } fs_dir_close(dir); /* * Now do all the work, by touching all the directories inside * test as well and compile the task templates into data we can * use to run the tests. */ for (i = 0; i < vec_size(directories); i++) { dir = fs_dir_open(directories[i]); while ((files = fs_dir_read(dir))) { util_snprintf(buffer, sizeof(buffer), "%s/%s", directories[i], files->d_name); if (stat(buffer, &directory) == -1) { con_err("internal error: stat failed, aborting\n"); abort(); } if (S_ISDIR(directory.st_mode)) continue; /* * We made it here, which concludes the file/directory is not * actually a directory, so it must be a file :) */ if (strcmp(files->d_name + strlen(files->d_name) - 5, ".tmpl") == 0) { task_template_t *tmpl = task_template_compile(files->d_name, directories[i], pad); char buf[4096]; /* one page should be enough */ const char *qcflags = NULL; task_t task; found ++; if (!tmpl) { con_err("error compiling task template: %s\n", files->d_name); success = false; continue; } /* * Generate a temportary file name for the output binary * so we don't trample over an existing one. */ tmpl->tempfilename = NULL; util_asprintf(&tmpl->tempfilename, "%s/TMPDAT.%s.dat", directories[i], files->d_name); /* * Additional QCFLAGS enviroment variable may be used * to test compile flags for all tests. This needs to be * BEFORE other flags (so that the .tmpl can override them) */ qcflags = platform_getenv("QCFLAGS"); /* * Generate the command required to open a pipe to a process * which will be refered to with a handle in the task for * reading the data from the pipe. */ if (strcmp(tmpl->proceduretype, "-pp")) { if (qcflags) { if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) { util_snprintf(buf, sizeof(buf), "%s %s/%s %s %s -o %s", task_bins[TASK_COMPILE], directories[i], tmpl->sourcefile, qcflags, tmpl->compileflags, tmpl->tempfilename ); } else { util_snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s %s -o %s", task_bins[TASK_COMPILE], curdir, defs, directories[i], tmpl->sourcefile, qcflags, tmpl->compileflags, tmpl->tempfilename ); } } else { if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) { util_snprintf(buf, sizeof(buf), "%s %s/%s %s -o %s", task_bins[TASK_COMPILE], directories[i], tmpl->sourcefile, tmpl->compileflags, tmpl->tempfilename ); } else { util_snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s -o %s", task_bins[TASK_COMPILE], curdir, defs, directories[i], tmpl->sourcefile, tmpl->compileflags, tmpl->tempfilename ); } } } else { /* Preprocessing (qcflags mean shit all here we don't allow them) */ if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) { util_snprintf(buf, sizeof(buf), "%s -E %s/%s -o %s", task_bins[TASK_COMPILE], directories[i], tmpl->sourcefile, tmpl->tempfilename ); } else { util_snprintf(buf, sizeof(buf), "%s -E %s/%s %s/%s -o %s", task_bins[TASK_COMPILE], curdir, defs, directories[i], tmpl->sourcefile, tmpl->tempfilename ); } } /* * The task template was compiled, now lets create a task from * the template data which has now been propagated. */ task.tmpl = tmpl; if (!(task.runhandles = task_popen(buf, "r"))) { con_err("error opening pipe to process for test: %s\n", tmpl->description); success = false; continue; } /* * Open up some file desciptors for logging the stdout/stderr * to our own. */ util_snprintf(buf, sizeof(buf), "%s.stdout", tmpl->tempfilename); task.stdoutlogfile = util_strdup(buf); if (!(task.stdoutlog = fs_file_open(buf, "w"))) { con_err("error opening %s for stdout\n", buf); continue; } util_snprintf(buf, sizeof(buf), "%s.stderr", tmpl->tempfilename); task.stderrlogfile = util_strdup(buf); if (!(task.stderrlog = fs_file_open(buf, "w"))) { con_err("error opening %s for stderr\n", buf); continue; } vec_push(task_tasks, task); } } fs_dir_close(dir); mem_d(directories[i]); /* free claimed memory */ } vec_free(directories); return success; }
static task_template_t *task_template_compile(const char *file, const char *dir, size_t *pad) { /* a page should be enough */ char fullfile[4096]; size_t filepadd = 0; fs_file_t *tempfile = NULL; task_template_t *tmpl = NULL; util_snprintf(fullfile, sizeof(fullfile), "%s/%s", dir, file); tempfile = fs_file_open(fullfile, "r"); tmpl = (task_template_t*)mem_a(sizeof(task_template_t)); task_template_nullify(tmpl); /* * Create some padding for the printing to align the * printing of the rules file to the console. */ if ((filepadd = strlen(fullfile)) > pad[1]) pad[1] = filepadd; tmpl->rulesfile = util_strdup(fullfile); /* * Esnure the file even exists for the task, this is pretty useless * to even do. */ if (!tempfile) { con_err("template file: %s does not exist or invalid permissions\n", file ); goto failure; } if (!task_template_parse(file, tmpl, tempfile, pad)) { con_err("template parse error: error during parsing\n"); goto failure; } /* * Regardless procedure type, the following tags must exist: * D * T * C * I */ if (!tmpl->description) { con_err("template compile error: %s missing `D:` tag\n", file); goto failure; } if (!tmpl->proceduretype) { con_err("template compile error: %s missing `T:` tag\n", file); goto failure; } if (!tmpl->compileflags) { con_err("template compile error: %s missing `C:` tag\n", file); goto failure; } if (!tmpl->sourcefile) { con_err("template compile error: %s missing `I:` tag\n", file); goto failure; } /* * Now lets compile the template, compilation is really just * the process of validating the input. */ if (!strcmp(tmpl->proceduretype, "-compile")) { if (tmpl->executeflags) con_err("template compile warning: %s erroneous tag `E:` when only compiling\n", file); if (tmpl->comparematch) con_err("template compile warning: %s erroneous tag `M:` when only compiling\n", file); goto success; } else if (!strcmp(tmpl->proceduretype, "-execute")) { if (!tmpl->executeflags) { /* default to $null */ tmpl->executeflags = util_strdup("$null"); } if (!tmpl->comparematch) { con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file); goto failure; } } else if (!strcmp(tmpl->proceduretype, "-fail")) { if (tmpl->executeflags) con_err("template compile warning: %s erroneous tag `E:` when only failing\n", file); if (tmpl->comparematch) con_err("template compile warning: %s erroneous tag `M:` when only failing\n", file); } else if (!strcmp(tmpl->proceduretype, "-diagnostic")) { if (tmpl->executeflags) con_err("template compile warning: %s erroneous tag `E:` when only diagnostic\n", file); if (!tmpl->comparematch) { con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file); goto failure; } } else if (!strcmp(tmpl->proceduretype, "-pp")) { if (tmpl->executeflags) con_err("template compile warning: %s erroneous tag `E:` when only preprocessing\n", file); if (!tmpl->comparematch) { con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file); goto failure; } } else { con_err("template compile error: %s invalid procedure type: %s\n", file, tmpl->proceduretype); goto failure; } success: fs_file_close(tempfile); return tmpl; failure: /* * The file might not exist and we jump here when that doesn't happen * so the check to see if it's not null here is required. */ if (tempfile) fs_file_close(tempfile); mem_d (tmpl); return NULL; }
static char *opts_ini_load(const char *section, const char *name, const char *value, char **parse_file) { char *error = NULL; bool found = false; /* * undef all of these because they may still be defined like in my * case they where. */ #undef GMQCC_TYPE_FLAGS #undef GMQCC_TYPE_OPTIMIZATIONS #undef GMQCC_TYPE_WARNS /* deal with includes */ if (!strcmp(section, "includes")) { static const char *include_error_beg = "failed to open file `"; static const char *include_error_end = "' for inclusion"; fs_file_t *file = fs_file_open(value, "r"); found = true; if (!file) { vec_append(error, strlen(include_error_beg), include_error_beg); vec_append(error, strlen(value), value); vec_append(error, strlen(include_error_end), include_error_end); } else { if (opts_ini_parse(file, &opts_ini_load, &error, parse_file) != 0) found = false; /* Change the file name */ mem_d(*parse_file); *parse_file = util_strdup(value); fs_file_close(file); } } /* flags */ #define GMQCC_TYPE_FLAGS #define GMQCC_DEFINE_FLAG(X) \ if (!strcmp(section, "flags") && !strcmp(name, #X)) { \ opts_set(opts.flags, X, opts_ini_bool(value)); \ found = true; \ } #include "opts.def" /* warnings */ #define GMQCC_TYPE_WARNS #define GMQCC_DEFINE_FLAG(X) \ if (!strcmp(section, "warnings") && !strcmp(name, #X)) { \ opts_set(opts.warn, WARN_##X, opts_ini_bool(value)); \ found = true; \ } #include "opts.def" /* Werror-individuals */ #define GMQCC_TYPE_WARNS #define GMQCC_DEFINE_FLAG(X) \ if (!strcmp(section, "errors") && !strcmp(name, #X)) { \ opts_set(opts.werror, WARN_##X, opts_ini_bool(value)); \ found = true; \ } #include "opts.def" /* optimizations */ #define GMQCC_TYPE_OPTIMIZATIONS #define GMQCC_DEFINE_FLAG(X,Y) \ if (!strcmp(section, "optimizations") && !strcmp(name, #X)) { \ opts_set(opts.optimization, OPTIM_##X, opts_ini_bool(value)); \ found = true; \ } #include "opts.def" /* nothing was found ever! */ if (!found) { if (strcmp(section, "includes") && strcmp(section, "flags") && strcmp(section, "warnings") && strcmp(section, "optimizations")) { static const char *invalid_section = "invalid_section `"; vec_append(error, strlen(invalid_section), invalid_section); vec_append(error, strlen(section), section); vec_push(error, '`'); } else if (strcmp(section, "includes")) { static const char *invalid_variable = "invalid_variable `"; static const char *in_section = "` in section: `"; vec_append(error, strlen(invalid_variable), invalid_variable); vec_append(error, strlen(name), name); vec_append(error, strlen(in_section), in_section); vec_append(error, strlen(section), section); vec_push(error, '`'); } else { static const char *expected_something = "expected something"; vec_append(error, strlen(expected_something), expected_something); } } vec_push(error, '\0'); return error; }
/* * Insertion functions (the opposite of extraction). Yes for generating * PAKs. */ static bool pak_insert_one(pak_file_t *pak, const char *file) { pak_directory_t dir; unsigned char *dat; long len; FILE *fp; /* * We don't allow insertion on files that already exist within the * pak file. Weird shit can happen if we allow that ;). We also * don't allow insertion if the pak isn't opened in write mode. */ if (!pak || !file || !pak->insert || pak_exists(pak, file, NULL)) return false; if (!(fp = fs_file_open(file, "rb"))) return false; /* * Calculate the total file length, since it will be wrote to * the directory entry, and the actual contents of the file * to the PAK file itself. */ if (fs_file_seek(fp, 0, SEEK_END) != 0 || ((len = fs_file_tell(fp)) < 0)) goto err; if (fs_file_seek(fp, 0, SEEK_SET) != 0) goto err; dir.len = len; dir.pos = fs_file_tell(pak->handle); /* * We're limited to 56 bytes for a file name string, that INCLUDES * the directory and '/' seperators. */ if (strlen(file) >= 56) goto err; util_strncpy(dir.name, file, strlen(file)); /* * Allocate some memory for loading in the data that will be * redirected into the PAK file. */ if (!(dat = (unsigned char *)mem_a(dir.len))) goto err; fs_file_read (dat, dir.len, 1, fp); fs_file_close(fp); fs_file_write(dat, dir.len, 1, pak->handle); /* * Now add the directory to the directories vector, so pak_close * can actually write it. */ vec_push(pak->directories, dir); return true; err: fs_file_close(fp); return false; }