struct regexp * regexp_minus(struct info *info, struct regexp *r1, struct regexp *r2) { struct regexp *result = NULL; struct fa *fa = NULL, *fa1 = NULL, *fa2 = NULL; int r; char *s = NULL; size_t s_len; fa1 = regexp_to_fa(r1); ERR_BAIL(r1->info); fa2 = regexp_to_fa(r2); ERR_BAIL(r2->info); fa = fa_minus(fa1, fa2); if (fa == NULL) goto error; r = fa_as_regexp(fa, &s, &s_len); if (r < 0) goto error; if (s == NULL) { /* FA is the empty set, which we can't represent as a regexp */ goto error; } if (regexp_c_locale(&s, NULL) < 0) goto error; result = make_regexp(info, s, fa_is_nocase(fa)); s = NULL; done: fa_free(fa); fa_free(fa1); fa_free(fa2); free(s); return result; error: unref(result, regexp); goto done; }
struct regexp * regexp_union_n(struct info *info, int n, struct regexp **r) { size_t len = 0; char *pat = NULL, *p, *expanded = NULL; int nnocase = 0, npresent = 0; int ret; for (int i=0; i < n; i++) if (r[i] != NULL) { len += strlen(r[i]->pattern->str) + strlen("()|"); npresent += 1; if (r[i]->nocase) nnocase += 1; } bool mixedcase = nnocase > 0 && nnocase < npresent; if (len == 0) return NULL; if (ALLOC_N(pat, len) < 0) return NULL; p = pat; int added = 0; for (int i=0; i < n; i++) { if (r[i] == NULL) continue; if (added > 0) *p++ = '|'; *p++ = '('; if (mixedcase && r[i]->nocase) { expanded = regexp_expand_nocase(r[i]); ERR_BAIL(r[i]->info); len += strlen(expanded) - strlen(r[i]->pattern->str); ret = REALLOC_N(pat, len); ERR_NOMEM(ret < 0, info); p = pat + strlen(pat); p = stpcpy(p, expanded); FREE(expanded); } else { p = stpcpy(p, r[i]->pattern->str); } *p++ = ')'; added += 1; } *p = '\0'; return make_regexp(info, pat, nnocase == npresent); error: FREE(expanded); FREE(pat); return NULL; }
struct regexp * regexp_concat_n(struct info *info, int n, struct regexp **r) { size_t len = 0; char *pat = NULL, *p, *expanded = NULL; int nnocase = 0, npresent = 0; for (int i=0; i < n; i++) if (r[i] != NULL) { len += strlen(r[i]->pattern->str) + strlen("()"); npresent += 1; if (r[i]->nocase) nnocase += 1; } bool mixedcase = nnocase > 0 && nnocase < npresent; if (len == 0) return NULL; len += 1; if (ALLOC_N(pat, len) < 0) return NULL; p = pat; for (int i=0; i < n; i++) { if (r[i] == NULL) continue; *p++ = '('; if (mixedcase && r[i]->nocase) { p = append_expanded(r[i], &pat, p, &len); ERR_BAIL(r[i]->info); } else { p = stpcpy(p, r[i]->pattern->str); } *p++ = ')'; } *p = '\0'; return make_regexp(info, pat, nnocase == npresent); error: FREE(expanded); FREE(pat); return NULL; }
static char *append_expanded(struct regexp *r, char **pat, char *p, size_t *len) { char *expanded = NULL; size_t ofs = p - *pat; int ret; expanded = regexp_expand_nocase(r); ERR_BAIL(r->info); *len += strlen(expanded) - strlen(r->pattern->str); ret = REALLOC_N(*pat, *len); ERR_NOMEM(ret < 0, r->info); p = stpcpy(*pat + ofs, expanded); error: FREE(expanded); return p; }
/** * Run a command without using the shell. * * return 0 if the command run and exited with 0 status; Otherwise * return -1 * */ int run_program(struct netcf *ncf, const char *const *argv, char **output) { pid_t childpid = -1; int exitstatus, waitret; char *argv_str; int ret = -1; char errbuf[128]; char *outtext = NULL; int outfd = -1; FILE *outfile = NULL; size_t outlen; if (!output) output = &outtext; argv_str = argv_to_string(argv); ERR_NOMEM(argv_str == NULL, ncf); exec_program(ncf, argv, argv_str, &childpid, &outfd); ERR_BAIL(ncf); printf("Attempting to execute %s\n", argv_str); outfile = fdopen(outfd, "r"); ERR_THROW_STRERROR(outfile == NULL,ncf, EEXEC, "Failed to create file stream for output while executing '%s': %s", argv_str, errbuf); *output = fread_file(outfile, &outlen); ERR_THROW_STRERROR(*output == NULL, ncf, EEXEC, "Error while reading output from execution of '%s': %s", argv_str, errbuf); /* finished with the stream. Close it so the child can exit. */ fclose(outfile); outfile = NULL; while ((waitret = waitpid(childpid, &exitstatus, 0) == -1) && errno == EINTR) { /* empty loop */ } ERR_THROW_STRERROR(waitret == -1, ncf, EEXEC, "Failed waiting for completion of '%s': %s", argv_str, errbuf); ERR_THROW(!WIFEXITED(exitstatus) && WIFSIGNALED(exitstatus), ncf, EEXEC, "'%s' terminated by signal: %d", argv_str, WTERMSIG(exitstatus)); ERR_THROW(!WIFEXITED(exitstatus), ncf, EEXEC, "'%s' terminated improperly", argv_str); ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_ENOENT, ncf, EEXEC, "Running '%s' program not found", argv_str); ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_CANNOT_INVOKE, ncf, EEXEC, "Running '%s' program located but not usable", argv_str); ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_SIGMASK, ncf, EEXEC, "Running '%s' failed to reset child process signal mask", argv_str); ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_DUP2, ncf, EEXEC, "Running '%s' failed to dup2 child process stdout/stderr", argv_str); ERR_THROW(WEXITSTATUS(exitstatus) == EXIT_INVALID_IN_THIS_STATE, ncf, EINVALIDOP, "Running '%s' operation is invalid in this state", argv_str); ERR_THROW(WEXITSTATUS(exitstatus) != 0, ncf, EEXEC, "Running '%s' failed with exit code %d: %s", argv_str, WEXITSTATUS(exitstatus), *output); ret = 0; error: if (outfile) fclose(outfile); else if (outfd >= 0) close(outfd); FREE(outtext); FREE(argv_str); return ret; }