Fix uip/whom.c for C89 compatibility
[mmh] / uip / prompter.c
index 6db0455..7f71e02 100644 (file)
 #include <errno.h>
 #include <signal.h>
 #include <setjmp.h>
-
-#include <termios.h>
-
-#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
+#define NRAPDSW  3
+       { "norapid", 2 },
+#define BODYSW  4
+       { "body", 0 },
+#define NBODYSW  5
+       { "nobody", 2 },
+#define VERSIONSW 6
        { "Version", 0 },
-#define HELPSW  11
+#define HELPSW  7
        { "help", 0 },
        { NULL, 0 }
 };
 
+char *version=VERSION;
 
-static struct termios tio;
-#define ERASE tio.c_cc[VERASE]
-#define KILL  tio.c_cc[VKILL]
-#define INTR  tio.c_cc[VINTR]
-
-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 void intrser(int);
 
 
 int
 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 = {{0}};
        char buffer[BUFSIZ], tmpfil[BUFSIZ];
        char **arguments, **argp;
        FILE *in, *out;
        char *tfile = NULL;
 
-#ifdef LOCALE
        setlocale(LC_ALL, "");
-#endif
        invo_name = mhbasename(argv[0]);
 
        /* read user profile/context */
@@ -95,35 +73,25 @@ main(int argc, char **argv)
        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);
+                               exit(EX_USAGE);
                        case UNKWNSW:
-                               adios(NULL, "-%s unknown", cp);
+                               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);
+                               exit(argc == 2 ? EX_OK : EX_USAGE);
+
                        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;
+                               exit(argc == 2 ? EX_OK : EX_USAGE);
 
                        case PREPSW:
                                prepend++;
@@ -140,208 +108,167 @@ main(int argc, char **argv)
                                continue;
 
                        case BODYSW:
-                               body++;
+                               qbody++;
                                continue;
                        case NBODYSW:
-                               body = 0;
-                               continue;
-
-                       case DOTSW:
-                               doteof++;
-                               continue;
-                       case NDOTSW:
-                               doteof = 0;
+                               qbody = 0;
                                continue;
                        }
                } 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");
