/* * R S E N T * * Generates random text messages. From James Gimpel, * "Algorithms in SNOBOL4". Calling sequence: * * rsent(text, rules, outfun, fildes) * char *text; -- generate from this text * RS_RULE *rules; -- compiled rule structure * int (*outfun)(); -- output function * FILE *fildes; -- file descriptor for outfun() * * The text line is copied to the output file, with commands expanded * using the rule vector. The rules are built and tested by rsmake.c. * * outfun() is defined: * * outfun(words, fildes) * char *words; -- a string to output * FILE *fildes; -- the file to output to * * Note: * outfun(NULL, fildes) -- flush partial by writing * -- a newline to fildes. */ #include #define EOS '\0' #define EOL '\n' #define FALSE 0 #define TRUE 1 typedef struct rule { char *r_name; /* Rule name */ int r_weightsum; /* Sum of all weights */ char **r_term; /* Rule terms */ } RS_RULE; rsent(text, rules, outfun, fildes) char *text; /* generate from this text */ RS_RULE *rules; /* compiled rule structure */ int (*outfun)(); /* output function */ FILE *fildes; /* file descriptor for outfun() */ /* * Generate text from the indicated pattern - recursive. */ { register char *start; /* Start of current stuff */ register char *end; /* End of current stuff */ register char *tp; /* Random text pointer */ RS_RULE *rp; /* Rule pointer */ short weight; /* Weight for randomness */ char **termp; /* Rule term pointer */ char *workp; /* Temp buffer pointer */ extern char *malloc(); /* Buffer allocator */ #ifndef nomacarg /* * Decus does this with a subroutine. */ #define irand(max) (((((short) rand()) & 32767)*max)/32768) #endif for (start = text; *start != EOS;) { /* * Look for in input string. */ end = (start == text) ? start : start + 1; while (*end != EOS && *end != '<') end++; /* * Output start .. end-1 (even if null string) */ if (end > start && (workp = malloc((end - start) + 1)) != NULL) { for (tp = workp; start < end;) { *tp++ = *start++; } *tp = EOS; (*outfun)(workp, fildes); free(workp); } if (*end++ == EOS) break; /* All done */ /* * (else scan stopped at '<'. Output the */ for ((rp = rules); (tp = rp->r_name) != NULL; rp++) { /* * Look for the in the rule name table */ for (start = end; *tp != EOS && *start == *tp;) { start++; tp++; } if (*tp == EOS && *start == '>') { /* Found a rule */ weight = irand(rp->r_weightsum); for (termp = rp->r_term; *termp != NULL; *termp++) { if ((weight -= (termp[0][0] & 0377)) < 0) break; } if (termp == NULL) { (*outfun)("\n(bug, weight messup in \"", fildes); (*outfun)(rp->r_name, fildes); (*outfun)("\".)\n", fildes); } else rsent(&termp[0][1], rules, outfun, fildes); break; /* Exit rule search */ } } if (tp == NULL) { /* * No match for this rule. It was a real '<'. */ (*outfun)("<", fildes); start = end; /* start at "foo>" */ } else start++; /* start after '>' */ } }