add free_field as standard for struct field
[mmh] / uip / prompter.c
index f92eda1..21ec5ce 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * prompter.c -- simple prompting editor front-end
- *
- * This code is Copyright (c) 2002, by the authors of nmh.  See the
- * COPYRIGHT file in the root directory of the nmh distribution for
- * complete copyright information.
- */
+** prompter.c -- simple prompting editor front-end
+**
+** This code is Copyright (c) 2002, by the authors of nmh.  See the
+** COPYRIGHT file in the root directory of the nmh distribution for
+** complete copyright information.
+*/
 
 #include <h/mh.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <signal.h>
 #include <setjmp.h>
-
-#ifdef HAVE_TERMIOS_H
-# include <termios.h>
-#else
-# ifdef HAVE_TERMIO_H
-#  include <termio.h>
-# else
-#  include <sgtty.h>
-# endif
-#endif
-
-#define QUOTE '\\'
-
-#ifndef CKILL
-# define CKILL '@'
-#endif
-
-#ifndef CERASE
-# define CERASE '#'
-#endif
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <locale.h>
+#include <sysexits.h>
 
 static struct swit switches[] = {
-#define ERASESW  0
-       { "erase chr", 0 },
-#define KILLSW  1
-       { "kill chr", 0 },
-#define PREPSW  2
+#define PREPSW  0
        { "prepend", 0 },
-#define NPREPSW  3
-       { "noprepend", 0 },
-#define RAPDSW  4
+#define NPREPSW  1
+       { "noprepend", 2 },
+#define RAPDSW  2
        { "rapid", 0 },
-#define NRAPDSW  5
-       { "norapid", 0 },
-#define BODYSW  6
-       { "body", -4 },
-#define NBODYSW  7
-       { "nobody", -6 },
-#define DOTSW  8
-       { "doteof", 0 },
-#define NDOTSW  9
-       { "nodoteof", 0 },
-#define VERSIONSW 10
-       { "version", 0 },
-#define HELPSW  11
+#define NRAPDSW  3
+       { "norapid", 2 },
+#define BODYSW  4
+       { "body", 0 },
+#define NBODYSW  5
+       { "nobody", 2 },
+#define VERSIONSW 6
+       { "Version", 0 },
+#define HELPSW  7
        { "help", 0 },
        { NULL, 0 }
 };
 
 
-#ifdef HAVE_TERMIOS_H
-static struct termios tio;
-# define ERASE tio.c_cc[VERASE]
-# define KILL  tio.c_cc[VKILL]
-# define INTR  tio.c_cc[VINTR]
-#else
-# ifdef HAVE_TERMIO_H
-static struct termio tio;
-#  define ERASE tio.c_cc[VERASE]
-#  define KILL  tio.c_cc[VKILL]
-#  define INTR  tio.c_cc[VINTR]
-# else
-static struct sgttyb tio;
-static struct tchars tc;
-#  define ERASE tio.sg_erase
-#  define KILL  tio.sg_kill
-#  define INTR  tc.t_intrc
-# endif
-#endif
-
-static int wtuser = 0;
-static int sigint = 0;
+volatile sig_atomic_t wtuser = 0;
+volatile sig_atomic_t sigint = 0;
 static jmp_buf sigenv;
 
 /*
- * prototypes
- */
-int getln (char *, int);
-static int chrcnv (char *);
-static void chrdsp (char *, char);
-static RETSIGTYPE intrser (int);
+** prototypes
+*/
+int getln(char *, int);
+static void intrser(int);
 
 
 int
