/* Create a category map with a category for each feature type in a GFF_Set. Category numbers are assigned in order of appearance of types */ CategoryMap* cm_new_from_features(GFF_Set *feats) { int i; CategoryMap *retval; Hashtable *hash; List *types; /* first scan features for all types */ hash = hsh_new(10); types = lst_new_ptr(10); for (i = 0; i < lst_size(feats->features); i++) { GFF_Feature *f = lst_get_ptr(feats->features, i); checkInterruptN(i, 10000); if (hsh_get(hash, f->feature->chars) == (void*)-1) { lst_push_ptr(types, f->feature); hsh_put_int(hash, f->feature->chars, 1); } } hsh_free(hash); /* now create a simple category map */ retval = cm_new(lst_size(types)); for (i = 0; i <= retval->ncats; i++) { String *type = i == 0 ? str_new_charstr(BACKGD_CAT_NAME) : str_dup(lst_get_ptr(types, i-1)); retval->ranges[i] = cm_new_category_range(type, i, i); } lst_free(types); return retval; }
/* Create a trivial CategoryMap, with feature types equal to category numbers (plus an optional prefix) and ranges all of size one. */ CategoryMap* cm_create_trivial(int ncats, char *feature_prefix) { int i; CategoryMap *retval = cm_new(ncats); for (i = 0; i <= ncats; i++) { String *type = str_new(STR_SHORT_LEN); if (feature_prefix != NULL) str_append_charstr(type, feature_prefix); str_append_int(type, i); retval->ranges[i] = cm_new_category_range(type, i, i); } return retval; }
CategoryMap *cm_create_copy(CategoryMap *src) { int i, has_dependencies = 0; CategoryMap *retval = cm_new(src->ncats); for (i = 0; i <= src->ncats; i++) { retval->ranges[i] = cm_category_range_create_copy(src->ranges[i]); if (retval->conditioned_on[i] != NULL) { retval->conditioned_on[i] = lst_new_int(lst_size(src->conditioned_on[i])); lst_cpy(retval->conditioned_on[i], src->conditioned_on[i]); has_dependencies = 1; } retval->labelling_precedence[i] = src->labelling_precedence[i]; retval->fill_precedence[i] = src->fill_precedence[i]; } if (has_dependencies) cm_create_unspooler(retval->ncats + 1, retval->conditioned_on); return retval; }
/* Read a CategoryMap from a file */ CategoryMap *cm_read(FILE *F) { String *line, *name; List *l; int cat, cat2, lineno, i, cm_read_error; CategoryMap *cm = NULL; CategoryRange *existing_range; static Regex *cat_range_re = NULL; static Regex *ncats_re = NULL; static Regex *fill_re = NULL; static Regex *label_re = NULL; static Regex *extend_re = NULL; int has_dependencies = 0; line = str_new(STR_SHORT_LEN); l = lst_new_ptr(3); if (cat_range_re == NULL) { cat_range_re = str_re_new("^[[:space:]]*([^[:space:]]+)[[:space:]]+([[:digit:]]+)(-([[:digit:]]+))?([[:space:]]+([[:digit:]].*))?"); ncats_re = str_re_new("^[[:space:]]*NCATS[[:space:]]*=[[:space:]]*([[:digit:]]+)"); fill_re = str_re_new("^[[:space:]]*FILL_PRECEDENCE[[:space:]]*=[[:space:]]*(.*)$"); label_re = str_re_new("^[[:space:]]*LABELLING_PRECEDENCE[[:space:]]*=[[:space:]]*(.*)$"); extend_re = str_re_new("^[[:space:]]*FEATURE_EXTEND[[:space:]]*:[[:space:]]*(.+)[[:space:]]*\\((.+)\\)$"); } lineno = 0; while ((str_readline(line, F)) != EOF) { lineno++; str_trim(line); if (str_equals_charstr(line, "")) continue; if (str_re_match(line, ncats_re, l, 1) >= 0) { /* NCATS line */ int ncats; str_as_int(lst_get_ptr(l, 1), &ncats); cm = cm_new(ncats); /* 0th category is "background" */ cm->ranges[0] = cm_new_category_range(str_new_charstr(BACKGD_CAT_NAME), 0, 0); } else if (cm == NULL || cm->ncats == 0) die("ERROR: NCATS line must appear first, and must specify a positive number of categories.\n"); else if (str_re_match(line, label_re, l, 1) >= 0) { /* LABELLING_PRECEDENCE line */ List *tmpl = lst_new_ptr(cm->ncats); int tmpi; str_split((String*)lst_get_ptr(l, 1), " ,", tmpl); for (i = 0; i < lst_size(tmpl); i++) { String *s = (String*)lst_get_ptr(tmpl, i); if (str_as_int(s, &tmpi) != 0 || tmpi < 0 || tmpi > cm->ncats) die("ERROR: bad integer in LABELLING_PRECEDENCE.\n"); cm->labelling_precedence[tmpi] = i; str_free(s); } lst_free(tmpl); } else if (str_re_match(line, fill_re, l, 1) >= 0) { /* FILL_PRECEDENCE line */ List *tmpl = lst_new_ptr(cm->ncats); int tmpi; str_split(lst_get_ptr(l, 1), " ,", tmpl); for (i = 0; i < lst_size(tmpl); i++) { String *s = lst_get_ptr(tmpl, i); if (str_as_int(s, &tmpi) != 0 || tmpi < 0 || tmpi > cm->ncats) die("ERROR: bad integer in FILL_PRECEDENCE.\n"); cm->fill_precedence[tmpi] = i; str_free(s); } lst_free(tmpl); } else if (str_re_match(line, extend_re, l, 2) >= 0) { /* FEATURE_EXTEND line */ String *target = lst_get_ptr(l, 2); List *sources = lst_new_ptr(2); str_split(lst_get_ptr(l, 1), " ,", sources); if (cm == NULL || (cat = cm_get_category(cm, target)) == 0) die("ERROR: FEATURE_EXTEND target must be a previously-defined non-background feature type.\n"); for (i = 0; i < lst_size(sources); i++) { if (cm_get_category(cm, lst_get_ptr(sources, i)) == 0) die("ERROR: FEATURE_EXTEND source list must consist of previously-defined non-background feature types.\n"); } } else { /* 'range' line */ if (str_re_match(line, cat_range_re, l, 6) < 0) die("ERROR at line %d: '%s'\n", lineno, line->chars); name = str_dup((String*)lst_get_ptr(l, 1)); str_as_int((String*)lst_get_ptr(l, 2), &cat); cat2 = cat; if (lst_get_ptr(l, 4) != NULL) str_as_int((String*)lst_get_ptr(l, 4), &cat2); if (cat < 0 || cat2 < cat || cat2 > cm->ncats) die("ERROR: Illegal category range.\n"); /* check for existing definitions of the specified category range. Either no such definition must exist, or one must exist that spans exactly the same category numbers */ existing_range = NULL; cm_read_error = 0; for (i = cat; !cm_read_error && i <= cat2; i++) { if (cm->ranges[i] != NULL && existing_range == NULL) existing_range = cm->ranges[i]; else if (cm->ranges[i] != existing_range) cm_read_error = 1; } if (existing_range != NULL && (existing_range->start_cat_no != cat || existing_range->end_cat_no != cat2)) cm_read_error = 1; if (cm_read_error) die("ERROR: Overlapping category ranges.\n"); /* either add new category range, or add new type to existing one */ if (existing_range != NULL) { lst_push_ptr(existing_range->feature_types, name); } else { CategoryRange *cr = cm_new_category_range(name, cat, cat2); for (i = cat; i <= cat2; i++) cm->ranges[i] = cr; } /* now address "conditioned_on" dependencies, if they have been specified */ if (lst_get_ptr(l, 6) != NULL) { if (existing_range != NULL) fprintf(stderr, "WARNING: ignoring 'conditioned on' list for type '%s'\n", name->chars); else { List *tmpl = lst_new_ptr(cm->ncats); int tmpi; if (cm->conditioned_on[cat] != NULL) die("ERROR cm_read: cm->conditioned_on[%i] should be NULL\n", cat); str_split((String*)lst_get_ptr(l, 6), " ,", tmpl); cm->conditioned_on[cat] = lst_new_int(lst_size(tmpl)); for (i = cat + 1; i <= cat2; i++) cm->conditioned_on[i] = cm->conditioned_on[cat]; /* all categories in range point to same "conditioned on" list */ for (i = 0; i < lst_size(tmpl); i++) { String *s = (String*)lst_get_ptr(tmpl, i); if (str_as_int(s, &tmpi) != 0 || tmpi < 0 || tmpi > cm->ncats) die("ERROR: bad integer in 'conditioned on' list for type '%s'.\n", name->chars); lst_push_int(cm->conditioned_on[cat], tmpi); str_free(s); } lst_free(tmpl); has_dependencies = 1; } } } for (i = 0; i < lst_size(l); i++) if (lst_get_ptr(l, i) != NULL) str_free((String*)lst_get_ptr(l, i)); } /* make sure every category has been specified */ for (i = 0; i <= cm->ncats; i++) if (cm->ranges[i] == 0) die("ERROR: category %d has not been specified.\n", i); /* build unspooler, if necessary */ if (has_dependencies) cm->unspooler = cm_create_unspooler(cm->ncats + 1, cm->conditioned_on); str_free(line); lst_free(l); return cm; }
/*ARGSUSED*/ static int exec_prodput( const product* prod, int argc, char** argv, const void* xprod, size_t xlen) { pid_t pid = 0; if (NULL == execMap) { execMap = cm_new(); if (NULL == execMap) { LOG_ADD0("Couldn't create child-process map for EXEC entries"); log_log(LOG_ERR); pid = -1; } } /* child-process map not allocated */ if (0 == pid) { int waitOnChild = 0; /* default is not to wait */ if (strcmp(argv[0], "-wait") == 0) { waitOnChild = 1; /* => wait for child */ argc--; argv++; } pid = ldmfork(); if (-1 == pid) { LOG_SERROR0("Couldn't fork EXEC process"); log_log(LOG_ERR); } else { if (0 == pid) { /* * Child process. * * Detach the child process from the parents process group?? * * (void) setpgid(0,0); */ const unsigned ulogOptions = ulog_get_options(); const char* ulogIdent = getulogident(); const unsigned ulogFacility = getulogfacility(); const char* ulogPath = getulogpath(); (void)signal(SIGTERM, SIG_DFL); (void)pq_close(pq); /* * It is assumed that the standard input, output, and error * streams are correctly established and should not be * modified. */ /* * Don't let the child process get any inappropriate privileges. */ endpriv(); (void) execvp(argv[0], argv); openulog(ulogIdent, ulogOptions, ulogFacility, ulogPath); LOG_SERROR1("Couldn't execute command \"%s\"", argv[0]); log_log(LOG_ERR); exit(EXIT_FAILURE); } /* child process */ else { /* * Parent process. */ (void)cm_add_argv(execMap, pid, argv); if (!waitOnChild) { udebug(" exec %s[%d]", argv[0], pid); } else { udebug(" exec -wait %s[%d]", argv[0], pid); (void)reap(pid, 0); } } } /* child-process forked */ } /* child-process map allocated */ return -1 == pid ? -1 : 1; }