#define _POSIX_SOURCE #include #include #include #include #include #include #include #define MAX_LINE 79 static int debug = 0; void construct_workflow(char *flow_spec) { if (strlen(flow_spec) == 1) { char local_flow[] = "./ "; if (! isalpha(flow_spec[0])) { fprintf(stderr, "Invalid component: %c\n", flow_spec[0]); exit(1); } local_flow[2] = flow_spec[0]; execlp(local_flow, local_flow, NULL); } else { char F[MAX_LINE], G[MAX_LINE]; int i, pivot, paren_depth; char op; int F_in_pipe[2], F_out_pipe[2]; int G_in_pipe[2], G_out_pipe[2]; FILE *F_in, *F_out, *G_in, *G_out; unsigned int x; unsigned int F_x, G_x, result; F[0] = G[0] = '\0'; pivot = 0; paren_depth = 0; /* we omit 1 char at each end, assumed to be parentheses */ for (i = 1; i < strlen(flow_spec) - 1; ++i) { switch (flow_spec[i]) { case '+': case '*': if (paren_depth == 0) pivot = i; break; case '(': ++paren_depth; break; case ')': --paren_depth; break; } if (pivot) break; else F[i-1] = flow_spec[i]; } F[i-1] = '\0'; /* terminate F */ op = flow_spec[pivot]; strcpy(G, &flow_spec[pivot+1]); G[strlen(G)-1] = '\0'; /* chop last char ')' of G */ if ((op != '+' && op != '*') || ((strlen(F) - 1) % 4 != 0) || ((strlen(G) - 1) % 4 != 0)) { fprintf(stderr, "Broken spec: '(%s|%c|%s)'\n", F, op, G); exit(1); } if (debug) fprintf(stderr, "Divided spec; F='%s',op='%c',G='%s'\n", F, op, G); pipe(F_in_pipe); pipe(F_out_pipe); pipe(G_in_pipe); pipe(G_out_pipe); if (fork() != 0) { if (fork() != 0) { /* parent */ close(F_in_pipe[0]); close(F_out_pipe[1]); close(G_in_pipe[0]); close(G_out_pipe[1]); F_in = fdopen(F_in_pipe[1], "w"); F_out = fdopen(F_out_pipe[0], "r"); G_in = fdopen(G_in_pipe[1], "w"); G_out = fdopen(G_out_pipe[0], "r"); while (fscanf(stdin, "%u", &x) != EOF) { fprintf(F_in, "%u\n", x); fprintf(G_in, "%u\n", x); fflush(F_in); fflush(G_in); fscanf(F_out, "%u", &F_x); fscanf(G_out, "%u", &G_x); if (op == '+') result = F_x + G_x; else if (op == '*') result = F_x * G_x; fprintf(stdout, "%u\n", result); fflush(stdout); if (debug) fprintf(stderr, "Spec '%s' forwarded %u, received back %u and %u, and returned %u\n", flow_spec, x, F_x, G_x, result); } fclose(F_in); fclose(F_out); fclose(G_in); fclose(G_out); wait(NULL); wait(NULL); exit(0); } else { /* child handling workflow F */ close(0); dup(F_in_pipe[0]); close(1); dup(F_out_pipe[1]); close(F_in_pipe[0]); close(F_in_pipe[1]); close(F_out_pipe[0]); close(F_out_pipe[1]); close(G_in_pipe[0]); close(G_in_pipe[1]); close(G_out_pipe[0]); close(G_out_pipe[1]); construct_workflow(F); } } else { /* child handling workflow G */ close(0); dup(G_in_pipe[0]); close(1); dup(G_out_pipe[1]); close(F_in_pipe[0]); close(F_in_pipe[1]); close(F_out_pipe[0]); close(F_out_pipe[1]); close(G_in_pipe[0]); close(G_in_pipe[1]); close(G_out_pipe[0]); close(G_out_pipe[1]); construct_workflow(G); } } } int main(int argc, char *argv[]) { char *workflow_spec; if (argc > 1) debug = 1; setvbuf(stdin, NULL, _IONBF, 0); workflow_spec = malloc(sizeof(char) * MAX_LINE); fgets(workflow_spec, MAX_LINE, stdin); /* chop off trailing newline */ workflow_spec[strlen(workflow_spec) - 1] = '\0'; if (debug) fprintf(stderr, "Initial spec='%s'\n", workflow_spec); construct_workflow(workflow_spec); return 0; }