-main (int argc, char **argv)
+main(int argc, char **argv)
 {
-       int body = 1, prepend = 1, rapid = 0;
-       int doteof = 0, fdi, fdo, i, state;
-       char *cp, *drft = NULL, *erasep = NULL;
-       char *killp = NULL, name[NAMESZ], field[BUFSIZ];
+       int qbody = 1, prepend = 1, rapid = 0;
+       int fdi, fdo, i;
+       char *cp, *drft = NULL;
+       enum state state;
+       struct field f = free_field;
        char buffer[BUFSIZ], tmpfil[BUFSIZ];
        char **arguments, **argp;
        FILE *in, *out;
        char *tfile = NULL;
 
-#ifdef LOCALE
        setlocale(LC_ALL, "");
-#endif
-       invo_name = r1bindex (argv[0], '/');
+       invo_name = mhbasename(argv[0]);
 
        /* read user profile/context */
        context_read();
 
-       arguments = getarguments (invo_name, argc, argv, 1);
+       arguments = getarguments(invo_name, argc, argv, 1);
        argp = arguments;
 
-       while ((cp = *argp++))
+       while ((cp = *argp++)) {
                if (*cp == '-') {
-                       switch (smatch (++cp, switches)) {
-                               case AMBIGSW:
-                                       ambigsw (cp, switches);
-                                       done (1);
-                               case UNKWNSW:
-                                       adios (NULL, "-%s unknown", cp);
-
-                               case HELPSW:
-                                       snprintf (buffer, sizeof(buffer), "%s [switches] file",
+                       switch (smatch(++cp, switches)) {
+                       case AMBIGSW:
+                               ambigsw(cp, switches);
+                               exit(EX_USAGE);
+                       case UNKWNSW:
+                               adios(EX_USAGE, NULL, "-%s unknown", cp);
+
+                       case HELPSW:
+                               snprintf(buffer, sizeof(buffer),
+                                               "%s [switches] file",
                                                invo_name);
-                                       print_help (buffer, switches, 1);
-                                       done (1);
-                               case VERSIONSW:
-                                       print_version(invo_name);
-                                       done (1);
-
-                               case ERASESW:
-                                       if (!(erasep = *argp++) || *erasep == '-')
-                                               adios (NULL, "missing argument to %s", argp[-2]);
-                                       continue;
-                               case KILLSW:
-                                       if (!(killp = *argp++) || *killp == '-')
-                                               adios (NULL, "missing argument to %s", argp[-2]);
-                                       continue;
-
-                               case PREPSW:
-                                       prepend++;
-                                       continue;
-                               case NPREPSW:
-                                       prepend = 0;
-                                       continue;
-
-                               case RAPDSW:
-                                       rapid++;
-                                       continue;
-                               case NRAPDSW:
-                                       rapid = 0;
-                                       continue;
-
-                               case BODYSW:
-                                       body++;
-                                       continue;
-                               case NBODYSW:
-                                       body = 0;
-                                       continue;
-
-                               case DOTSW:
-                                       doteof++;
-                                       continue;
-                               case NDOTSW:
-                                       doteof = 0;
-                                       continue;
+                               print_help(buffer, switches, 1);
+                               exit(argc == 2 ? EX_OK : EX_USAGE);
+
+                       case VERSIONSW:
+                               print_version(invo_name);
+                               exit(argc == 2 ? EX_OK : EX_USAGE);
+
+                       case PREPSW:
+                               prepend++;
+                               continue;
+                       case NPREPSW:
+                               prepend = 0;
+                               continue;
+
+                       case RAPDSW:
+                               rapid++;
+                               continue;
+                       case NRAPDSW:
+                               rapid = 0;
+                               continue;
+
+                       case BODYSW:
+                               qbody++;
+                               continue;
+                       case NBODYSW:
+                               qbody = 0;
+                               continue;
                        }
-               } else {
-                       if (!drft)
-                               drft = cp;
+               } else if (!drft) {
+                       drft = cp;
                }
+       }
 
-       if (!drft)
-               adios (NULL, "usage: %s [switches] file", invo_name);
-       if ((in = fopen (drft, "r")) == NULL)
-               adios (drft, "unable to open");
+       if (!drft) {
+               adios(EX_USAGE, NULL, "usage: %s [switches] file", invo_name);
+       }
+       if ((in = fopen(drft, "r")) == NULL) {
+               adios(EX_IOERR, drft, "unable to open");
+       }
 
        tfile = m_mktemp2(NULL, invo_name, NULL, &out);
-       if (tfile == NULL) adios("prompter", "unable to create temporary file");
-       chmod (tmpfil, 0600);
-       strncpy (tmpfil, tfile, sizeof(tmpfil));
-
-       /*
-        * Are we changing the kill or erase character?
-        */
-       if (killp || erasep) {
-#ifdef HAVE_TERMIOS_H
-               cc_t save_erase, save_kill;
-#else
-               int save_erase, save_kill;
-#endif
-
-               /* get the current terminal attributes */
-#ifdef HAVE_TERMIOS_H
-               tcgetattr(0, &tio);
-#else
-# ifdef HAVE_TERMIO_H
-               ioctl(0, TCGETA, &tio);
-# else
-               ioctl (0, TIOCGETP, (char *) &tio);
-               ioctl (0, TIOCGETC, (char *) &tc);
-# endif
-#endif
-
-               /* save original kill, erase character for later */
-               save_kill = KILL;
-               save_erase = ERASE;
-
-               /* set new kill, erase character in terminal structure */
-               KILL = killp ? chrcnv (killp) : save_kill;
-               ERASE = erasep ? chrcnv (erasep) : save_erase;
-
-               /* set the new terminal attributes */
-#ifdef HAVE_TERMIOS_H
-                tcsetattr(0, TCSADRAIN, &tio);
-#else
-# ifdef HAVE_TERMIO_H
-               ioctl(0, TCSETAW, &tio);
-# else
-               ioctl (0, TIOCSETN, (char *) &tio);
-# endif
-#endif
-
-               /* print out new kill erase characters */
-               chrdsp ("erase", ERASE);
-               chrdsp (", kill", KILL);
-               chrdsp (", intr", INTR);
-               putchar ('\n');
-               fflush (stdout);
-
-               /*
-                * We set the kill and erase character back to original
-                * setup in terminal structure so we can easily
-                * restore it upon exit.
-                */
-               KILL = save_kill;
-               ERASE = save_erase;
+       if (tfile == NULL) {
+               adios(EX_CANTCREAT, "prompter", "unable to create temporary file");
        }
+       chmod(tmpfil, 0600);
+       strncpy(tmpfil, tfile, sizeof(tmpfil));
 
        sigint = 0;
-       SIGNAL2 (SIGINT, intrser);
+       SIGNAL2(SIGINT, intrser);
 
        /*
-        * Loop through the lines of the draft skeleton.
-        */
-       for (state = FLD;;) {
-               switch (state = m_getfld (state, name, field, sizeof(field), in)) {
-                       case FLD:
-                       case FLDEOF:
-                       case FLDPLUS:
-                               /*
-                                * Check if the value of field contains anything
-                                * other than space or tab.
-                                */
-                               for (cp = field; *cp; cp++)
-                                       if (*cp != ' ' && *cp != '\t')
-                                               break;
-
-                               /* If so, just add header line to draft */
-                               if (*cp++ != '\n' || *cp != 0) {
-                                       printf ("%s:%s", name, field);
-                                       fprintf (out, "%s:%s", name, field);
-                                       while (state == FLDPLUS) {
-                                               state =
-                                                       m_getfld (state, name, field, sizeof(field), in);
-                                               printf ("%s", field);
-                                               fprintf (out, "%s", field);
-                                       }
-                               } else {
-                                       /* Else, get value of header field */
-                                       printf ("%s: ", name);
-                                       fflush (stdout);
-                                       i = getln (field, sizeof(field));
-                                       if (i == -1) {
+       ** Loop through the lines of the draft skeleton.
+       */
+       for (state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
+                       /*
+                       ** Check if the value of field contains
+                       ** anything other than space or tab.
+                       */
+                       for (cp = f.value; *cp; cp++) {
+                               if (*cp != ' ' && *cp != '\t') {
+                                       break;
+                               }
+                       }
+
+                       /* If so, just add header line to draft */
+                       if (*cp++ != '\n' || *cp) {
+                               printf("%s:%s", f.name, f.value);
+                               fprintf(out, "%s:%s", f.name, f.value);
+                       } else {
+                               /* Else, get value of header field */
+                               printf("%s: ", f.name);
+                               fflush(stdout);
+                               i = getln(buffer, sizeof(buffer));
+                               if (i == -1) {
 abort:
-                                               if (killp || erasep) {
-#ifdef HAVE_TERMIOS_H
-                                                       tcsetattr(0, TCSADRAIN, &tio);
-#else
-# ifdef HAVE_TERMIO
-                                                       ioctl (0, TCSETA, &tio);
-# else
-                                                       ioctl (0, TIOCSETN, (char *) &tio);
-# endif
-#endif
+                                       unlink(tmpfil);
+                                       exit(EX_DATAERR);
+                               }
+                               if (i || (buffer[0]!='\n' && buffer[0]!='\0')) {
+                                       fprintf(out, "%s:", f.name);
+                                       do {
+                                               if (buffer[0] != ' ' && buffer[0] != '\t') {
+                                                       putc(' ', out);
                                                }
-                                               unlink (tmpfil);
-                                               done (1);
-                                       }
-                                       if (i != 0 || (field[0] != '\n' && field[0] != 0)) {
-                                               fprintf (out, "%s:", name);
-                                               do {
-                                                       if (field[0] != ' ' && field[0] != '\t')
-                                                               putc (' ', out);
-                                                       fprintf (out, "%s", field);
-                                               } while (i == 1
-                                                                       && (i = getln (field, sizeof(field))) >= 0);
-                                               if (i == -1)
-                                                       goto abort;
+                                               fprintf(out, "%s", buffer);
+                                       } while (i == 1 && (i = getln(buffer, sizeof(buffer))) >= 0);
+                                       if (i == -1) {
+                                               goto abort;
                                        }
                                }
-
-                               if (state == FLDEOF) {  /* moby hack */
-                                       fprintf (out, "--------\n");
-                                       printf ("--------\n");
-                                       if (!body)
-                                               break;
-                                       goto no_body;
+                       }
+                       continue;
+
+               case BODY2:
+               case FILEEOF2:
+                       fprintf(out, "--------\n");
+                       if (qbody) {
+                               if (!*f.value) {
+                                       printf("--------\n");
+                                       goto has_no_body;
                                }
-                               continue;
 
-                       case BODY:
-                       case BODYEOF:
-                       case FILEEOF:
-                               if (!body)
-                                       break;
-                               fprintf (out, "--------\n");
-                               if (field[0] == 0 || !prepend)
-                                       printf ("--------\n");
-                               if (field[0]) {
-                                       if (prepend && body) {
-                                               printf ("\n--------Enter initial text\n\n");
-                                               fflush (stdout);
-                                               for (;;) {
-                                                       getln (buffer, sizeof(buffer));
-                                                       if (doteof && buffer[0] == '.' && buffer[1] == '\n')
-                                                               break;
-                                                       if (buffer[0] == 0)
-                                                               break;
-                                                       fprintf (out, "%s", buffer);
+                               if (prepend) {
+                                       printf("--------Enter initial text\n");
+                                       fflush(stdout);
+                                       for (;;) {
+                                               getln(buffer, sizeof(buffer));
+                                               if (!*buffer) {
+                                                       break;
                                                }
+                                               fprintf(out, "%s", buffer);
                                        }
-
-                                       do {
-                                               fprintf (out, "%s", field);
-                                               if (!rapid && !sigint)
-                                                       printf ("%s", field);
-                                       } while (state == BODY &&
-                                                       (state = m_getfld (state, name, field, sizeof(field), in)));
-                                       if (prepend || !body)
-                                               break;
-                                       else
-                                               printf ("\n--------Enter additional text\n\n");
-                               }
-no_body:
-                               fflush (stdout);
-                               for (;;) {
-                                       getln (field, sizeof(field));
-                                       if (doteof && field[0] == '.' && field[1] == '\n')
-                                               break;
-                                       if (field[0] == 0)
-                                               break;
-                                        fprintf (out, "%s", field);
+                               } else {
+                                       printf("--------\n");
                                }
+                       }
+
+                       if (state == BODY2) {
+                               do {
+                                       fprintf(out, "%s", f.value);
+                                       if (!rapid && !sigint) {
+                                               printf("%s", f.value);
+                                       }
+                               } while ((state = m_getfld2(state, &f, in))
+                                               ==BODY2);
+                       }
+
+                       if (prepend || !qbody) {
                                break;
+                       }
 
-                       default:
-                               adios (NULL, "skeleton is poorly formatted");
+                       printf("--------Enter additional text\n");
+has_no_body:
+                       fflush(stdout);
+                       for (;;) {
+                               getln(buffer, sizeof(buffer));
+                               if (!*buffer) {
+                                       break;
+                               }
+                               fprintf(out, "%s", buffer);
+                       }
+                       break;
+
+               default:
+                       adios(EX_DATAERR, NULL, "skeleton is poorly formatted");
                }
                break;
        }
 
-       if (body)
-               printf ("--------\n");
-
-       fflush (stdout);
-       fclose (in);
-       fclose (out);
-       SIGNAL (SIGINT, SIG_IGN);
-
-       if (killp || erasep) {
-#ifdef HAVE_TERMIOS_H
-                tcsetattr(0, TCSADRAIN, &tio);
-#else
-# ifdef HAVE_TERMIO_H
-               ioctl (0, TCSETAW, &tio);
-# else
-               ioctl (0, TIOCSETN, (char *) &tio);
-# endif
-#endif
+       if (qbody) {
+               printf("--------\n");
        }
 
-       if ((fdi = open (tmpfil, O_RDONLY)) == NOTOK)
-               adios (tmpfil, "unable to re-open");
-       if ((fdo = creat (drft, m_gmprot ())) == NOTOK)
-               adios (drft, "unable to write");
-       cpydata (fdi, fdo, tmpfil, drft);
-       close (fdi);
-       close (fdo);
-       unlink (tmpfil);
-
-       context_save ();  /* save the context file */
-       done (0);
-       return 1;
+       fflush(stdout);
+       fclose(in);
+       fclose(out);
+       SIGNAL(SIGINT, SIG_IGN);
+
+       if ((fdi = open(tmpfil, O_RDONLY)) == NOTOK) {
+               adios(EX_IOERR, tmpfil, "unable to re-open");
+       }
+       if ((fdo = creat(drft, m_gmprot())) == NOTOK) {
+               adios(EX_IOERR, drft, "unable to write");
+       }
+       cpydata(fdi, fdo, tmpfil, drft);
+       close(fdi);
+       close(fdo);
+       unlink(tmpfil);
+
+       context_save();
+       return EX_OK;
 }
 
 
 int
-getln (char *buffer, int n)
+getln(char *buffer, int n)
 {
        int c;
+       sig_atomic_t psigint = sigint;
        char *cp;
 
        cp = buffer;
-       *cp = 0;
+       *cp = '\0';
 
-       switch (setjmp (sigenv)) {
-               case OK:
-                       wtuser = 1;
-                       break;
+       switch (setjmp(sigenv)) {
+       case 0:
+               wtuser = 1;
+               break;
 
-               case DONE:
-                       wtuser = 0;
+       default:
+               wtuser = 0;
+               if (sigint == psigint) {
                        return 0;
-
-               default:
-                       wtuser = 0;
+               } else {
+                       sigint = psigint;
                        return NOTOK;
+               }
        }
 
        for (;;) {
-               switch (c = getchar ()) {
-                       case EOF:
-                               clearerr (stdin);
-                               longjmp (sigenv, DONE);
-
-                       case '\n':
-                               if (cp[-1] == QUOTE) {
-                                       cp[-1] = c;
-                                       wtuser = 0;
-                                       return 1;
-                               }
-                               *cp++ = c;
-                               *cp = 0;
+               switch (c = getchar()) {
+               case EOF:
+                       clearerr(stdin);
+                       longjmp(sigenv, DONE);
+
+               case '\n':
+                       if (cp[-1] == '\\') {
+                               cp[-1] = c;
                                wtuser = 0;
-                               return 0;
+                               return 1;
+                       }
+                       *cp++ = c;
+                       *cp = '\0';
+                       wtuser = 0;
+                       return 0;
 
-                       default:
-                               if (cp < buffer + n)
-                                       *cp++ = c;
-                               *cp = 0;
+               default:
+                       if (cp < buffer + n)
+                               *cp++ = c;
+                       *cp = '\0';
                }
        }
 }
 
 
-static RETSIGTYPE
-intrser (int i)
-{
-#ifndef RELIABLE_SIGNALS
-       SIGNAL (SIGINT, intrser);
-#endif
-
-       if (wtuser)
-               longjmp (sigenv, NOTOK);
-       sigint++;
-}
-
-
-static int
-chrcnv (char *cp)
-{
-       return (*cp != QUOTE ? *cp : m_atoi (++cp));
-}
-
-
 static void
-chrdsp (char *s, char c)
+intrser(int i)
 {
-       printf ("%s ", s);
-       if (c < ' ' || c == 0177)
-               printf ("^%c", c ^ 0100);
-       else
-               printf ("%c", c);
+       if (wtuser) {
+               close(STDIN_FILENO);
+       }
+       sigint++;
 }