|
|
1.1 root 1: /*
2: * Facilitate entry of references
3: */
4:
5: #include <stdio.h>
6: #include <signal.h>
7: #include <sys/types.h>
8: #include <sys/stat.h>
9:
10: #define TEMPLATE "/usr/frodo/lib/refer/template"
11: #define REFER "refer.out"
12: #define TMPREF "/tmp/referXXXXXX"
13:
14: #ifdef PREFER
15: #define TYPE "%type"
16: #endif /* PREFER */
17:
18: #define TRUE (1)
19: #define FALSE (0)
20:
21: #define EDITOR "EDITOR"
22: #define VISUAL "VISUAL"
23:
24: struct ref {
25: struct ref *r_next; /* next reference node */
26: char *r_prompt; /* prompt for reference */
27: struct att *r_att; /* attributes */
28: };
29:
30: struct att {
31: struct att *a_next; /* next attribute node */
32: char a_flag; /* prompt flag */
33: char *a_prompt; /* prompt for attribute */
34: char *a_def; /* default value for attribute */
35: char *a_refer; /* refer string to output */
36: char *a_mcont; /* middle continue string to output */
37: char *a_econt; /* end continue string to output */
38: };
39:
40: char
41: *getenv(),
42: *malloc(),
43: *mktemp(),
44: *strchr(),
45: *strtok(),
46: *tmpref
47: ;
48:
49: int cleanup();
50:
51: FILE
52: *tmpopen(),
53: *tmp,
54: *refer
55: ;
56:
57: void
58: fixrefer(),
59: edit()
60: ;
61:
62: struct ref
63: *ref,
64: *sr
65: ;
66:
67: main(argc, argv)
68: int argc;
69: char *argv[];
70: {
71: register char
72: *tempname,
73: *refname
74: ;
75:
76: signal(SIGINT, cleanup);
77: signal(SIGQUIT, cleanup);
78:
79: tempname = refname = NULL;
80: while (--argc) {
81: if (!strcmp("-o", *++argv)) {
82: refname = *++argv;
83: --argc;
84: } else
85: tempname = *argv;
86: }
87: readtemplate(tempname ? tempname : TEMPLATE);
88:
89: if ((refer = fopen(refname ? refname : REFER, "a")) == NULL)
90: errexit(1, "Can't open reference file, %s\n", REFER);
91:
92: doreferences();
93: }
94:
95: /*
96: * Process all user input.
97: */
98: doreferences()
99: {
100: int cont;
101: struct ref
102: *rr,
103: *r
104: ;
105: struct att *a;
106: char buf[BUFSIZ];
107: register char
108: *p,
109: *bufp
110: ;
111: char comm[80];
112:
113: tmpref = mktemp(TMPREF);
114: sr = NULL;
115: for (;;) {
116: sprintf(comm, "Reference type [%s] ", ref->r_prompt);
117: if (getln(comm, buf, sizeof(buf)) == NULL)
118: cleanup();
119:
120: if ((p = strchr(&buf[0], '\n')) != NULL)
121: *p = '\0';
122:
123: if (!strlen(&buf[0]))
124: strcpy(&buf[0], ref->r_prompt);
125:
126: switch (match(&rr, buf)) {
127: case 0:
128: printf("Legal reference types are:\n");
129: for (r = ref; r; r = r->r_next)
130: printf("%s\n", r->r_prompt);
131: continue;
132:
133: case 1:
134: r = rr;
135: break;
136:
137: default: /* handled in match() */
138: continue;
139: }
140:
141: if (!strcmp(r->r_prompt, "quit"))
142: cleanup();
143:
144: fixrefer();
145:
146: if (!strcmp(r->r_prompt, "help")) {
147: help();
148: continue;
149: }
150:
151: printf("referencing a %s\n", r->r_prompt);
152: sr = r;
153: if ((tmp = fopen(tmpref, "w")) == NULL)
154: errexit(1, "Can't open %s\n", tmpref);
155:
156: for (a = r->r_att; a; a = a->a_next) {
157: if (a->a_flag == '!')
158: continue;
159: do {
160: do {
161: if (a->a_def[0])
162: sprintf(comm, "%s [%s]: ",
163: a->a_prompt, a->a_def);
164: else
165: sprintf(comm, "%s: ", a->a_prompt);
166: if (getln(comm, buf, sizeof(buf)) == NULL)
167: cleanup();
168:
169: p = strchr(buf, '\n');
170: *p = '\0';
171:
172: if (a->a_flag == '\0' && !strlen(buf)
173: && !a->a_def[0])
174: printf("The %s field is not optional\n",
175: a->a_prompt);
176: else if (a->a_def[0])
177: break;
178: } while (a->a_flag == '\0' && !strlen(buf));
179:
180: if ((cont = strlen(buf)) != 0 && buf[strlen(buf) - 1] == '&')
181: buf[strlen(buf) - 1] = '\0';
182: else
183: cont = 0;
184:
185: bufp = buf;
186: while (*bufp == ' ' || *bufp == '\t')
187: ++bufp;
188: if (strlen(buf))
189: fprintf(tmp, "%s: %s\n", a->a_prompt, bufp);
190: else
191: fprintf(tmp, "%s: %s\n", a->a_prompt, a->a_def);
192: fflush(tmp);
193: } while (cont != 0);
194: fflush(tmp);
195: }
196: fprintf(tmp, "\n");
197: fclose(tmp);
198: }
199: }
200:
201: /*
202: * Print out all attributes for a given reference; ``?'' for all.
203: */
204: help()
205: {
206: register struct att *a;
207: char helpref[BUFSIZ];
208: struct ref *r;
209:
210: printf("which reference type: ");
211: fgets(helpref, sizeof(helpref), stdin);
212: helpref[strlen(&helpref[0]) - 1] = '\0';
213: switch (match(&r, helpref)) {
214: case 0:
215: if (!strcmp(helpref, "?")) {
216: for (r = ref; r; r = r->r_next) {
217: printf("%s:\n", r->r_prompt);
218: for (a = r->r_att; a; a = a->a_next)
219: printf("\t%s\n", a->a_prompt);
220: }
221: } else
222: printf("No matches for %s\n", helpref);
223: break;
224:
225: case 1:
226: printf("Attributes for `%s':\n", r->r_prompt);
227: for (a = r->r_att; a; a = a->a_next)
228: printf("\t%s\n", a->a_prompt);
229: break;
230: }
231: }
232:
233: /*
234: * Read in references from template file
235: */
236: readtemplate(file)
237: char *file;
238: {
239: FILE *template;
240: register char
241: *p,
242: *pp
243: ;
244: register struct att *a = NULL;
245: char buf[BUFSIZ];
246: struct ref *r = NULL;
247:
248: template = tmpopen(file);
249: while (fgets(&buf[0], sizeof(buf), template) != NULL) {
250: if ((p = strchr(&buf[0], '\n')) != NULL)
251: *p = '\0';
252:
253: switch (buf[0]) {
254: case ':':
255: continue;
256:
257: case '\t':
258: if (r == NULL)
259: errexit(1, "Attribute without reference active\n");
260:
261: if (a == NULL) {
262: if ((a = r->r_att =
263: (struct att *)malloc((unsigned)sizeof(struct att)))
264: == NULL)
265: errexit(1, "Out of memory for attributes\n");
266: } else if ((a = a->a_next =
267: (struct att *)malloc((unsigned)sizeof(struct att))) == NULL)
268: errexit(1, "Out of memory for attributes\n");
269: p = &buf[1];
270:
271: switch (*p) {
272: case '?':
273: case '-':
274: case '!':
275: a->a_flag = *p++;
276: break;
277:
278: default:
279: a->a_flag = '\0';
280: }
281:
282: if ((p = strtok(p, "\n\t")) == NULL)
283: errexit(1, "Attribute without prompt\n");
284:
285: if ((a->a_prompt = malloc((unsigned)strlen(p) + 1)) == NULL)
286: errexit(1, "Out of memory for attribute prompt\n");
287: strcpy(a->a_prompt, p);
288: if ((pp = strchr(a->a_prompt, '[')) != NULL) {
289: *pp = '\0';
290: while (a->a_prompt[strlen(a->a_prompt) - 1] == ' ')
291: a->a_prompt[strlen(a->a_prompt) - 1] = '\0';
292: if ((a->a_def = malloc((unsigned)strlen(pp + 1) + 1))
293: == NULL)
294: errexit(1, "Out of memory for attribute default\n");
295: strcpy(a->a_def, pp + 1);
296: if ((pp = strchr(a->a_def, ']')) == NULL)
297: errexit(1, "Unmatched []\n");
298: *pp = '\0';
299: } else
300: a->a_def = "";
301:
302: if ((p = strtok(NULL, "\t\n")) == NULL)
303: errexit(1, "Attribute without refer\n");
304:
305: if ((a->a_refer = malloc((unsigned)strlen(p) + 1)) == NULL)
306: errexit(1, "Out of memory for attribute refer\n");
307:
308: strcpy(a->a_refer, p);
309:
310: a->a_next = NULL;
311:
312: if ((p = strtok(NULL, "\n\t")) == NULL || !strcmp(p, "NULL"))
313: a->a_mcont = "";
314: else {
315: if ((a->a_mcont = malloc((unsigned)strlen(p) + 1))
316: == NULL)
317: errexit(1, "Out of memory for attribute continue\n");
318: strcpy(a->a_mcont, p);
319: }
320:
321: if ((p = strtok(NULL, "\n\t")) == NULL || !strcmp(p, "NULL"))
322: a->a_econt = "";
323: else {
324: if ((a->a_econt = malloc((unsigned)strlen(p) + 1))
325: == NULL)
326: errexit(1, "Out of memory for attribute continue\n");
327: strcpy(a->a_econt, p);
328: }
329:
330: break;
331:
332: default:
333: addref(&r, buf);
334: a = NULL;
335: }
336: }
337: fclose(template);
338:
339: addref(&r, "help");
340: addref(&r, "quit");
341: r->r_next = NULL;
342: }
343:
344: /*
345: * Add a reference with prompt.
346: */
347: addref(r, prompt)
348: register struct ref **r;
349: char *prompt;
350: {
351: if (ref == NULL) {
352: if ((*r = ref = (struct ref *)malloc((unsigned)sizeof(struct ref)))
353: == NULL)
354: errexit(1, "Out of memory for reference.\n");
355: } else if ((*r = (*r)->r_next = (struct ref *)malloc((unsigned)sizeof(struct ref)))
356: == NULL)
357: errexit(1, "Out of memory for references\n");
358:
359: if (((*r)->r_prompt = malloc((unsigned)strlen(prompt) + 1)) == NULL)
360: errexit(1, "Out of memory for reference prompt\n");
361: strcpy((*r)->r_prompt, prompt);
362: (*r)->r_next = NULL;
363: (*r)->r_att = NULL;
364: }
365:
366: /*
367: * Get a line to process; if ~e or ~v call editors.
368: */
369: getln(msg, str, sz)
370: register char *msg, *str;
371: int sz;
372: {
373: for (;;) {
374: printf(msg);
375: if (fgets(str, sz, stdin) == NULL)
376: return(NULL);
377:
378: if (!strcmp(str, "~e\n"))
379: edit(EDITOR);
380: else if (!strcmp(str, "~v\n"))
381: edit(VISUAL);
382: else
383: return(1);
384: }
385: }
386:
387: char
388: editor[80],
389: veditor[80]
390: ;
391:
392: /*
393: * Call one of the editors on the text entered so far.
394: */
395: void
396: edit(which)
397: char *which;
398: {
399: char command[100];
400:
401: if (!editor[0])
402: open_ed(editor, EDITOR);
403: if (!veditor[0])
404: open_ed(veditor, VISUAL);
405:
406: if (tmp)
407: fclose(tmp);
408: else {
409: printf("There is no file yet.\n");
410: return;
411: }
412:
413: sprintf(command, "%s %s", (!strcmp(which, EDITOR) ? editor : veditor),
414: tmpref);
415: system(command);
416: tmp = fopen(tmpref, "a+");
417: }
418:
419: /*
420: * Get user's editors as set in environment or else use ed or vi.
421: */
422: open_ed(ed, which)
423: register char *ed, *which;
424: {
425: char *p;
426: struct stat e_stat;
427:
428: if (p = getenv(which))
429: strcpy(ed, p);
430: if (!ed[0] || stat(ed, &e_stat) == -1)
431: strcpy(ed, (!strcmp(which, EDITOR) ? "/bin/ed" : "/usr/bin/vi"));
432: }
433:
434: /*
435: * Write out to file.
436: */
437: void
438: fixrefer()
439: {
440: char
441: buf[BUFSIZ],
442: savestr[BUFSIZ]
443: ;
444: register char
445: *bufp,
446: *p
447: ;
448: register struct ref *r;
449: register struct att
450: *a,
451: *t
452: ;
453: int
454: first = 1,
455: printed
456: ;
457:
458: if ((tmp = fopen(tmpref, "r")) == NULL)
459: return;
460:
461: if ((r = sr) == NULL)
462: return;
463:
464: a = r->r_att;
465: if (fgets(buf, sizeof buf, tmp) == NULL)
466: return;
467: #ifdef PREFER
468: putrefer(refer, "%s %s\n", TYPE, r->r_prompt);
469: #endif /* PREFER */
470:
471: if ((p = strchr(buf, '\n')) != NULL)
472: *p = '\0';
473:
474: for (t = a; t; t = t->a_next)
475: if (!strncmp(t->a_prompt, buf, strlen(t->a_prompt)))
476: break;
477:
478: if (t) {
479: bufp = buf + strlen(t->a_prompt);
480: if (*bufp == ':')
481: bufp += 2;
482: } else
483: return;
484: a = t;
485: if (a->a_flag != '!')
486: strcpy(savestr, bufp);
487: while (fgets(&buf[0], sizeof(buf), tmp) != NULL) {
488: if ((p = strchr(buf, '\n')) != NULL)
489: *p = '\0';
490:
491: for (t = a; t; t = t->a_next) {
492: if (!strncmp(t->a_prompt, buf, strlen(t->a_prompt)))
493: break;
494: }
495:
496: if (t && t != a) {
497: if (first && a->a_flag != '!') /* first line */
498: putrefer(refer, "%s %s\n", a->a_refer, savestr);
499: else if (a->a_flag != '!') /* last line */
500: putrefer(refer, "%s %s\n", a->a_econt, savestr);
501: first = TRUE;
502: a = t;
503: bufp = buf + strlen(t->a_prompt);
504: if (*bufp == ':')
505: bufp += 2;
506: } else {
507: printed = FALSE;
508: if (first && a->a_flag != '!') /* first line */
509: printed = putrefer(refer, "%s %s\n", a->a_refer,
510: savestr);
511: else if (a->a_flag != '!') /* middle line */
512: putrefer(refer, "%s %s\n", a->a_mcont, savestr);
513: if (printed)
514: first = FALSE;
515: bufp = (t ? buf + strlen(t->a_prompt) : buf);
516: if (*bufp == ':')
517: bufp += 2;
518: }
519: strcpy(savestr, bufp);
520: }
521: if (first)
522: putrefer(refer, "%s %s\n", a->a_refer, savestr);
523: else
524: putrefer(refer, "%s %s\n", a->a_econt, savestr);
525: fprintf(refer, "\n");
526: }
527:
528: /*
529: * Print string onto fp, or nothing if arg2 is NULL.
530: */
531: putrefer(fp, str, arg1, arg2)
532: FILE *fp;
533: char *str, *arg1, *arg2;
534: {
535: if (strlen(arg2)) {
536: fprintf(fp, str, arg1, arg2);
537: return(1);
538: }
539: return(0);
540: }
541:
542: /*
543: * End of program.
544: */
545: cleanup()
546: {
547: signal(SIGINT, SIG_IGN);
548: signal(SIGQUIT, SIG_IGN);
549: if (tmp) {
550: fflush(tmp);
551: fclose(tmp);
552: }
553: fixrefer();
554: unlink(tmpref);
555: printf("\n");
556: exit(0);
557: }
558:
559: /*
560: * Open template file.
561: */
562: FILE *
563: tmpopen(file)
564: char *file;
565: {
566: FILE *fp;
567:
568: if ((fp = fopen(file, "r")) == NULL)
569: errexit(1, "Can't open template file, %s\n", file);
570: return(fp);
571: }
572:
573: /*
574: * Find matches for buf in ref; set rr to last match.
575: */
576: match(rr, buf)
577: register struct ref **rr;
578: char *buf;
579: {
580: register struct ref *r;
581: register matches;
582:
583: for (r = ref, matches = 0; r; r = r->r_next)
584: if (!strncmp(buf, r->r_prompt, strlen(buf))) {
585: ++matches;
586: *rr = r;
587: }
588:
589: if (matches >= 2) {
590: printf("`%s' is not unique: ", &buf[0]);
591: for (r = ref; r; r = r->r_next)
592: if (!strncmp(buf, r->r_prompt, strlen(buf)))
593: printf("`%s' ", r->r_prompt);
594: printf("all match\n");
595: }
596: return(matches);
597: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.