int super_html_read_serve( FILE *flog, const unsigned char *path, const struct ejudge_cfg *config, const struct contest_desc *cnts, struct sid_state *sstate) { struct stat sb; int cond_count = 0, total, i, cur_id, j, arch, k; struct generic_section_config *pg; struct section_global_data *global; struct section_problem_data *prob, *aprob; struct section_tester_data *tst, *atst; struct section_language_data *lang; size_t vm_size, st_size; size_t *mem_lims, *st_lims; int *mem_cnt, *st_cnt; //int mem_u, st_u, max_i; path_t check_cmd = { 0 }; FILE *fuh; char *fuh_text = 0; size_t fuh_size = 0; path_t cs_spool_dir; path_t conf_dir; path_t tmppath; unsigned char *prob_no_any = 0; size_t cs_spool_dir_len = 0; unsigned char cs_conf_file[PATH_MAX]; if (!cnts) { fprintf(flog, "No contest XML description\n"); return -1; } if (!cnts->conf_dir || !*cnts->conf_dir) { snprintf(conf_dir, sizeof(conf_dir), "%s/%s", cnts->root_dir, "conf"); } else if (!os_IsAbsolutePath(cnts->conf_dir)) { snprintf(conf_dir, sizeof(conf_dir), "%s/%s", cnts->root_dir, cnts->conf_dir); } else { snprintf(conf_dir, sizeof(conf_dir), "%s", cnts->conf_dir); } if (stat(path, &sb) < 0) { // file do not exist return 0; } if (!S_ISREG(sb.st_mode)) { fprintf(flog, "File `%s' not a regular file\n", path); return -1; } if (access(path, R_OK) < 0) { fprintf(flog, "File `%s' is not readable\n", path); return -1; } // FIXME: redirect output? if (!(sstate->cfg = prepare_parse_config_file(path, &cond_count))) { fprintf(flog, "Parsing of `%s' failed\n", path); return -1; } if (cond_count > 0) { fprintf(flog, "The configuration file uses conditional compilation directives\n"); return -1; } // find global section for (pg = sstate->cfg; pg; pg = pg->next) if (!pg->name[0] || !strcmp(pg->name, "global")) break; if (!pg) { fprintf(flog, "The global section is not defined\n"); return -1; } global = sstate->global = (struct section_global_data *) pg; // set up the default value of the root_dir if (!global->root_dir[0]) { snprintf(global->root_dir, sizeof(global->root_dir), "%06d", global->contest_id); } if (!os_IsAbsolutePath(global->root_dir) && config && config->contests_home_dir && os_IsAbsolutePath(config->contests_home_dir)) { snprintf(tmppath, sizeof(tmppath), "%s/%s", config->contests_home_dir, global->root_dir); snprintf(global->root_dir, sizeof(global->root_dir), "%s", tmppath); } #if defined EJUDGE_CONTESTS_HOME_DIR if (!os_IsAbsolutePath(global->root_dir)) { snprintf(tmppath, sizeof(tmppath), "%s/%s", EJUDGE_CONTESTS_HOME_DIR, global->root_dir); snprintf(global->root_dir, sizeof(global->root_dir), "%s", tmppath); } #endif if (!os_IsAbsolutePath(global->root_dir)) { err("global.root_dir must be absolute directory!"); return -1; } // check variables that we don't want to be ever set if (prepare_check_forbidden_global(flog, global) < 0) return -1; // contest_id, conf_dir, root_dir must match if (global->contest_id != cnts->id) { fprintf(flog, "contest_id does not match\n"); return -1; } if (strcmp(global->root_dir, cnts->root_dir)) { fprintf(flog, "root_dir does not match\n"); return -1; } /* if ((!cnts->conf_dir && global->conf_dir) || (cnts->conf_dir && strcmp(cnts->conf_dir, global->conf_dir))) { fprintf(flog, "conf_dir does not match\n"); return -1; } */ // compile server must be used if (!global->compile_dir[0]) { fprintf(flog, "compilation server is not used\n"); return -1; } if (!os_IsAbsolutePath(global->compile_dir)) { snprintf(tmppath, sizeof(tmppath), "%s/var/%s", global->root_dir, global->compile_dir); path_normalize(tmppath, sizeof(tmppath)); snprintf(global->compile_dir, sizeof(global->compile_dir), "%s", tmppath); } if (!config->compile_home_dir) { fprintf(flog, "compile server home dir is not set\n"); return -1; } // cut off "/var/compile" suffix from the compile dir snprintf(cs_spool_dir, sizeof(cs_spool_dir), "%s", global->compile_dir); cs_spool_dir_len = strlen(cs_spool_dir); if (cs_spool_dir_len < sizeof(compile_dir_suffix) || strcmp(cs_spool_dir+cs_spool_dir_len-sizeof(compile_dir_suffix)+1, compile_dir_suffix) != 0) { fprintf(flog, "invalid `compile_dir' %s\n", cs_spool_dir); return -1; } cs_spool_dir[cs_spool_dir_len-sizeof(compile_dir_suffix)+1] = 0; sstate->compile_home_dir = xstrdup(cs_spool_dir); //fprintf(stderr, "compile_home_dir>>%s<<\n", sstate->compile_home_dir); /* snprintf(cs_spool_dir, sizeof(cs_spool_dir), "%s/var/compile", config->compile_home_dir); if (strcmp(cs_spool_dir, global->compile_dir)) { fprintf(flog, "non-default compilation server is used\n"); return -1; } */ prepare_set_global_defaults(global); if (global->stand2_file_name[0]) sstate->enable_stand2 = 1; if (global->plog_file_name[0]) sstate->enable_plog = 1; if (global->stand_extra_format[0]) sstate->enable_extra_col = 1; fuh = open_memstream(&fuh_text, &fuh_size); prepare_unparse_unhandled_global(fuh, global); close_memstream(fuh); fuh = 0; if (fuh_text && *fuh_text) { global->unhandled_vars = fuh_text; } else { xfree(fuh_text); } fuh_text = 0; fuh_size = 0; // collect languages total = 0; cur_id = 0; for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "language") != 0) continue; lang = (struct section_language_data*) pg; if (!lang->id) lang->id = cur_id + 1; cur_id = lang->id; if (lang->id <= 0 || lang->id > EJ_MAX_LANG_ID) { fprintf(flog, "Invalid language ID\n"); return -1; } if (lang->id >= total) total = lang->id + 1; } sstate->lang_a = 0; sstate->langs = 0; sstate->loc_cs_map = 0; sstate->lang_opts = 0; sstate->lang_flags = 0; if (total > 0) { sstate->lang_a = 4; while (total > sstate->lang_a) sstate->lang_a *= 2; XCALLOC(sstate->langs, sstate->lang_a); XCALLOC(sstate->loc_cs_map, sstate->lang_a); XCALLOC(sstate->lang_opts, sstate->lang_a); XCALLOC(sstate->lang_flags, sstate->lang_a); for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "language") != 0) continue; lang = (struct section_language_data*) pg; if (sstate->langs[lang->id]) { fprintf(flog, "Duplicated language ID %d\n", lang->id); return -1; } sstate->langs[lang->id] = lang; } } // load the compilation server state and establish correspondence if (super_load_cs_languages(config, sstate, global->extra_compile_dirs, 0, cs_conf_file, sizeof(cs_conf_file)) < 0) { fprintf(flog, "Failed to load compilation server configuration\n"); return -1; } for (i = 1; i < sstate->lang_a; i++) { if (!(lang = sstate->langs[i])) continue; if (!lang->compile_id) lang->compile_id = lang->id; if (prepare_check_forbidden_lang(flog, lang) < 0) return -1; /* if (lang->compile_id <= 0 || lang->compile_id >= sstate->cs_lang_total || !sstate->cs_langs[lang->compile_id]) { } */ // improve error messaging if (lang->compile_id > 0 && lang->compile_id < sstate->cs_lang_total && sstate->cs_langs[lang->compile_id] && strcmp(lang->short_name, sstate->cs_langs[lang->compile_id]->short_name) != 0) { fprintf(flog, "contest configuration file '%s' specifies language short name '%s' for language %d\n" "and it is different from language short name '%s' in compilation configuration file '%s'\n", path, lang->short_name, lang->compile_id, sstate->cs_langs[lang->compile_id]->short_name, cs_conf_file); return -1; } if (lang->compile_id <= 0 || lang->compile_id >= sstate->cs_lang_total || !sstate->cs_langs[lang->compile_id] || strcmp(lang->short_name, sstate->cs_langs[lang->compile_id]->short_name) != 0) { lang->compile_id = 0; } for (int j = 1; j < sstate->cs_lang_total; ++j) { if (sstate->cs_langs[j] && !strcmp(lang->short_name, sstate->cs_langs[j]->short_name)) { lang->compile_id = j; break; } } if (lang->compile_id <= 0) { fprintf(flog, "Invalid compile_id\n"); return -1; } sstate->loc_cs_map[lang->id] = lang->compile_id; sstate->cs_loc_map[lang->compile_id] = lang->id; fuh = open_memstream(&fuh_text, &fuh_size); prepare_unparse_unhandled_lang(fuh, lang); close_memstream(fuh); fuh = 0; if (fuh_text && *fuh_text) { lang->unhandled_vars = fuh_text; } else { xfree(fuh_text); } fuh_text = 0; fuh_size = 0; if (lang->compiler_env) { for (j = 0; lang->compiler_env[j]; j++) { if (!strncmp(lang->compiler_env[j], "EJUDGE_FLAGS=", 13)) { sstate->lang_opts[lang->id] = xstrmerge1(sstate->lang_opts[lang->id], lang->compiler_env[j] + 13); } } for (--j; j >= 0; --j) { if (!strncmp(lang->compiler_env[j], "EJUDGE_FLAGS=", 13)) { xfree(lang->compiler_env[j]); lang->compiler_env[j] = 0; for (k = j + 1; lang->compiler_env[k]; k++) { lang->compiler_env[k - 1] = lang->compiler_env[k]; } lang->compiler_env[k - 1] = lang->compiler_env[k]; } } } } // collect abstract problems for (pg = sstate->cfg, total = 0; pg; pg = pg->next) { if (!strcmp(pg->name, "problem") && (prob = (struct section_problem_data*) pg)->abstract) total++; } sstate->aprob_a = 0; sstate->aprob_u = 0; sstate->aprobs = 0; sstate->aprob_flags = 0; if (total) { sstate->aprob_a = 4; while (total > sstate->aprob_a) sstate->aprob_a *= 2; XCALLOC(sstate->aprobs, sstate->aprob_a); XCALLOC(sstate->aprob_flags, sstate->aprob_a); for (pg = sstate->cfg, i = 0; pg; pg = pg->next) { if (strcmp(pg->name, "problem") != 0) continue; prob = (struct section_problem_data*) pg; if (!prob->abstract) continue; sstate->aprobs[i++] = prob; if (!prob->short_name[0]) { fprintf(flog, "Abstract problem must have `short_name' field set\n"); return -1; } if (prob->super[0]) { fprintf(flog, "Abstract problem must not have a superproblem\n"); return -1; } if (prepare_check_forbidden_prob(flog, prob) < 0) return -1; prepare_set_abstr_problem_defaults(prob, global); fuh = open_memstream(&fuh_text, &fuh_size); prepare_unparse_unhandled_prob(fuh, prob, global); close_memstream(fuh); fuh = 0; if (fuh_text && *fuh_text) { prob->unhandled_vars = fuh_text; } else { xfree(fuh_text); } fuh_text = 0; fuh_size = 0; } ASSERT(i == total); sstate->aprob_u = total; } // collect concrete problems total = 0; cur_id = 0; for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "problem") != 0) continue; prob = (struct section_problem_data*) pg; if (prob->abstract) continue; if (!prob->id) prob->id = cur_id + 1; cur_id = prob->id; if (prob->id <= 0 || prob->id > EJ_MAX_PROB_ID) { fprintf(flog, "Invalid problem ID\n"); return -1; } if (prob->id >= total) total = prob->id + 1; } sstate->probs = 0; sstate->prob_a = 0; sstate->prob_flags = 0; if (total > 0) { sstate->prob_a = 4; while (total > sstate->prob_a) sstate->prob_a *= 2; XCALLOC(sstate->probs, sstate->prob_a); XCALLOC(sstate->prob_flags, sstate->prob_a); XALLOCAZ(prob_no_any, sstate->prob_a); for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "problem") != 0) continue; prob = (struct section_problem_data*) pg; if (prob->abstract) continue; if (sstate->probs[prob->id]) { fprintf(flog, "Duplicated problem id %d\n", prob->id); return -1; } sstate->probs[prob->id] = prob; if (prob->super[0]) { for (i = 0; i < sstate->aprob_u; i++) if (!strcmp(prob->super, sstate->aprobs[i]->short_name)) break; if (i == sstate->aprob_u) { fprintf(flog, "Abstract problem `%s' not found\n", prob->super); return -1; } } if (prepare_check_forbidden_prob(flog, prob) < 0) return -1; prepare_set_concr_problem_defaults(prob, global); fuh = open_memstream(&fuh_text, &fuh_size); prepare_unparse_unhandled_prob(fuh, prob, global); close_memstream(fuh); fuh = 0; if (fuh_text && *fuh_text) { prob->unhandled_vars = fuh_text; } else { xfree(fuh_text); } fuh_text = 0; fuh_size = 0; } } // collect abstract testers total = 0; for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "tester")) continue; tst = (struct section_tester_data*) pg; if (!tst->abstract) continue; // check, that we know such abstract tester if ((arch = prepare_unparse_is_supported_tester(tst->name)) < 0) { fprintf(flog, "Unsupported abstract tester `%s'\n", tst->name); return -1; } if ((i = prepare_unparse_is_supported_arch(tst->arch)) < 0) { fprintf(flog, "Unsupported tester architecture `%s'\n", tst->arch); return -1; } if (i != arch) { fprintf(flog, "Abstract tester name does not match tester arch\n"); return -1; } if (tst->id) { fprintf(flog, "Abstract tester must not define tester ID\n"); return -1; } if (tst->problem_name[0]) { fprintf(flog, "Abstract tester must not define problem name\n"); return -1; } if (tst->problem) { fprintf(flog, "Abstract tester must not define problem ID\n"); return -1; } total++; } /* Relax, try to work without testers... */ /* if (!total) { fprintf(flog, "No abstract testers defined\n"); return -1; } */ sstate->atester_total = total; if (total > 0) { XCALLOC(sstate->atesters, sstate->atester_total); for (pg = sstate->cfg, i = 0; pg; pg = pg->next) { if (strcmp(pg->name, "tester")) continue; tst = (struct section_tester_data*) pg; if (!tst->abstract) continue; sstate->atesters[i++] = tst; // FIXME: check for unhandled fields } } // collect concrete testers, attempting to recover vm limit, stack limit // and checker name total = 0; cur_id = 0; for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "tester") != 0) continue; tst = (struct section_tester_data*) pg; if (tst->abstract) continue; if (!tst->id) tst->id = cur_id + 1; cur_id = tst->id; if (tst->id <= 0 || tst->id > EJ_MAX_TESTER) { fprintf(flog, "Invalid tester ID\n"); return -1; } if (tst->id >= total) total = tst->id + 1; } sstate->tester_total = total; if (total > 0) { XCALLOC(sstate->testers, sstate->tester_total); } for (pg = sstate->cfg; pg; pg = pg->next) { if (strcmp(pg->name, "tester") != 0) continue; tst = (struct section_tester_data*) pg; if (tst->abstract) continue; if (sstate->testers[tst->id]) { fprintf(flog, "Duplicated tester ID %d\n", tst->id); return -1; } sstate->testers[tst->id] = tst; if (tst->super && tst->super[0] && tst->super[1]) { fprintf(flog, "Tester %d has several supertesters\n", tst->id); return -1; } atst = 0; if (tst->super) { for (i = 0; i < sstate->atester_total; i++) if (!strcmp(sstate->atesters[i]->name, tst->super[0])) break; if (i == sstate->atester_total) { fprintf(flog, "Abstract tester `%s' not found\n", tst->super[0]); return -1; } atst = sstate->atesters[i]; } if (tst->any) { continue; } prob = 0; if (tst->problem && tst->problem_name[0]) { fprintf(flog, "Both problem and problem_name fields cannot be set\n"); return -1; } else if (tst->problem) { if (tst->problem <= 0 || tst->problem >= sstate->prob_a || !sstate->probs[tst->problem]) { fprintf(flog, "problem %d is invalid\n", tst->problem); return -1; } prob = sstate->probs[tst->problem]; } else if (tst->problem_name[0]) { for (i = 1; i < sstate->prob_a; i++) if (sstate->probs[i] && !strcmp(sstate->probs[i]->short_name, tst->problem_name)) break; if (i == sstate->prob_a) { fprintf(flog, "Problem `%s' does not exist\n", tst->problem_name); return -1; } prob = sstate->probs[i]; } else { fprintf(flog, "Neither problem not problem_name are set\n"); return -1; } prob_no_any[prob->id] = 1; vm_size = tst->max_vm_size; if (vm_size == -1L && atst) vm_size = atst->max_vm_size; st_size = tst->max_stack_size; if (st_size == -1L && atst) st_size = atst->max_stack_size; if (vm_size != -1L) { if (prob->max_vm_size == -1L) prob->max_vm_size = vm_size; if (prob->max_vm_size != vm_size) { fprintf(flog, "Conflicting max_vm_size specifications for problem `%s'\n", prob->short_name); return -1; } } if (st_size != -1L) { if (prob->max_stack_size == -1L) prob->max_stack_size = st_size; if (prob->max_stack_size != st_size) { fprintf(flog, "Conflicting max_stack_size specifications for problem `%s'\n", prob->short_name); return -1; } } } for (i = 0; i < sstate->tester_total; i++) { if (!(tst = sstate->testers[i])) continue; atst = 0; if (tst->super) { for (j = 0; j < sstate->atester_total; j++) if (!strcmp(sstate->atesters[j]->name, tst->super[0])) break; if (j == sstate->atester_total) { fprintf(flog, "Abstract tester `%s' not found\n", tst->super[0]); return -1; } atst = sstate->atesters[j]; } if (!tst->any) continue; for (j = 0; j < sstate->prob_a; j++) { if (!(prob = sstate->probs[j])) continue; if (prob_no_any[j]) continue; vm_size = tst->max_vm_size; if (vm_size == -1L && atst) vm_size = atst->max_vm_size; st_size = tst->max_stack_size; if (st_size == -1L && atst) st_size = atst->max_stack_size; if (vm_size != -1L) { if (prob->max_vm_size == -1L) prob->max_vm_size = vm_size; if (prob->max_vm_size != vm_size) { fprintf(flog, "Conflicting max_vm_size specifications for problem `%s'\n", prob->short_name); return -1; } } if (st_size != -1L) { if (prob->max_stack_size == -1L) prob->max_stack_size = st_size; if (prob->max_stack_size != st_size) { fprintf(flog, "Conflicting max_stack_size specifications for problem `%s'\n", prob->short_name); return -1; } } } } XALLOCA(mem_lims, sstate->prob_a); XALLOCA(st_lims, sstate->prob_a); XALLOCA(mem_cnt, sstate->prob_a); XALLOCA(st_cnt, sstate->prob_a); // propagate most used memory limit to superproblem /* for (i = 0; i < sstate->aprob_u; i++) { aprob = sstate->aprobs[i]; mem_u = 0; st_u = 0; XMEMZERO(mem_cnt, sstate->prob_a); XMEMZERO(st_cnt, sstate->prob_a); for (j = 1; j < sstate->prob_a; j++) { if (!(prob = sstate->probs[j]) || !prob->super[0] || strcmp(prob->super, aprob->short_name)) continue; if (prob->max_vm_size != -1L) { for (k = 0; k < mem_u; k++) if (mem_lims[k] == prob->max_vm_size) break; if (k == mem_u) mem_u++; mem_lims[k] = prob->max_vm_size; mem_cnt[k]++; } if (prob->max_stack_size != -1L) { for (k = 0; k < st_u; k++) if (st_lims[k] == prob->max_stack_size) break; if (k == st_u) st_u++; st_lims[k] = prob->max_stack_size; st_cnt[k]++; } } if (mem_u > 0) { max_i = 0; for (i = 1; i < mem_u; i++) if (mem_cnt[i] > mem_cnt[max_i]) max_i = i; aprob->max_vm_size = mem_lims[max_i]; for (j = 1; j < sstate->prob_a; j++) { if (!(prob = sstate->probs[j]) || !prob->super[0] || strcmp(prob->super, aprob->short_name)) continue; if (prob->max_vm_size == -1L) { prob->max_vm_size = 0; } else if (prob->max_vm_size == aprob->max_vm_size) { prob->max_vm_size = -1L; } } } if (st_u > 0) { max_i = 0; for (i = 1; i < st_u; i++) if (st_cnt[i] > st_cnt[max_i]) max_i = i; aprob->max_stack_size = st_lims[max_i]; for (j = 1; j < sstate->prob_a; j++) { if (!(prob = sstate->probs[j]) || !prob->super[0] || strcmp(prob->super, aprob->short_name)) continue; if (prob->max_stack_size == -1L) { prob->max_stack_size = 0; } else if (prob->max_stack_size == aprob->max_stack_size) { prob->max_stack_size = -1L; } } } } */ // assign this check_cmd to all abstract problems without check_cmd for (i = 0; i < sstate->aprob_u; i++) if (!(aprob = sstate->aprobs[i])->check_cmd[0]) snprintf(aprob->check_cmd, sizeof(aprob->check_cmd), "%s", check_cmd); sstate->contest_start_cmd_text = do_load_file(conf_dir, global->contest_start_cmd); sstate->contest_stop_cmd_text = do_load_file(conf_dir, global->contest_stop_cmd); sstate->stand_header_text = do_load_file(conf_dir, global->stand_header_file); sstate->stand_footer_text = do_load_file(conf_dir, global->stand_footer_file); sstate->stand2_header_text = do_load_file(conf_dir, global->stand2_header_file); sstate->stand2_footer_text = do_load_file(conf_dir, global->stand2_footer_file); sstate->plog_header_text = do_load_file(conf_dir, global->plog_header_file); sstate->plog_footer_text = do_load_file(conf_dir, global->plog_footer_file); return 0; }
static int handle_conditional(FILE *f) { int c; unsigned char *cmd, *p; struct cond_stack *new_item = 0; cfg_cond_value_t val; // initialize the parsecfg_state.raw buffer parsecfg_state.raw.u = 0; if (!parsecfg_state.raw.a) { parsecfg_state.raw.a = 1024; XCALLOC(parsecfg_state.raw.s, parsecfg_state.raw.a); } parsecfg_state.raw.s[parsecfg_state.raw.u] = 0; // read the line into the buffer while ((c = fgetc(f)) != EOF && c != '\n') { if (!c) continue; if (parsecfg_state.raw.u >= parsecfg_state.raw.a) { parsecfg_state.raw.a *= 2; XREALLOC(parsecfg_state.raw.s, parsecfg_state.raw.a); } parsecfg_state.raw.s[parsecfg_state.raw.u++] = c; } if (parsecfg_state.raw.u >= parsecfg_state.raw.a) { parsecfg_state.raw.a *= 2; XREALLOC(parsecfg_state.raw.s, parsecfg_state.raw.a); } parsecfg_state.raw.s[parsecfg_state.raw.u] = 0; while (parsecfg_state.raw.u > 0 && isspace(parsecfg_state.raw.s[parsecfg_state.raw.u - 1])) parsecfg_state.raw.s[--parsecfg_state.raw.u] = 0; parsecfg_state.raw_i = 0; while (parsecfg_state.raw.s[parsecfg_state.raw_i] > 0 && parsecfg_state.raw.s[parsecfg_state.raw_i] <= ' ') parsecfg_state.raw_i++; //fprintf(stderr, ">>%s\n", parsecfg_state.raw.s + parsecfg_state.raw_i); if (parsecfg_state.raw.s[parsecfg_state.raw_i] != '@') { fprintf(stderr, "%d: invalid conditional directive\n", parsecfg_state.lineno); goto failure; } parsecfg_state.raw_i++; while (parsecfg_state.raw.s[parsecfg_state.raw_i] > 0 && parsecfg_state.raw.s[parsecfg_state.raw_i] <= ' ') parsecfg_state.raw_i++; XALLOCA(cmd, parsecfg_state.raw.u + 1); p = cmd; while (isalnum(parsecfg_state.raw.s[parsecfg_state.raw_i]) || parsecfg_state.raw.s[parsecfg_state.raw_i] == '_') *p++ = parsecfg_state.raw.s[parsecfg_state.raw_i++]; *p = 0; if (!strcmp(cmd, "if")) { XCALLOC(new_item, 1); new_item->next = parsecfg_state.cond_stack; parsecfg_state.cond_stack = new_item; if (parse_expr(1, &val) < 0) goto failure; //print_value(&val); if (!parsecfg_state.output_enabled) { parsecfg_state.cond_stack->was_true = 1; parsecfg_state.output_enabled = parsecfg_state.cond_stack->output_enabled = 0; } else if (convert_to_bool(&val)) { parsecfg_state.cond_stack->was_true = 1; parsecfg_state.output_enabled = parsecfg_state.cond_stack->output_enabled = 1; } else { parsecfg_state.output_enabled = parsecfg_state.cond_stack->output_enabled = 0; } free_value(&val); } else if (!strcmp(cmd, "elif")) { if (!parsecfg_state.cond_stack) { fprintf(stderr, "%d: dangling elif\n", parsecfg_state.lineno); goto failure; } if (parsecfg_state.cond_stack->was_else) { fprintf(stderr, "%d: elif after else\n", parsecfg_state.lineno); goto failure; } if (parse_expr(1, &val) < 0) goto failure; if (!parsecfg_state.cond_stack->was_true && convert_to_bool(&val)) { parsecfg_state.cond_stack->was_true = 1; parsecfg_state.output_enabled = parsecfg_state.cond_stack->output_enabled = 1; } else { parsecfg_state.output_enabled = parsecfg_state.cond_stack->output_enabled = 0; } free_value(&val); } else if (!strcmp(cmd, "else")) { if (!parsecfg_state.cond_stack) { fprintf(stderr, "%d: dangling else\n", parsecfg_state.lineno); goto failure; } if (parsecfg_state.cond_stack->was_else) { fprintf(stderr, "%d: else after else\n", parsecfg_state.lineno); goto failure; } while (parsecfg_state.raw.s[parsecfg_state.raw_i] > 0 && parsecfg_state.raw.s[parsecfg_state.raw_i] <= ' ') parsecfg_state.raw_i++; if (parsecfg_state.raw.s[parsecfg_state.raw_i]) { fprintf(stderr, "%d: garbage after else\n", parsecfg_state.lineno); goto failure; } parsecfg_state.cond_stack->was_else = 1; if (!parsecfg_state.cond_stack->was_true) { parsecfg_state.cond_stack->was_true = 1; parsecfg_state.output_enabled = parsecfg_state.cond_stack->output_enabled = 1; } else { parsecfg_state.output_enabled = parsecfg_state.cond_stack->output_enabled = 0; } } else if (!strcmp(cmd, "endif")) { if (!parsecfg_state.cond_stack) { fprintf(stderr, "%d: dangling endif\n", parsecfg_state.lineno); goto failure; } while (parsecfg_state.raw.s[parsecfg_state.raw_i] > 0 && parsecfg_state.raw.s[parsecfg_state.raw_i] <= ' ') parsecfg_state.raw_i++; if (parsecfg_state.raw.s[parsecfg_state.raw_i]) { fprintf(stderr, "%d: garbage after endif\n", parsecfg_state.lineno); goto failure; } new_item = parsecfg_state.cond_stack; parsecfg_state.cond_stack = parsecfg_state.cond_stack->next; if (!parsecfg_state.cond_stack) parsecfg_state.output_enabled = 1; else parsecfg_state.output_enabled = parsecfg_state.cond_stack->output_enabled; xfree(new_item); } else { fprintf(stderr, "%d: invalid conditional compilation directive\n", parsecfg_state.lineno); goto failure; } parsecfg_state.lineno++; return 0; failure: parsecfg_state.lineno++; return -1; }
void generate_daily_statistics( const struct contest_desc *cnts, const serve_state_t state, FILE *f, time_t from_time, time_t to_time, int utf8_mode) { int u_max, u_tot; int *u_ind, *u_rev; int p_max, p_tot, i, j; int *p_ind, *p_rev; int row_sz, row_sh; unsigned char *solved = 0; int r_tot, u, p, idx, max_u_total; const struct run_entry *runs, *rcur; int *u_total = 0, *u_ok = 0, *u_failed = 0, *u_afterok = 0, *u_errors = 0; int *u_trans = 0, *u_cf = 0, *u_ac = 0, *u_ign = 0, *u_disq = 0, *u_pend = 0; int *u_ce = 0, *u_sort = 0; int *l_total = 0, *l_ok = 0, *l_ce = 0; int *p_total = 0, *p_ok = 0; unsigned char *u_reg = 0; struct teamdb_export uinfo; int *sort_num, *sort_idx; int total_empty = 0; int total_errors = 0; int total_status[128]; int total_pseudo = 0; int total_afterok = 0; int total_trans = 0; int total_ok = 0; int total_failed = 0; int total_cf = 0; int total_ac = 0; int total_ign = 0; int total_disq = 0; int total_pend = 0; int total_ce = 0; int total_reg = 0; int total_runs = 0; int w, y; unsigned char *login, *name, probname[256], langname[256]; int clar_total = 0, clar_total_today = 0, clar_from_judges = 0; int clar_to_judges = 0; time_t clar_time; struct clar_entry_v2 clar; /* u_tot - total number of teams in index array * u_max - maximal possible number of teams * u_ind[0..u_tot-1] - index array: team_idx -> team_id * u_rev[0..u_max-1] - reverse index: team_id -> team_idx */ if (state->global->disable_user_database > 0) { u_max = run_get_max_user_id(state->runlog_state) + 1; } else { u_max = teamdb_get_max_team_id(state->teamdb_state) + 1; } XALLOCAZ(u_ind, u_max); XALLOCAZ(u_rev, u_max); XALLOCAZ(u_reg, u_max); for (i = 1, u_tot = 0; i < u_max; i++) { u_rev[i] = -1; if (teamdb_lookup(state->teamdb_state, i) && teamdb_export_team(state->teamdb_state, i, &uinfo) >= 0) { if (is_registered_today(cnts, uinfo.user, from_time, to_time)) { total_reg++; u_reg[u_tot] = 1; } u_rev[i] = u_tot; u_ind[u_tot++] = i; } } /* p_tot - total number of problems in index array * p_max - maximal possible number of problems * p_ind[0..p_tot-1] - index array: prob_idx -> prob_id * p_rev[0..p_max-1] - reverse index: prob_id -> prob_idx */ p_max = state->max_prob + 1; XALLOCAZ(p_ind, p_max); XALLOCAZ(p_rev, p_max); for (i = 1, p_tot = 0; i < p_max; i++) { p_rev[i] = -1; if (state->probs[i]) { p_rev[i] = p_tot; p_ind[p_tot++] = i; } } r_tot = run_get_total(state->runlog_state); runs = run_get_entries_ptr(state->runlog_state); if (!u_tot || !p_tot || !r_tot) return; /* calculate the power of 2 not less than p_tot */ for (row_sz = 1, row_sh = 0; row_sz < p_tot; row_sz <<= 1, row_sh++); /* all two-dimensional arrays will have rows of size row_sz */ XCALLOC(solved, row_sz * u_tot); memset(total_status, 0, sizeof(total_status)); XALLOCAZ(u_total, u_tot); XALLOCAZ(u_ok, u_tot); XALLOCAZ(u_failed, u_tot); XALLOCAZ(u_afterok, u_tot); XALLOCAZ(u_errors, u_tot); XALLOCAZ(u_trans, u_tot); XALLOCAZ(u_cf, u_tot); XALLOCAZ(u_ac, u_tot); XALLOCAZ(u_ign, u_tot); XALLOCAZ(u_disq, u_tot); XALLOCAZ(u_pend, u_tot); XALLOCAZ(u_ce, u_tot); XALLOCA(u_sort, u_tot); XALLOCAZ(l_total, state->max_lang + 1); XALLOCAZ(l_ok, state->max_lang + 1); XALLOCAZ(l_ce, state->max_lang + 1); XALLOCAZ(p_total, p_tot); XALLOCAZ(p_ok, p_tot); for (i = 0, rcur = runs; i < r_tot; i++, rcur++) { if (rcur->time >= to_time) break; if (rcur->time < from_time) { if (rcur->status == RUN_EMPTY) continue; if (rcur->status != RUN_OK) continue; if (rcur->user_id <= 0 || rcur->user_id >= u_max || u_rev[rcur->user_id] < 0) continue; if (rcur->prob_id <= 0 || rcur->prob_id >= p_max || p_rev[rcur->prob_id] < 0) continue; solved[(u_rev[rcur->user_id] << row_sh) + p_rev[rcur->prob_id]] = 1; continue; } // ok, collect statistics if ((rcur->status > RUN_MAX_STATUS && rcur->status < RUN_PSEUDO_FIRST) || (rcur->status>RUN_PSEUDO_LAST && rcur->status<RUN_TRANSIENT_FIRST) || (rcur->status > RUN_TRANSIENT_LAST)) { fprintf(f, "error: run %d has invalid status %d\n", i, rcur->status); total_errors++; continue; } if (rcur->status == RUN_EMPTY) { total_empty++; continue; } if (rcur->user_id <= 0 || rcur->user_id >= u_max || (u = u_rev[rcur->user_id]) < 0) { fprintf(f, "error: run %d has invalid user_id %d\n", i, rcur->user_id); total_errors++; continue; } if (rcur->status >= RUN_PSEUDO_FIRST && rcur->status <= RUN_PSEUDO_LAST) { total_status[rcur->status]++; total_pseudo++; u_total[u]++; continue; } if (rcur->prob_id <= 0 || rcur->prob_id >= p_max || (p = p_rev[rcur->prob_id]) < 0) { fprintf(f, "error: run %d has invalid prob_id %d\n", i, rcur->prob_id); total_errors++; u_errors[u]++; u_total[u]++; continue; } idx = (u << row_sh) + p; if (solved[idx]) { u_afterok[u]++; u_total[u]++; total_afterok++; continue; } if (rcur->lang_id) { if (rcur->lang_id < 0 || rcur->lang_id > state->max_lang || !state->langs[rcur->lang_id]) { fprintf(f, "error: run %d has invalid lang_id %d\n", i, rcur->lang_id); total_errors++; u_errors[u]++; u_total[u]++; continue; } } if (rcur->status >= RUN_TRANSIENT_FIRST && rcur->status <= RUN_TRANSIENT_LAST) { total_trans++; u_total[u]++; u_trans[u]++; continue; } switch (rcur->status) { case RUN_OK: total_ok++; u_ok[u]++; u_total[u]++; l_total[rcur->lang_id]++; l_ok[rcur->lang_id]++; p_total[p]++; p_ok[p]++; solved[idx] = 1; break; case RUN_COMPILE_ERR: case RUN_STYLE_ERR: case RUN_REJECTED: total_ce++; u_ce[u]++; u_total[u]++; l_total[rcur->lang_id]++; l_ce[rcur->lang_id]++; p_total[p]++; break; case RUN_RUN_TIME_ERR: case RUN_TIME_LIMIT_ERR: case RUN_WALL_TIME_LIMIT_ERR: case RUN_PRESENTATION_ERR: case RUN_WRONG_ANSWER_ERR: case RUN_MEM_LIMIT_ERR: case RUN_SECURITY_ERR: case RUN_PARTIAL: total_failed++; u_failed[u]++; u_total[u]++; l_total[rcur->lang_id]++; p_total[p]++; total_status[rcur->status]++; break; case RUN_CHECK_FAILED: total_cf++; u_cf[u]++; u_total[u]++; break; case RUN_ACCEPTED: case RUN_PENDING_REVIEW: total_ac++; u_ac[u]++; u_total[u]++; break; case RUN_IGNORED: total_ign++; u_ign[u]++; u_total[u]++; break; case RUN_DISQUALIFIED: total_disq++; u_disq[u]++; u_total[u]++; break; case RUN_PENDING: total_pend++; u_pend[u]++; u_total[u]++; break; default: abort(); } } clar_total = clar_get_total(state->clarlog_state); for (i = 0; i < clar_total; i++) { if (clar_get_record(state->clarlog_state, i, &clar) < 0) continue; if (clar.id < 0) continue; clar_time = clar.time; if (clar_time >= to_time) break; if (clar_time < from_time) continue; clar_total_today++; if (!clar.from) clar_from_judges++; else clar_to_judges++; } if (total_reg > 0) { fprintf(f, "New users registered: %d\n", total_reg); for (i = 0; i < u_tot; i++) { if (!u_reg[i]) continue; u = u_ind[i]; if (!(login = teamdb_get_login(state->teamdb_state, u))) login = ""; if (!(name = teamdb_get_name(state->teamdb_state, u))) name = ""; w = 30; y = 0; if (utf8_mode) w = utf8_cnt(name, w, &y); fprintf(f, " %-6d %-15.15s %-*.*s\n", u, login, w + y, w, name); } fprintf(f, "\n"); } total_runs = total_empty + total_pseudo + total_afterok + total_trans + total_ok + total_failed + total_cf + total_ac + total_ign + total_disq + total_pend + total_ce; if (total_runs > 0) fprintf(f, "Total new runs: %d\n", total_runs); if (total_empty > 0) fprintf(f, " Empty (cleared) records: %d\n", total_empty); if (total_pseudo > 0) fprintf(f, " Virtual records: %d\n", total_pseudo); if (total_trans > 0) fprintf(f, " Currently being tested: %d\n", total_trans); if (total_afterok > 0) fprintf(f, " Submits after success: %d\n", total_afterok); if (total_ok > 0) fprintf(f, " Successful submits: %d\n", total_ok); if (total_failed > 0) fprintf(f, " Unsuccessful submits: %d\n", total_failed); if (total_status[RUN_RUN_TIME_ERR] > 0) fprintf(f, " Run-time error: %d\n", total_status[RUN_RUN_TIME_ERR]); if (total_status[RUN_TIME_LIMIT_ERR] > 0) fprintf(f, " Time-limit exceeded: %d\n", total_status[RUN_TIME_LIMIT_ERR]); if (total_status[RUN_PRESENTATION_ERR] > 0) fprintf(f, " Presentation error: %d\n", total_status[RUN_PRESENTATION_ERR]); if (total_status[RUN_WRONG_ANSWER_ERR] > 0) fprintf(f, " Wrong answer: %d\n", total_status[RUN_WRONG_ANSWER_ERR]); if (total_status[RUN_MEM_LIMIT_ERR] > 0) fprintf(f, " Memory limit exceeded: %d\n", total_status[RUN_MEM_LIMIT_ERR]); if (total_status[RUN_SECURITY_ERR] > 0) fprintf(f, " Security violation: %d\n", total_status[RUN_SECURITY_ERR]); if (total_status[RUN_WALL_TIME_LIMIT_ERR] > 0) fprintf(f, " Wall time-limit exceeded:%d\n", total_status[RUN_WALL_TIME_LIMIT_ERR]); if (total_status[RUN_PARTIAL] > 0) fprintf(f, " Partial solution: %d\n", total_status[RUN_PARTIAL]); if (total_ce > 0) fprintf(f, " Compilation error: %d\n", total_ce); if (total_cf > 0) fprintf(f, " Checking failed: %d\n", total_cf); if (total_ac > 0) fprintf(f, " Accepted for testing: %d\n", total_ac); if (total_ign > 0) fprintf(f, " Ignored: %d\n", total_ign); if (total_disq > 0) fprintf(f, " Disqualified: %d\n", total_disq); if (total_pend > 0) fprintf(f, " Pending check: %d\n", total_pend); if (total_runs > 0) fprintf(f, "\n"); if (total_runs > 0) { fprintf(f, "%-40.40s %-7.7s %-7.7s\n", "Problem", "Total", "Success"); for (i = 0; i < p_tot; i++) { p = p_ind[i]; snprintf(probname, sizeof(probname), "%s: %s", state->probs[p]->short_name, state->probs[p]->long_name); w = 40; y = 0; if (utf8_mode) w = utf8_cnt(probname, w, &y); fprintf(f, "%-*.*s %-7d %-7d\n", w + y, w, probname, p_total[i], p_ok[i]); } fprintf(f, "\n"); } if (total_runs > 0) { fprintf(f, "%-40.40s %-7.7s %-7.7s %-7.7s\n", "Language", "Total", "CE", "Success"); if (l_total[0] > 0) { fprintf(f, "%-40.40s %-7d %-7d %-7d\n", "N/A (0)", l_total[0], l_ce[0], l_ok[0]); } for (i = 1; i <= state->max_lang; i++) { if (!state->langs[i]) continue; snprintf(langname, sizeof(langname), "%s - %s", state->langs[i]->short_name, state->langs[i]->long_name); w = 40; y = 0; if (utf8_mode) w = utf8_cnt(langname, w, &y); fprintf(f, "%-*.*s %-7d %-7d %-7d\n", w + y, w, langname, l_total[i], l_ce[i], l_ok[i]); } fprintf(f, "\n"); } // sort users by decreasing order of user's submit max_u_total = 0; for (i = 0; i < u_tot; i++) if (u_total[i] > max_u_total) max_u_total = u_total[i]; XALLOCAZ(sort_num, max_u_total + 1); XALLOCAZ(sort_idx, max_u_total + 1); for (i = 0; i < u_tot; i++) sort_num[u_total[i]]++; sort_idx[max_u_total] = 0; for (i = max_u_total - 1; i >= 0; i--) sort_idx[i] = sort_idx[i + 1] + sort_num[i + 1]; for (i = 0; i < u_tot; i++) u_sort[sort_idx[u_total[i]]++] = i; if (total_runs > 0) { fprintf(f, "%-7.7s %-24.24s %-7.7s %-7.7s %s\n", "Id", "User", "Total", "Success", "Other"); for (i = 0; i < u_tot; i++) { j = u_sort[i]; if (!u_total[j]) break; u = u_ind[j]; name = teamdb_get_name(state->teamdb_state, u); if (!name || !*name) name = teamdb_get_login(state->teamdb_state, u); if (!name) name = ""; w = 24; y = 0; if (utf8_mode) w = utf8_cnt(name, w, &y); fprintf(f, "%-7d %-*.*s %-7d %-7d %-7d %d/%d/%d %d/%d/%d/%d/%d/%d\n", u, w + y, w, name, u_total[j], u_ok[j], u_failed[j], u_cf[j], u_ce[j], u_ign[j], u_afterok[j], u_errors[j], u_trans[j], u_ac[j], u_disq[j], u_pend[j]); } fprintf(f, "\n"); } if (clar_total_today > 0) { fprintf(f, "Clarification requests: %d\n" "To judges: %d\n" "From judges: %d\n\n", clar_total_today, clar_to_judges, clar_from_judges); } xfree(solved); }