static void task_template_destroy(task_template_t *tmpl) { if (!tmpl) return; if (tmpl->description) mem_d(tmpl->description); if (tmpl->proceduretype) mem_d(tmpl->proceduretype); if (tmpl->compileflags) mem_d(tmpl->compileflags); if (tmpl->executeflags) mem_d(tmpl->executeflags); if (tmpl->sourcefile) mem_d(tmpl->sourcefile); if (tmpl->rulesfile) mem_d(tmpl->rulesfile); if (tmpl->testflags) mem_d(tmpl->testflags); /* * Delete all allocated string for task tmpl then destroy the * main vector. */ { size_t i = 0; for (; i < vec_size(tmpl->comparematch); i++) mem_d(tmpl->comparematch[i]); vec_free(tmpl->comparematch); } /* * Nullify all the template members otherwise NULL comparision * checks will fail if tmpl pointer is reused. */ mem_d(tmpl->tempfilename); mem_d(tmpl); }
static GMQCC_INLINE void correct_trie_del(correct_trie_t *t) { size_t i; if (t->entries) { for (i = 0; i < sizeof(correct_alpha)-1; ++i) correct_trie_del_sub(&t->entries[i]); mem_d(t->entries); } mem_d(t); }
void prog_delete(qc_program_t *prog) { if (prog->filename) mem_d(prog->filename); vec_free(prog->entitydata); vec_free(prog->entitypool); vec_free(prog->localstack); vec_free(prog->stack); vec_free(prog->profile); mem_d(prog); }
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; }
/* * The following functions below implement printing / dumping of statistical * information. */ static void stat_dump_mem_contents(stat_mem_block_t *block, uint16_t cols) { unsigned char *buffer = (unsigned char *)mem_a(cols); unsigned char *memory = (unsigned char *)(block + 1); size_t i; for (i = 0; i < block->size; i++) { if (!(i % 16)) { if (i != 0) con_out(" %s\n", buffer); con_out(" 0x%08X: ", i); } con_out(" %02X", memory[i]); buffer[i % cols] = ((memory[i] < 0x20) || (memory[i] > 0x7E)) ? '.' : memory[i]; buffer[(i % cols) + 1] = '\0'; } while ((i % cols) != 0) { con_out(" "); i++; } con_out(" %s\n", buffer); mem_d(buffer); }
/* * 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); }
/* * EXPOSED INTERFACE for the hashtable implementation * util_htnew(size) -- to make a new hashtable * util_htset(table, key, value, sizeof(value)) -- to set something in the table * util_htget(table, key) -- to get something from the table * util_htdel(table) -- to delete the table */ hash_table_t *util_htnew(size_t size) { hash_table_t *hashtable = NULL; stat_size_entry_t *find = NULL; if (size < 1) return NULL; if (!stat_size_hashtables) stat_size_hashtables = stat_size_new(); if (!(hashtable = (hash_table_t*)mem_a(sizeof(hash_table_t)))) return NULL; if (!(hashtable->table = (hash_node_t**)mem_a(sizeof(hash_node_t*) * size))) { mem_d(hashtable); return NULL; } if ((find = stat_size_get(stat_size_hashtables, size))) find->value++; else { stat_type_hashtables++; stat_size_put(stat_size_hashtables, size, 1); } hashtable->size = size; memset(hashtable->table, 0, sizeof(hash_node_t*) * size); stat_used_hashtables++; return hashtable; }
int platform_vasprintf(char **dat, const char *fmt, va_list args) { int ret; int len; char *tmp = NULL; char buf[128]; va_list cpy; va_copy(cpy, args); len = vsnprintf(buf, sizeof(buf), fmt, cpy); va_end (cpy); if (len < (int)sizeof(buf)) { *dat = util_strdup(buf); return len; } tmp = (char*)mem_a(len + 1); if ((ret = vsnprintf(tmp, len + 1, fmt, args)) != len) { mem_d(tmp); *dat = NULL; return -1; } *dat = tmp; return len; }
void prog_delete(qc_program *prog) { if (prog->filename) mem_d(prog->filename); vec_free(prog->code); vec_free(prog->defs); vec_free(prog->fields); vec_free(prog->functions); vec_free(prog->strings); vec_free(prog->globals); vec_free(prog->entitydata); vec_free(prog->entitypool); vec_free(prog->localstack); vec_free(prog->stack); vec_free(prog->profile); mem_d(prog); }
static bool pak_close(pak_file_t *pak) { size_t itr; long tell; if (!pak) return false; /* * In insert mode we need to patch the header, and write * our directory entries at the end of the file. */ if (pak->insert) { if ((tell = fs_file_tell(pak->handle)) != 0) goto err; pak->header.dirlen = vec_size(pak->directories) * 64; pak->header.diroff = tell; /* patch header */ if (fs_file_seek (pak->handle, 0, SEEK_SET) != 0) goto err; fs_file_write(&(pak->header), sizeof(pak_header_t), 1, pak->handle); /* write directories */ if (fs_file_seek (pak->handle, pak->header.diroff, SEEK_SET) != 0) goto err; for (itr = 0; itr < vec_size(pak->directories); itr++) { fs_file_write(&(pak->directories[itr]), sizeof(pak_directory_t), 1, pak->handle); } } vec_free (pak->directories); fs_file_close(pak->handle); mem_d (pak); return true; err: vec_free (pak->directories); fs_file_close(pak->handle); mem_d (pak); return false; }
static GMQCC_INLINE void correct_trie_del_sub(correct_trie_t *t) { size_t i; if (!t->entries) return; for (i = 0; i < sizeof(correct_alpha)-1; ++i) { correct_trie_del_sub(&t->entries[i]); } mem_d(t->entries); }
static GMQCC_INLINE void correct_pool_delete(void) { size_t i; for (i = 0; i < vec_size(correct_pool_data); ++i) mem_d(correct_pool_data[i]); correct_pool_data = NULL; correct_pool_this = NULL; correct_pool_addr = 0; }
void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)) { hash_node_t **pair = &ht->table[bin]; hash_node_t *tmp; while (*pair && (*pair)->key && strcmp(key, (*pair)->key) > 0) pair = &(*pair)->next; tmp = *pair; if (!tmp || !tmp->key || strcmp(key, tmp->key) != 0) return; if (cb) (*cb)(tmp->value); *pair = tmp->next; mem_d(tmp->key); mem_d(tmp); }
void correct_del(correct_trie_t* dictonary, size_t **data) { size_t i; const size_t vs = vec_size(data); for (i = 0; i < vs; i++) mem_d(data[i]); vec_free(data); correct_trie_del(dictonary); }
static int task_pclose(fs_file_t **files) { popen_t *open = ((popen_t*)files); fs_file_close(files[1]); fs_file_close(files[2]); remove(open->name_err); remove(open->name_out); mem_d(open); return EXIT_SUCCESS; }
void code_cleanup(code_t *code) { vec_free(code->statements); vec_free(code->linenums); vec_free(code->columnnums); vec_free(code->defs); vec_free(code->fields); vec_free(code->functions); vec_free(code->globals); vec_free(code->chars); util_htdel(code->string_cache); mem_d(code); }
static int task_pclose(fs_file_t **handles) { popen_t *data = (popen_t*)handles; int status = 0; close(data->pipes[0]); /* stdin */ close(data->pipes[1]); /* stdout */ close(data->pipes[2]); /* stderr */ waitpid(data->pid, &status, 0); mem_d(data); return status; }
/* * Free all allocated data in a hashtable, this is quite the amount * of work. */ void util_htrem(hash_table_t *ht, void (*callback)(void *data)) { size_t i = 0; for (; i < ht->size; ++i) { hash_node_t *n = ht->table[i]; hash_node_t *p; /* free in list */ while (n) { if (n->key) mem_d(n->key); if (callback) callback(n->value); p = n; n = p->next; mem_d(p); } } /* free table */ mem_d(ht->table); mem_d(ht); }
static void task_destroy(void) { /* * Free all the data in the task list and finally the list itself * then proceed to cleanup anything else outside the program like * temporary files. */ size_t i; for (i = 0; i < vec_size(task_tasks); i++) { /* * Close any open handles to files or processes here. It's mighty * annoying to have to do all this cleanup work. */ if (task_tasks[i].stdoutlog) fs_file_close (task_tasks[i].stdoutlog); if (task_tasks[i].stderrlog) fs_file_close (task_tasks[i].stderrlog); /* * Only remove the log files if the test actually compiled otherwise * forget about it (or if it didn't compile, and the procedure type * was set to -fail (meaning it shouldn't compile) .. stil remove) */ if (task_tasks[i].compiled || !strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) { if (remove(task_tasks[i].stdoutlogfile)) con_err("error removing stdout log file: %s\n", task_tasks[i].stdoutlogfile); if (remove(task_tasks[i].stderrlogfile)) con_err("error removing stderr log file: %s\n", task_tasks[i].stderrlogfile); (void)!remove(task_tasks[i].tmpl->tempfilename); } /* free util_strdup data for log files */ mem_d(task_tasks[i].stdoutlogfile); mem_d(task_tasks[i].stderrlogfile); task_template_destroy(task_tasks[i].tmpl); } vec_free(task_tasks); }
static hash_node_t *_util_htnewpair(const char *key, void *value) { hash_node_t *node; if (!(node = (hash_node_t*)mem_a(sizeof(hash_node_t)))) return NULL; if (!(node->key = util_strdupe(key))) { mem_d(node); return NULL; } node->value = value; node->next = NULL; return node; }
/* * When given a string like "a/b/c/d/e/file" * this function will handle the creation of * the directory structure, included nested * directories. */ static void pak_tree_build(const char *entry) { char *directory; char *elements[28]; char *pathsplit; char *token; size_t itr; size_t jtr; pathsplit = (char *)mem_a(56); directory = (char *)mem_a(56); memset(pathsplit, 0, 56); util_strncpy(directory, entry, 56); for (itr = 0; (token = pak_tree_sep(&directory, "/")) != NULL; itr++) { elements[itr] = token; } for (jtr = 0; jtr < itr - 1; jtr++) { util_strcat(pathsplit, elements[jtr]); util_strcat(pathsplit, "/"); if (fs_dir_make(pathsplit)) { mem_d(pathsplit); mem_d(directory); /* TODO: undo on fail */ return; } } mem_d(pathsplit); mem_d(directory); }
void fold_cleanup(fold_t *fold) { size_t i; for (i = 0; i < vec_size(fold->imm_float); ++i) ast_delete(fold->imm_float[i]); for (i = 0; i < vec_size(fold->imm_vector); ++i) ast_delete(fold->imm_vector[i]); for (i = 0; i < vec_size(fold->imm_string); ++i) ast_delete(fold->imm_string[i]); vec_free(fold->imm_float); vec_free(fold->imm_vector); vec_free(fold->imm_string); util_htdel(fold->imm_string_untranslate); util_htdel(fold->imm_string_dotranslate); mem_d(fold); }
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; }
void _util_vec_delete(void *data, size_t line, const char *file) { char *ident = (char *)data - IDENT_SIZE; if (!strcmp(ident, IDENT_MEM)) { stat_mem_block_t *block = (stat_mem_block_t*)((char *)data - IDENT_MEM_TOP); VALGRIND_MAKE_MEM_DEFINED(block, sizeof(stat_mem_block_t)); con_err("internal warning: invalid use of vec_free:\n"); con_err("internal warning: memory block last allocated (size: %u (bytes), at %s:%u)\n", (unsigned)block->size, block->file, (unsigned)block->line); con_err("internal warning: released with with wrong routine at %s:%u\n", file, (unsigned)line); con_err("internal warning: forwarding to mem_d, please fix it\n"); VALGRIND_MAKE_MEM_NOACCESS(block, sizeof(stat_mem_block_t)); mem_d(data); return; } /* forward */ stat_mem_deallocate((void*)(ident - sizeof(vector_t)), line, file); }
static int qc_strcat(qc_program_t *prog) { char *buffer; size_t len1, len2; qcany_t *str1, *str2; qcany_t out; const char *cstr1; const char *cstr2; CheckArgs(2); str1 = GetArg(0); str2 = GetArg(1); cstr1 = prog_getstring(prog, str1->string); cstr2 = prog_getstring(prog, str2->string); len1 = strlen(cstr1); len2 = strlen(cstr2); buffer = (char*)mem_a(len1 + len2 + 1); memcpy(buffer, cstr1, len1); memcpy(buffer+len1, cstr2, len2+1); out.string = prog_tempstring(prog, buffer); mem_d(buffer); Return(out); return 0; }
static void stat_size_del(stat_size_table_t table) { size_t i = 0; for (; i < ST_SIZE; i++) if(table[i]) mem_d(table[i]); mem_d(table); }
/* * 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; }