Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / uip / prompter.c
1 /* prompter.c - prompting editor front-end */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: prompter.c,v 1.9 1992/12/15 00:20:22 jromine Exp $";
4 #endif  /* lint */
5
6 #include "../h/mh.h"
7 #include <stdio.h>
8 #include <errno.h>
9 #ifndef SYS5
10 #include <sgtty.h>
11 #else   /* SYS5 */
12 #include <sys/types.h>
13 #include <termio.h>
14 #ifndef NOIOCTLH
15 #include <sys/ioctl.h>
16 #endif  /* NOIOCTLH */
17 #endif  /* SYS5 */
18 #ifdef  BSD42
19 #include <setjmp.h>
20 #endif  /* BSD42 */
21 #include <signal.h>
22 #ifdef LOCALE
23 #include        <locale.h>
24 #endif
25
26
27 #define QUOTE   '\\'
28 #ifndef CKILL
29 #define CKILL   '@'
30 #endif  /* not CKILL */
31 #ifndef CERASE
32 #define CERASE  '#'
33 #endif  /* not CERASE */
34
35 /* \f */
36
37 static struct swit switches[] = {
38 #define ERASESW 0
39     "erase chr", 0,
40 #define KILLSW  1
41     "kill chr", 0,
42
43 #define PREPSW  2
44     "prepend", 0,       
45 #define NPREPSW 3
46     "noprepend", 0,     
47
48 #define RAPDSW  4
49     "rapid", 0, 
50 #define NRAPDSW 5
51     "norapid", 0,       
52
53 #define BODYSW  6
54     "body", -4,
55 #define NBODYSW 7
56     "nobody", -6,
57
58 #define DOTSW   8
59     "doteof", 0,
60 #define NDOTSW  9
61     "nodoteof", 0,
62
63 #define HELPSW  10
64     "help", 4,          
65
66     NULL, 0
67 };
68
69 /* \f */
70
71 extern int  errno;
72
73
74 #ifndef SYS5
75 #define ERASE   sg.sg_erase
76 #define KILL    sg.sg_kill
77 static struct sgttyb    sg;
78
79 #define INTR    tc.t_intrc
80 static struct tchars    tc;
81 #else   /* SYS5 */
82 #define ERASE   sg.c_cc[VERASE]
83 #define KILL    sg.c_cc[VKILL]
84 #define INTR    sg.c_cc[VINTR]
85 static struct termio    sg;
86 #endif  /* SYS5 */
87
88
89 static TYPESIG  intrser ();
90
91 static int  wtuser = 0;
92 static int  sigint = 0;
93
94 #ifdef  BSD42
95 static jmp_buf sigenv;
96 #endif  /* BSD42 */
97
98 /* \f */
99
100 /* ARGSUSED */
101
102 main (argc, argv)
103 int     argc;
104 char   *argv[];
105 {
106     int     body = 1,
107             prepend = 1,
108             rapid = 0,
109             doteof = 0,
110             fdi,
111             fdo,
112             i,
113             state;
114     char   *cp,
115            *drft = NULL,
116            *erasep = NULL,
117            *killp = NULL,
118             name[NAMESZ],
119             field[BUFSIZ],
120             buffer[BUFSIZ],
121             tmpfil[BUFSIZ],
122           **ap,
123            *arguments[MAXARGS],
124           **argp;
125     FILE *in, *out;
126
127 #ifdef LOCALE
128         setlocale(LC_ALL, "");
129 #endif
130     invo_name = r1bindex (argv[0], '/');
131     if ((cp = m_find (invo_name)) != NULL) {
132         ap = brkstring (cp = getcpy (cp), " ", "\n");
133         ap = copyip (ap, arguments);
134     }
135     else
136         ap = arguments;
137     (void) copyip (argv + 1, ap);
138     argp = arguments;
139
140 /* \f */
141
142     while (cp = *argp++)
143         if (*cp == '-')
144             switch (smatch (++cp, switches)) {
145                 case AMBIGSW: 
146                     ambigsw (cp, switches);
147                     done (1);
148                 case UNKWNSW: 
149                     adios (NULLCP, "-%s unknown", cp);
150                 case HELPSW: 
151                     (void) sprintf (buffer, "%s [switches] file", invo_name);
152                     help (buffer, switches);
153                     done (1);
154
155                 case ERASESW: 
156                     if (!(erasep = *argp++) || *erasep == '-')
157                         adios (NULLCP, "missing argument to %s", argp[-2]);
158                     continue;
159                 case KILLSW: 
160                     if (!(killp = *argp++) || *killp == '-')
161                         adios (NULLCP, "missing argument to %s", argp[-2]);
162                     continue;
163
164                 case PREPSW: 
165                     prepend++;
166                     continue;
167                 case NPREPSW: 
168                     prepend = 0;
169                     continue;
170
171                 case RAPDSW: 
172                     rapid++;
173                     continue;
174                 case NRAPDSW: 
175                     rapid = 0;
176                     continue;
177
178                 case BODYSW: 
179                     body++;
180                     continue;
181                 case NBODYSW: 
182                     body = 0;
183                     continue;
184
185                 case DOTSW: 
186                     doteof++;
187                     continue;
188                 case NDOTSW: 
189                     doteof = 0;
190                     continue;
191             }
192         else
193             if (!drft)
194                 drft = cp;
195
196 /* \f */
197
198     if (!drft)
199         adios (NULLCP, "usage: %s [switches] file", invo_name);
200     if ((in = fopen (drft, "r")) == NULL)
201         adios (drft, "unable to open");
202
203     (void) strcpy (tmpfil, m_tmpfil (invo_name));
204     if ((out = fopen (tmpfil, "w")) == NULL)
205         adios (tmpfil, "unable to create");
206     (void) chmod (tmpfil, 0600);
207
208     if (killp || erasep) {
209 #ifndef SYS5
210         int    serase,
211                skill;
212 #else   /* SYS5 */
213         char   serase,
214                skill;
215 #endif  /* SYS5 */
216
217 #ifndef SYS5
218         (void) ioctl (0, TIOCGETP, (char *) &sg);
219         (void) ioctl (0, TIOCGETC, (char *) &tc);
220 #else   /* SYS5 */
221         (void) ioctl(0, TCGETA, &sg);
222 #endif  /* SYS5 */
223         skill = KILL;
224         serase = ERASE;
225         KILL = killp ? chrcnv (killp) : skill;
226         ERASE = erasep ? chrcnv (erasep) : serase;
227 #ifndef SYS5
228         (void) ioctl (0, TIOCSETN, (char *) &sg);
229 #else   /* SYS5 */
230         (void) ioctl(0, TCSETAW, &sg);
231 #endif  /* SYS5 */
232
233         chrdsp ("erase", ERASE);
234         chrdsp (", kill", KILL);
235         chrdsp (", intr", INTR);
236         (void) putchar ('\n');
237         (void) fflush (stdout);
238
239         KILL = skill;
240         ERASE = serase;
241     }
242
243 /* \f */
244
245     sigint = 0;
246     setsig (SIGINT, intrser);
247
248     for (state = FLD;;) {
249         switch (state = m_getfld (state, name, field, sizeof field, in)) {
250             case FLD: 
251             case FLDEOF: 
252             case FLDPLUS: 
253                 for (cp = field; *cp; cp++)
254                     if (*cp != ' ' && *cp != '\t')
255                         break;
256                 if (*cp++ != '\n' || *cp != 0) {
257                     printf ("%s:%s", name, field);
258                     fprintf (out, "%s:%s", name, field);
259                     while (state == FLDPLUS) {
260                         state =
261                             m_getfld (state, name, field, sizeof field, in);
262                         printf ("%s", field);
263                         fprintf (out, "%s", field);
264                     }
265                 }
266                 else {
267                     printf ("%s: ", name);
268                     (void) fflush (stdout);
269                     i = getln (field, sizeof field);
270                     if (i == -1) {
271 abort: ;
272                         if (killp || erasep)
273 #ifndef SYS5
274                             (void) ioctl (0, TIOCSETN, (char *) &sg);
275 #else   /* SYS5 */
276                             (void) ioctl (0, TCSETA, &sg);
277 #endif  /* SYS5 */
278                         (void) unlink (tmpfil);
279                         done (1);
280                     }
281                     if (i != 0 || (field[0] != '\n' && field[0] != 0)) {
282                         fprintf (out, "%s:", name);
283                         do {
284                             if (field[0] != ' ' && field[0] != '\t')
285                                 (void) putc (' ', out);
286                             fprintf (out, "%s", field);
287                         } while (i == 1
288                                     && (i = getln (field, sizeof field)) >= 0);
289                         if (i == -1)
290                             goto abort;
291                     }
292                 }
293                 if (state == FLDEOF) {/* moby hack */
294                     fprintf (out, "--------\n");
295                     printf ("--------\n");
296                     if (!body)
297                         break;
298                     goto no_body;
299                 }
300                 continue;
301
302             case BODY: 
303             case BODYEOF:
304             case FILEEOF: 
305                 if (!body)
306                     break;
307                 fprintf (out, "--------\n");
308                 if (field[0] == 0 || !prepend)
309                     printf ("--------\n");
310                 if (field[0]) {
311                     if (prepend && body) {
312                         printf ("\n--------Enter initial text\n\n");
313                         (void) fflush (stdout);
314                         for (;;) {
315                             (void) getln (buffer, sizeof buffer);
316                             if (doteof && buffer[0] == '.' && buffer[1] == '\n')
317                                 break;
318                             if (buffer[0] == 0)
319                                 break;
320                             fprintf (out, "%s", buffer);
321                         }
322                     }
323
324                     do {
325                         fprintf (out, "%s", field);
326                         if (!rapid && !sigint)
327                             printf ("%s", field);
328                     } while (state == BODY &&
329                             (state = m_getfld (state, name, field, sizeof field, in)));
330                     if (prepend || !body)
331                         break;
332                     else
333                         printf ("\n--------Enter additional text\n\n");
334                 }
335 no_body: ;
336                 (void) fflush (stdout);
337                 for (;;) {
338                     (void) getln (field, sizeof field);
339                     if (doteof && field[0] == '.' && field[1] == '\n')
340                         break;
341                     if (field[0] == 0)
342                         break;
343                     fprintf (out, "%s", field);
344                 }
345                 break;
346
347             default: 
348                 adios (NULLCP, "skeleton is poorly formatted");
349         }
350         break;
351     }
352
353     if (body)
354         printf ("--------\n");
355     (void) fflush (stdout);
356
357     (void) fclose (in);
358     (void) fclose (out);
359
360     (void) signal (SIGINT, SIG_IGN);
361
362 /* \f */
363
364     if (killp || erasep)
365 #ifndef SYS5
366         (void) ioctl (0, TIOCSETN, (char *) &sg);
367 #else   /* SYS5 */
368         (void) ioctl (0, TCSETAW, &sg);
369 #endif  /* SYS5 */
370
371     if ((fdi = open (tmpfil, 0)) == NOTOK)
372         adios (tmpfil, "unable to re-open");
373     if ((fdo = creat (drft, m_gmprot ())) == NOTOK)
374         adios (drft, "unable to write");
375     cpydata (fdi, fdo, tmpfil, drft);
376     (void) close (fdi);
377     (void) close (fdo);
378     (void) unlink (tmpfil);
379
380     m_update ();
381
382     done (0);
383 }
384
385 /* \f */
386
387 getln (buffer, n)
388 char   *buffer;
389 int     n;
390 {
391     int     c;
392     char   *cp;
393
394     cp = buffer;
395     *cp = 0;
396
397 #ifndef BSD42
398     wtuser = 1;
399 #else   /* BSD42 */
400     switch (setjmp (sigenv)) {
401         case OK: 
402             wtuser = 1;
403             break;
404
405         case DONE: 
406             wtuser = 0;
407             return 0;
408
409         default: 
410             wtuser = 0;
411             return NOTOK;
412     }
413 #endif  /* BSD42 */
414
415     for (;;)
416         switch (c = getchar ()) {
417             case EOF: 
418 #ifndef BSD42
419                 wtuser = 0;
420                 return (errno != EINTR ? 0 : NOTOK);
421 #else   /* BSD42 */
422                 clearerr (stdin);
423                 longjmp (sigenv, DONE);
424 #endif  /* BSD42 */
425
426             case '\n': 
427                 if (cp[-1] == QUOTE) {
428                     cp[-1] = c;
429                     wtuser = 0;
430                     return 1;
431                 }
432                 *cp++ = c;
433                 *cp = 0;
434                 wtuser = 0;
435                 return 0;
436
437             default: 
438                 if (cp < buffer + n)
439                     *cp++ = c;
440                 *cp = 0;
441         }
442 }
443
444 /* \f */
445
446 /* ARGSUSED */
447
448 static  TYPESIG intrser (i)
449 int    i;
450 {
451 #ifndef BSD42
452     (void) signal (SIGINT, intrser);
453     if (!wtuser)
454         sigint++;
455 #else   /* BSD42 */
456     if (wtuser)
457         longjmp (sigenv, NOTOK);
458     sigint++;
459 #endif  /* BSD42 */
460 }
461
462
463 chrcnv (cp)
464 register char   *cp;
465 {
466     return (*cp != QUOTE ? *cp : m_atoi (++cp));
467 }
468
469
470 chrdsp (s, c)
471 char   *s,
472         c;
473 {
474     printf ("%s ", s);
475     if (c < ' ' || c == 0177)
476         printf ("^%c", c ^ 0100);
477     else
478         printf ("%c", c);
479 }