Ejemplo n.º 1
0
/**
 * NAME:    os_SubstSuffix
 * PURPOSE: replace the suffix of the path with the given new suffix
 * ARGS:    path   - path of the file
 *          suffix - new suffix
 * RETURN:  new path allocated in the heap
 */
  char *
os_SubstSuffix(char const *path, char const *suffix)
{
  char *dp;
  char *sp;
  char *r;

  if (path == NULL)
    return NULL;

  sp = strrchr(path, '/');
  dp = strrchr(path, '.');

  if (dp == NULL || (sp != NULL && sp > dp))
    {
      return xstrmerge2(path, suffix);
    }

  r = xstrdup(path);
  r[dp - path] = 0;
  return xstrmerge1(r, suffix);
}
Ejemplo n.º 2
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;
}