source: trunk/third/nmh/uip/prompter.c @ 12455

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