Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
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);
}