+       if (tfile == NULL) {
+               adios(EX_CANTCREAT, "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) {
-               cc_t save_erase, save_kill;
-
-               /* get the current terminal attributes */
-               tcgetattr(0, &tio);
-
-               /* 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 */
-                tcsetattr(0, TCSADRAIN, &tio);
-
-               /* 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;
-       }
-
        sigint = 0;
        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:
+       for (state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case LENERR2:
+                       state = FLD2;
+                       /* FALL */
+
+               case FLD2:
                        /*
                        ** Check if the value of field contains
                        ** anything other than space or tab.
                        */
-                       for (cp = field; *cp; cp++)
-                               if (*cp != ' ' && *cp != '\t')
+                       for (cp = f.value; *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);
-                               }
+                       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: ", name);
+                               printf("%s: ", f.name);
                                fflush(stdout);
-                               i = getln(field, sizeof(field));
+                               i = getln(buffer, sizeof(buffer));
                                if (i == -1) {
 abort:
-                                       if (killp || erasep) {
-                                               tcsetattr(0, TCSADRAIN, &tio);
-                                       }
                                        unlink(tmpfil);
-                                       done(1);
+                                       exit(EX_DATAERR);
                                }
-                               if (i != 0 || (field[0] != '\n' && field[0] != 0)) {
-                                       fprintf(out, "%s:", name);
+                               if (i || (buffer[0]!='\n' && buffer[0]!='\0')) {
+                                       fprintf(out, "%s:", f.name);
                                        do {
-                                               if (field[0] != ' ' && field[0] != '\t')
+                                               if (buffer[0] != ' ' && buffer[0] != '\t') {
                                                        putc(' ', out);
-                                               fprintf(out, "%s", field);
-                                       } while (i == 1 && (i = getln(field, sizeof(field))) >= 0);
-                                       if (i == -1)
+                                               }
+                                               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 BODY:
-               case BODYEOF:
-               case FILEEOF:
-                       if (!body)
-                               break;
+               case BODY2:
+               case FILEEOF2:
                        fprintf(out, "--------\n");
-                       if (field[0] == 0 || !prepend)
-                               printf("--------\n");
-                       if (field[0]) {
-                               if (prepend && body) {
-                                       printf("\n--------Enter initial text\n\n");
+                       if (qbody) {
+                               if (f.value == NULL) {
+                                       printf("--------\n");
+                                       goto has_no_body;
+                               }
+
+                               if (prepend) {
+                                       printf("--------Enter initial text\n");
                                        fflush(stdout);
                                        for (;;) {
                                                getln(buffer, sizeof(buffer));
-                                               if (doteof && buffer[0] == '.' && buffer[1] == '\n')
-                                                       break;
-                                               if (buffer[0] == 0)
+                                               if (!*buffer) {
                                                        break;
+                                               }
                                                fprintf(out, "%s", buffer);
                                        }
+                               } else {
+                                       printf("--------\n");
                                }
+                       }
 
+                       if (state == BODY2) {
                                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");
+                                       fprintf(out, "%s", f.value);
+                                       if (!rapid && !sigint) {
+                                               printf("%s", f.value);
+                                       }
+                               } while ((state = m_getfld2(state, &f, in))
+                                               ==BODY2);
+                               if (state != FILEEOF2) {
+                                       adios(EX_IOERR, "m_getfld2", "io error");
+                               }
+                       }
+
+                       if (prepend || !qbody) {
+                               break;
                        }
-no_body:
+
+                       printf("--------Enter additional text\n");
+has_no_body:
                        fflush(stdout);
                        for (;;) {
-                               getln(field, sizeof(field));
-                               if (doteof && field[0] == '.' && field[1] == '\n')
-                                       break;
-                               if (field[0] == 0)
+                               getln(buffer, sizeof(buffer));
+                               if (!*buffer) {
                                        break;
-                                fprintf(out, "%s", field);
+                               }
+                               fprintf(out, "%s", buffer);
                        }
                        break;
 
+               case FMTERR2:
+                       advise(NULL, "skeleton is poorly formatted");
+                       continue;
                default:
-                       adios(NULL, "skeleton is poorly formatted");
+                       adios(EX_IOERR, "m_getfld2", "io error");
                }
                break;
        }
 
-       if (body)
+       if (qbody) {
                printf("--------\n");
+       }
 
        fflush(stdout);
        fclose(in);
        fclose(out);
        SIGNAL(SIGINT, SIG_IGN);
 
-       if (killp || erasep) {
-                tcsetattr(0, TCSADRAIN, &tio);
+       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");
        }
-
-       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;
+       context_save();
+       return EX_OK;
 }
 
 
@@ -349,23 +276,25 @@ int
 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:
+       case 0:
                wtuser = 1;
                break;
 
-       case DONE:
-               wtuser = 0;
-               return 0;
-
        default:
                wtuser = 0;
-               return NOTOK;
+               if (sigint == psigint) {
+                       return 0;
+               } else {
+                       sigint = psigint;
+                       return NOTOK;
+               }
        }
 
        for (;;) {
@@ -375,20 +304,20 @@ getln(char *buffer, int n)
                        longjmp(sigenv, DONE);
 
                case '\n':
-                       if (cp[-1] == QUOTE) {
+                       if (cp[-1] == '\\') {
                                cp[-1] = c;
                                wtuser = 0;
                                return 1;
                        }
                        *cp++ = c;
-                       *cp = 0;
+                       *cp = '\0';
                        wtuser = 0;
                        return 0;
 
                default:
                        if (cp < buffer + n)
                                *cp++ = c;
-                       *cp = 0;
+                       *cp = '\0';
                }
        }
 }
@@ -397,25 +326,8 @@ getln(char *buffer, int n)
 static void
 intrser(int i)
 {
-       if (wtuser)
-               longjmp(sigenv, NOTOK);
+       if (wtuser) {
+               close(STDIN_FILENO);
+       }
        sigint++;
 }
-
-
-static int
-chrcnv(char *cp)
-{
-       return (*cp != QUOTE ? *cp : m_atoi(++cp));
-}
-
-
-static void
-chrdsp(char *s, char c)
-{
-       printf("%s ", s);
-       if (c < ' ' || c == 0177)
-               printf("^%c", c ^ 0100);
-       else
-               printf("%c", c);
-}