]> diplodocus.org Git - nmh/blob - docs/historical/mh-jun-1982/dytest/mhl.c
Replaced use of snprintf() with memcpy()/memmove().
[nmh] / docs / historical / mh-jun-1982 / dytest / mhl.c
1 #ifdef COMMENT
2 Proprietary Rand Corporation, 1981.
3 Further distribution of this software
4 subject to the terms of the Rand
5 license agreement.
6 #endif
7
8 /* THIS command is included wholesale by show.c, which calls
9 * its `main' rather than execing it when showproc is "mhl"
10 */
11
12 #include <ctype.h>
13 #include <signal.h>
14 #include <setjmp.h>
15 #include <sgtty.h>
16 #ifndef INCLUDED_BY_SHOW
17 #include <stdio.h>
18 #include "../mh.h"
19 #endif INCLUDED_BY_SHOW
20 char *calloc();
21 extern char *index();
22 extern char *sprintf();
23
24 char *ignores[25];
25 char **igp = ignores; /* List of ignored components */
26 char *parptr, *parse();
27 char *fmtfile; /* User specified format file */
28 char *folder; /* Name of folder messages are in */
29 char *profargs[32]; /* Args extracted from profile */
30 int ofilec; /* Count of real output file args */
31 int ofilen; /* Number of output file */
32 int ontty; /* Output to char device */
33 int clearflg; /* Overrides format screen clear */
34 int row, column; /* For character output routine */
35 int alength, awidth; /* -length and -width args */
36 char *oneline();
37 int sigcatch();
38 int exitstat;
39 jmp_buf env;
40
41 extern char _sobuf[]; /* MLW standard out buffer */
42 char *strcpy();
43
44 /* Defines for c_flags (see below) */
45 #define NOCOMPONENT 01 /* Don't show component name */
46 #define UPPERCASE 02 /* Display in all upper case */
47 #define CENTER 04 /* Center line within width */
48 #define CLEARTEXT 010 /* Clear text line--simply copy to output */
49 #define PROCESSED 020 /* This item processed already */
50 #define EXTRA 040 /* This message comp is an "extra" */
51 #define HDROUTPUT 0100 /* This comp's hdr has been output */
52 #define CLEARSCR 0200 /* Clear screen before each file */
53 #define LEFTADJUST 0400 /* Left adjust mult lines of component */
54 #define COMPRESS 01000 /* Compress text--ignore <lf's> */
55
56 struct comp {
57 struct comp *c_next; /* Chain to next */
58 char *c_name, /* Component name */
59 *c_text, /* Text associated with component */
60 *c_ovtxt; /* Line overflow indicator text */
61 int c_offset, /* Left margin indent */
62 c_ovoff, /* Line overflow indent */
63 c_width, /* Width of field */
64 c_cwidth, /* Component width (default strlen(comp)) */
65 c_length; /* Length in lines */
66 short c_flags; /* Special flags (see above) */
67
68 } *msghd, *msgtl, *fmthd, *fmttl,
69 /* Global contains global len/wid info */
70 global = { NULL, NULL, NULL, "", 0, 0, 80, 0, 40, 0 },
71 holder = { NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NOCOMPONENT };
72
73 /* Defines for putcomp subrutine mode arg */
74 #define ONECOMP 0 /* Display only control comp name */
75 #define BOTHCOMP 1 /* Display both comp names (conditionally) */
76
77 /*ARGSUSED*/
78 main(argc, argv)
79 int argc;
80 char *argv[];
81 {
82 register struct comp *comp;
83 register char *cp, **ap;
84 FILE *fp;
85 char line[256], name[64];
86 int out();
87
88 invo_name = argv[0];
89 setbuf(stdout, _sobuf);
90 VOID signal(SIGQUIT, out);
91 ontty = gtty(1, (struct sgttyb *)name) != -1;
92 cp = r1bindex(argv[0], '/');
93 if((cp = m_find(cp)) != NULL) {
94 ap = brkstring(getcpy(cp), " ", "\n");
95 VOID copyip(ap, profargs);
96 /* procargs(ap);*/
97 procargs(profargs);
98 }
99 procargs(argv + 1);
100 if(!folder)
101 folder = getenv("mhfolder");
102 if(fmtfile) {
103 if((fp = fopen(m_maildir(fmtfile), "r")) == NULL) {
104 fprintf(stderr, "mhl: Can't open format file: %s\n",
105 fmtfile);
106 done(1);
107 }
108 } else if((fp = fopen(m_maildir(mhlformat), "r")) == NULL &&
109 (fp = fopen(mhlstdfmt, "r")) == NULL) {
110 fprintf(stderr, "mhl: Can't open default format file.\n");
111 done(1);
112 }
113 while(fgets(line, sizeof line, fp)) {
114 if(line[0] == ';') /* Comment line */
115 continue;
116
117 line[strlen(line)-1] = 0; /* Zap the <lf> */
118
119 if(line[0] == ':') { /* Clear text line */
120 comp = (struct comp *) calloc(1, sizeof (struct comp));
121 comp->c_text = getcpy(line+1);
122 comp->c_flags = CLEARTEXT;
123 comp->c_ovoff = -1;
124 comp->c_cwidth = -1;
125 goto fmtqueue;
126 }
127
128 parptr = line;
129 strcpy(name, parse());
130 /*** printf("%s %c %s\n", name, *parptr, parptr+1); */
131 switch(*parptr) {
132
133 case '\0':
134 case ',':
135 case '=':
136 if(uleq(name, "ignores")) {
137 igp = copyip(brkstring(getcpy(++parptr), ",", NULLCP), igp);
138 continue;
139 }
140 parptr = line;
141 while(*parptr) {
142 if(evalvar(&global)) {
143 fmterr: fprintf(stderr, "mhl: format file syntax error: %s\n",
144 line);
145 done(1);
146 }
147 if(*parptr)
148 parptr++;
149 }
150 continue;
151
152 case ':':
153 comp = (struct comp *) calloc(1, sizeof (struct comp));
154 comp->c_name = getcpy(name);
155 comp->c_cwidth = -1;
156 comp->c_ovoff = -1;
157 while(*parptr == ':' || *parptr == ',') {
158 parptr++;
159 if(evalvar(comp))
160 goto fmterr;
161 }
162 fmtqueue: if(!fmthd)
163 fmthd = fmttl = comp;
164 else {
165 fmttl->c_next = comp;
166 fmttl = comp;
167 }
168 continue;
169
170 default:
171 goto fmterr;
172
173 }
174 }
175 if(clearflg == 1)
176 global.c_flags |= CLEARSCR;
177 else if(clearflg == -1)
178 global.c_flags &= ~CLEARSCR;
179 if(awidth) global.c_width = awidth;
180 if(alength) global.c_length = alength;
181 if(global.c_width < 5) global.c_width = 10000;
182 if(global.c_length < 5) global.c_length = 10000;
183 VOID fclose(fp);
184 if(!ofilec)
185 process(NULLCP);
186 else {
187 for(ap = profargs; *ap; ap++)
188 if(**ap)
189 process(*ap);
190 for(ap = argv+1; *ap; ap++)
191 if(**ap)
192 process(*ap);
193 }
194 done(exitstat);
195 }
196
197
198 evalvar(sp)
199 register struct comp *sp;
200 {
201 register char *cp;
202 int c;
203 char name[32];
204
205 if(!*parptr)
206 return 0;
207 strcpy(name, parse());
208 /***printf("evalvar: %s %c %s\n", name, *parptr, parptr+1); */
209 if(uleq(name, "width")) {
210 if(!*parptr++ == '=' || !*(cp = parse())) {
211 missing: fprintf(stderr, "mhl: missing arg to variable %s\n",
212 name);
213 return 1;
214 }
215 sp->c_width = atoi(cp);
216 return 0;
217 }
218 if(uleq(name, "compwidth")) {
219 if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
220 sp->c_cwidth = atoi(cp);
221 return 0;
222 }
223 if(uleq(name, "length")) {
224 if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
225 sp->c_length = atoi(cp);
226 return 0;
227 }
228 if(uleq(name, "overflowtext")) {
229 if(!*parptr++ == '=') goto missing;
230 cp = parptr;
231 while(*parptr && *parptr != ':' && *parptr != ',') parptr++;
232 c = *parptr;
233 *parptr = 0;
234 sp->c_ovtxt = getcpy(cp);
235 *parptr = c;
236 return 0;
237 }
238 if(uleq(name, "offset")) {
239 if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
240 sp->c_offset = atoi(cp);
241 return 0;
242 }
243 if(uleq(name, "overflowoffset")) {
244 if(!*parptr++ == '=' || !*(cp = parse())) goto missing;
245 sp->c_ovoff = atoi(cp);
246 return 0;
247 }
248 if(uleq(name, "nocomponent")) {
249 sp->c_flags |= NOCOMPONENT;
250 return 0;
251 }
252 if(uleq(name, "uppercase")) {
253 sp->c_flags |= UPPERCASE;
254 return 0;
255 }
256 if(uleq(name, "center")) {
257 sp->c_flags |= CENTER;
258 return 0;
259 }
260 if(uleq(name, "clearscreen")) {
261 sp->c_flags |= CLEARSCR;
262 return 0;
263 }
264 if(uleq(name, "leftadjust")) {
265 sp->c_flags |= LEFTADJUST;
266 return 0;
267 }
268 if(uleq(name, "compress")) {
269 sp->c_flags |= COMPRESS;
270 return 0;
271 }
272 return 1;
273 }
274
275
276 char *
277 parse()
278 {
279 static char result[64];
280 register char *cp;
281 register int c;
282
283 cp = result;
284 while(c = *parptr)
285 if(isalnum(c) || c == '.' || c == '-' || c == '_') {
286 *cp++ = c;
287 parptr++;
288 } else
289 break;
290 *cp = 0;
291 return result;
292 }
293
294 struct swit switches[] = {
295 "clear", 0, /* 0 */
296 "noclear", 0, /* 1 */
297 "folder folder", 0, /* 2 */
298 "form formfile", 0, /* 3 */
299 "length of page", 0, /* 4 */
300 "width of line", 0, /* 5 */
301 "help", 4, /* 6 */
302 0, 0
303 };
304
305 procargs(ap)
306 register char **ap;
307 {
308 register char *cp;
309
310 while(cp = *ap++)
311 if(*cp == '-') switch(smatch(++cp, switches)) {
312 case -2:ambigsw(cp, switches); /* ambiguous */
313 done(1);
314 /* unknown */
315 case -1:fprintf(stderr, "mhl: -%s unknown\n", cp);
316 done(1);
317 /* -form format */
318 case 0: clearflg = 1; /* -clear */
319 ap[-1] = "";
320 break;
321
322 case 1: clearflg = -1; /* -noclear */
323 ap[-1] = "";
324 break;
325
326 case 2: if(!(folder = *ap++) || *folder == '-') {
327 missing: fprintf(stderr, "mhl: Missing arg for %s\n", ap[-2]);
328 done(1);
329 }
330 ap[-2] = ""; ap[-1] = "";
331 break;
332
333 case 3: if(!(fmtfile = *ap++) || *fmtfile == '-')
334 goto missing;
335 ap[-2] = ""; ap[-1] = "";
336 break;
337 /* length */
338 case 4: if(!(cp = *ap++) || *cp == '-')
339 goto missing;
340 alength = atoi(cp);
341 ap[-2] = ""; ap[-1] = "";
342 break;
343 /* width */
344 case 5: if(!(cp = *ap++) || *cp == '-')
345 goto missing;
346 awidth = atoi(cp);
347 ap[-2] = ""; ap[-1] = "";
348 break;
349 /* -help */
350 case 6: help("mhl [switches] [files]", switches);
351 done(0);
352
353 } else
354 ofilec++;
355 }
356
357 FILE *fp;
358
359 process(fname)
360 char *fname;
361 {
362 register int state;
363 register struct comp *comp, *c2, *c3;
364 char *cp, **ip, name[NAMESZ], buf[BUFSIZ];
365
366 if(setjmp(env)) {
367 discard(stdout);
368 putchar('\n');
369 goto out;
370 }
371 VOID signal(SIGINT, sigcatch);
372 if(fname) {
373 if((fp = fopen(fname, "r")) == NULL) {
374 fprintf(stderr, "mhl: Can't open ");
375 perror(fname);
376 exitstat++;
377 VOID signal(SIGINT, SIG_IGN);
378 return;
379 }
380 } else
381 fp = stdin;
382 if(ontty) {
383 strcpy(buf, "\n");
384 if(ofilec > 1) {
385 if(ofilen)
386 printf("\n\n\n");
387 printf("Press <return> to list \"");
388 if(folder) printf("%s:", folder);
389 printf("%s\"...", fname);
390 VOID fflush(stdout);
391 strcpy(buf, "");
392 VOID read(1, buf, sizeof buf);
393 }
394 if(index(buf, '\n')) {
395 if(global.c_flags & CLEARSCR)
396 printf("\014\200");
397 } else
398 printf("\n");
399 } else if(ofilec > 1) {
400 if(ofilen)
401 printf("\n\n\n");
402 printf(">>> ");
403 if(folder) printf("%s: ", folder);
404 printf("%s\n\n", fname);
405 }
406
407 ofilen++;
408 row = column = 0;
409 msghd = 0;
410 for(state = FLD ; ;) {
411 state = m_getfld(state, name, buf, sizeof buf, fp);
412 switch(state) {
413
414 case FLD:
415 case FLDEOF:
416 case FLDPLUS:
417 for(ip = ignores; *ip; ip++)
418 if(uleq(name, *ip)) {
419 while(state == FLDPLUS)
420 state = m_getfld(state, name, buf, sizeof buf, fp);
421 goto next;
422 }
423 for(c3 = msghd; c3; c3 = c3->c_next)
424 if(uleq(name, c3->c_name))
425 break;
426 if(c3) {
427 comp = c3;
428 comp->c_text = add(buf, comp->c_text);
429 } else {
430 comp = (struct comp *) calloc(1, sizeof (struct comp));
431 comp->c_name = getcpy(name);
432 comp->c_text = getcpy(buf);
433 comp->c_cwidth = -1;
434 comp->c_ovoff = -1;
435 }
436 while(state == FLDPLUS) {
437 state = m_getfld(state, name, buf, sizeof buf, fp);
438 comp->c_text = add(buf, comp->c_text);
439 }
440 for(c2 = fmthd; c2; c2 = c2->c_next)
441 if(uleq(c2->c_name, comp->c_name))
442 goto goodun;
443 comp->c_flags |= EXTRA;
444 goodun: if(!c3) {
445 if(!msghd)
446 msghd = msgtl = comp;
447 else {
448 msgtl->c_next = comp;
449 msgtl = comp;
450 }
451 }
452 if(state == FLDEOF)
453 goto doit;
454 continue;
455
456 default:
457 case LENERR:
458 case FMTERR:
459 fprintf(stderr, "Message format error!\n");
460 exitstat++;
461 return;
462
463 case BODY:
464 case BODYEOF:
465 case FILEEOF:
466 doit:
467 for(comp = fmthd; comp; comp = comp->c_next) {
468 if(comp->c_flags & CLEARTEXT) {
469 putcomp(comp, comp, ONECOMP);
470 continue;
471 }
472 if(uleq(comp->c_name, "messagename")) {
473 cp = concat(fname, "\n", NULLCP);
474 if(folder) {
475 holder.c_text = concat(folder, ":", cp, NULLCP);
476 free(cp);
477 } else
478 holder.c_text = cp;
479 putcomp(comp, &holder, ONECOMP);
480 free(holder.c_text);
481 holder.c_text = 0;
482 }
483 if(uleq(comp->c_name, "extras")) {
484 for(c2 = msghd; c2; c2 = c2->c_next)
485 if(c2->c_flags & EXTRA)
486 putcomp(comp, c2, BOTHCOMP);
487 continue;
488 }
489 if(uleq(comp->c_name, "body")) {
490 holder.c_text = buf;
491 putcomp(comp, &holder, ONECOMP);
492 holder.c_text = 0;
493 while(state == BODY) {
494 state = m_getfld(state, name, buf, sizeof buf, fp);
495 holder.c_text = buf;
496 putcomp(comp, &holder, ONECOMP);
497 holder.c_text = 0;
498 }
499 continue;
500 }
501 for(c2 = msghd; c2; c2 = c2->c_next)
502 if(uleq(c2->c_name, comp->c_name)) {
503 putcomp(comp, c2, ONECOMP);
504 break;
505 }
506 }
507 out:
508 if(fp)
509 VOID fclose(fp);
510 fp = NULL;
511 if(holder.c_text) cndfree(holder.c_text);
512 holder.c_text = 0;
513 for(c2 = msghd; c2; c2 = comp) {
514 comp = c2->c_next;
515 cndfree(c2->c_name);
516 cndfree(c2->c_text);
517 free( (char *)c2);
518 }
519 msghd = msgtl = NULL;
520 for(c2 = fmthd; c2; c2 = c2->c_next)
521 c2->c_flags &= ~HDROUTPUT;
522 VOID signal(SIGINT, SIG_IGN);
523 return;
524 }
525 next: ;
526 }
527 }
528
529 int lm; /* Left Margin for putstr */
530 int llim; /* line limit for this component */
531 int wid; /* width limit for this comp */
532 int ovoff; /* overflow offset for this comp */
533 char *ovtxt; /* overflow text for this comp */
534 int term; /* term from last oneline() */
535 char *onelp; /* oneline() text pointer */
536
537 putcomp(cc, c2, flag)
538 register struct comp *cc, *c2;
539 int flag;
540 {
541 register char *cp;
542 int count, cchdr = 0;
543
544 #ifdef DEBUGCOMP
545 printf("%s(%o):%s:%s", cc->c_name, cc->c_flags, c2->c_name,
546 c2->c_text);
547 #endif
548 onelp = NULL;
549 lm = 0;
550 llim = cc->c_length? cc->c_length : -1;
551 wid = cc->c_width? cc->c_width : global.c_width;
552 ovoff = cc->c_ovoff >= 0 ? cc->c_ovoff : global.c_ovoff;
553 ovoff += cc->c_offset;
554 ovtxt = cc->c_ovtxt ? cc->c_ovtxt : global.c_ovtxt;
555 if(!ovtxt) ovtxt = "";
556 if(wid < ovoff + strlen(ovtxt) + 5) {
557 fprintf(stderr, "mhl: component: %s width too small for overflow.\n",
558 cc->c_name);
559 done(1);
560 }
561 if(cc->c_flags & CLEARTEXT) {
562 putstr(cc->c_text);
563 putstr("\n");
564 return;
565 }
566 if(cc->c_flags & CENTER) {
567 count = global.c_width;
568 if(cc->c_width) count = cc->c_width;
569 count -= cc->c_offset;
570 count -= strlen(c2->c_text);
571 if(!(cc->c_flags&HDROUTPUT) && !(cc->c_flags&NOCOMPONENT))
572 count -= strlen(cc->c_name) + 2;
573 lm = cc->c_offset+(count/2);
574 } else if(cc->c_offset)
575 lm = cc->c_offset;
576 if(!(cc->c_flags & HDROUTPUT) && !(cc->c_flags & NOCOMPONENT)) {
577 putstr(cc->c_name); putstr(": ");
578 cc->c_flags |= HDROUTPUT;
579 cchdr++;
580 if((count = cc->c_cwidth - strlen(cc->c_name) - 2) > 0)
581 while(count--) putstr(" ");
582 }
583 if(flag == BOTHCOMP && !(c2->c_flags & HDROUTPUT) &&
584 !(c2->c_flags & NOCOMPONENT)) {
585 putstr(c2->c_name); putstr(": ");
586 c2->c_flags |= HDROUTPUT;
587 }
588 if(cc->c_flags & UPPERCASE)
589 for(cp = c2->c_text; *cp; cp++)
590 if(islower(*cp))
591 *cp -= 'a' - 'A';
592 count = 0;
593 if(cchdr)
594 count = (cc->c_cwidth>=0) ? cc->c_cwidth : strlen(cc->c_name)+2;
595 count += cc->c_offset;
596 putstr(oneline(c2->c_text, cc->c_flags));
597 /*** if(cc->c_flags & COMPRESS) printf("-1-"); /***/
598 if(term == '\n')
599 putstr("\n");
600 while(cp = oneline(c2->c_text, cc->c_flags)) {
601 /*** if(cc->c_flags & COMPRESS) printf("-2-"); /***/
602 if(*cp) {
603 lm = count;
604 putstr(cp);
605 if(term == '\n')
606 putstr("\n");
607 } else
608 if(term == '\n')
609 putstr("\n");
610 }
611 c2->c_flags |= PROCESSED;
612 }
613
614 putstr(string)
615 register char *string;
616 {
617 if(!column && lm > 0)
618 while(lm > 0)
619 if(lm >= 8) {
620 putch('\t');
621 lm -= 8;
622 } else {
623 putch(' ');
624 lm--;
625 }
626 lm = 0;
627 while(*string)
628 putch(*string++);
629 }
630
631 putch(ch)
632 {
633 char buf[32];
634
635 if(llim == 0)
636 return;
637 switch(ch) {
638 case '\n':
639 if(llim > 0) llim--;
640 column = 0;
641 row++;
642 if(ontty && row == global.c_length) {
643 putchar('\007');
644 VOID fflush(stdout);
645 buf[0] = 0;
646 VOID read(1, buf, sizeof buf);
647 if(index(buf, '\n')) {
648 if(global.c_flags & CLEARSCR) {
649 putchar('\014');
650 putchar('\200');
651 }
652 row = 0;
653 } else {
654 putchar('\n');
655 row = global.c_length / 3;
656 }
657 return;
658 }
659 break;
660 case '\t':
661 column |= 07;
662 column++;
663 break;
664
665 case '\010':
666 column--;
667 break;
668
669 case '\r':
670 column = 0;
671 break;
672
673 default:
674 if(ch >= ' ')
675 column++;
676 }
677 if(column >= wid) {
678 putch('\n');
679 if(ovoff > 0)
680 lm = ovoff;
681 if(ovtxt)
682 putstr(ovtxt);
683 else
684 putstr("");
685 putch(ch);
686 return;
687 }
688 putchar(ch);
689 }
690
691
692 char *
693 oneline(stuff, flgs)
694 char *stuff;
695 {
696 register char *ret;
697 register char *cp;
698 int spc;
699
700 if(!onelp)
701 onelp = stuff;
702 if(!*onelp) {
703 onelp = 0;
704 return NULL;
705 }
706 ret = onelp;
707 term = 0;
708 if(flgs & COMPRESS) {
709 cp = ret;
710 spc = 0;
711 while(*onelp) {
712 if(*onelp == '\n' || *onelp == '\t' || *onelp == ' '){
713 if(*onelp == '\n' && !onelp[1]) {
714 term = '\n';
715 break;
716 } else if(!spc) {
717 *cp++ = ' ';
718 spc++;
719 }
720 } else {
721 *cp++ = *onelp;
722 spc = 0;
723 }
724 onelp++;
725 }
726 *onelp = 0;
727 *cp = 0;
728 } else {
729 while(*onelp && *onelp != '\n') onelp++;
730 if(*onelp == '\n') {
731 term = '\n';
732 *onelp++ = 0;
733 }
734 if(flgs&LEFTADJUST)
735 while(*ret == ' ' || *ret == '\t') ret++;
736 }
737 return ret;
738 }
739
740
741 sigcatch()
742 {
743 longjmp(env, 1);
744 }
745
746
747 out()
748 {
749 putchar('\n');
750 VOID fflush(stdout);
751 exit(-1);
752 }
753
754 discard(io)
755 register FILE *io;
756 {
757 struct sgttyb sg;
758
759 if (ioctl(fileno (io), TIOCGETP, &sg) >= 0)
760 ioctl(fileno (io), TIOCSETP, &sg);
761 io->_cnt = BUFSIZ;
762 io->_ptr