Merge branch 'master' of ssh://marmaro.de:443/var/git/mmh
[mmh] / uip / prompter.c
1 /*
2 ** prompter.c -- simple prompting editor front-end
3 **
4 ** This code is Copyright (c) 2002, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <fcntl.h>
11 #include <h/signals.h>
12 #include <errno.h>
13 #include <signal.h>
14 #include <setjmp.h>
15
16 static struct swit switches[] = {
17 #define PREPSW  0
18         { "prepend", 0 },
19 #define NPREPSW  1
20         { "noprepend", 2 },
21 #define RAPDSW  2
22         { "rapid", 0 },
23 #define NRAPDSW  3
24         { "norapid", 2 },
25 #define BODYSW  4
26         { "body", 0 },
27 #define NBODYSW  5
28         { "nobody", 2 },
29 #define VERSIONSW 6
30         { "Version", 0 },
31 #define HELPSW  7
32         { "help", 0 },
33         { NULL, 0 }
34 };
35
36
37 static int wtuser = 0;
38 static int sigint = 0;
39 static jmp_buf sigenv;
40
41 /*
42 ** prototypes
43 */
44 int getln(char *, int);
45 static void intrser(int);
46
47
48 int
49 main(int argc, char **argv)
50 {
51         int qbody = 1, prepend = 1, rapid = 0;
52         int fdi, fdo, i, state;
53         char *cp, *drft = NULL;
54         char name[NAMESZ], field[BUFSIZ];
55         char buffer[BUFSIZ], tmpfil[BUFSIZ];
56         char **arguments, **argp;
57         FILE *in, *out;
58         char *tfile = NULL;
59
60         setlocale(LC_ALL, "");
61         invo_name = mhbasename(argv[0]);
62
63         /* read user profile/context */
64         context_read();
65
66         arguments = getarguments(invo_name, argc, argv, 1);
67         argp = arguments;
68
69         while ((cp = *argp++)) {
70                 if (*cp == '-') {
71                         switch (smatch(++cp, switches)) {
72                         case AMBIGSW:
73                                 ambigsw(cp, switches);
74                                 exit(1);
75                         case UNKWNSW:
76                                 adios(NULL, "-%s unknown", cp);
77
78                         case HELPSW:
79                                 snprintf(buffer, sizeof(buffer),
80                                                 "%s [switches] file",
81                                                 invo_name);
82                                 print_help(buffer, switches, 1);
83                                 exit(0);
84                         case VERSIONSW:
85                                 print_version(invo_name);
86                                 exit(0);
87
88                         case PREPSW:
89                                 prepend++;
90                                 continue;
91                         case NPREPSW:
92                                 prepend = 0;
93                                 continue;
94
95                         case RAPDSW:
96                                 rapid++;
97                                 continue;
98                         case NRAPDSW:
99                                 rapid = 0;
100                                 continue;
101
102                         case BODYSW:
103                                 qbody++;
104                                 continue;
105                         case NBODYSW:
106                                 qbody = 0;
107                                 continue;
108                         }
109                 } else if (!drft) {
110                         drft = cp;
111                 }
112         }
113
114         if (!drft)
115                 adios(NULL, "usage: %s [switches] file", invo_name);
116         if ((in = fopen(drft, "r")) == NULL)
117                 adios(drft, "unable to open");
118
119         tfile = m_mktemp2(NULL, invo_name, NULL, &out);
120         if (tfile == NULL)
121                 adios("prompter", "unable to create temporary file");
122         chmod(tmpfil, 0600);
123         strncpy(tmpfil, tfile, sizeof(tmpfil));
124
125         sigint = 0;
126         SIGNAL2(SIGINT, intrser);
127
128         /*
129         ** Loop through the lines of the draft skeleton.
130         */
131         for (state = FLD;;) {
132                 switch (state = m_getfld(state, name, field, sizeof(field),
133                                 in)) {
134                 case FLD:
135                 case FLDEOF:
136                 case FLDPLUS:
137                         /*
138                         ** Check if the value of field contains
139                         ** anything other than space or tab.
140                         */
141                         for (cp = field; *cp; cp++)
142                                 if (*cp != ' ' && *cp != '\t')
143                                         break;
144
145                         /* If so, just add header line to draft */
146                         if (*cp++ != '\n' || *cp) {
147                                 printf("%s:%s", name, field);
148                                 fprintf(out, "%s:%s", name, field);
149                                 while (state == FLDPLUS) {
150                                         state = m_getfld(state, name, field,
151                                                         sizeof(field), in);
152                                         printf("%s", field);
153                                         fprintf(out, "%s", field);
154                                 }
155                         } else {
156                                 /* Else, get value of header field */
157                                 printf("%s: ", name);
158                                 fflush(stdout);
159                                 i = getln(field, sizeof(field));
160                                 if (i == -1) {
161 abort:
162                                         unlink(tmpfil);
163                                         /* sysexits.h EX_DATAERR */
164                                         exit(1);
165                                 }
166                                 if (i || (field[0]!='\n' && field[0]!='\0')) {
167                                         fprintf(out, "%s:", name);
168                                         do {
169                                                 if (field[0] != ' ' && field[0] != '\t')
170                                                         putc(' ', out);
171                                                 fprintf(out, "%s", field);
172                                         } while (i == 1 && (i = getln(field, sizeof(field))) >= 0);
173                                         if (i == -1)
174                                                 goto abort;
175                                 }
176                         }
177
178                         if (state == FLDEOF) {  /* moby hack */
179                                 /* draft has no body separator; only headers */
180                                 fprintf(out, "--------\n");
181                                 if (!qbody)
182                                         break;
183                                 printf("--------\n");
184                                 goto has_no_body;
185                         }
186                         continue;
187
188                 case BODY:
189                 case BODYEOF:
190                 case FILEEOF:
191                         fprintf(out, "--------\n");
192                         if (qbody) {
193                                 if (!*field) {
194                                         printf("--------\n");
195                                         goto has_no_body;
196                                 }
197
198                                 if (prepend) {
199                                         printf("--------Enter initial text\n");
200                                         fflush(stdout);
201                                         for (;;) {
202                                                 getln(buffer, sizeof(buffer));
203                                                 if (!*buffer)
204                                                         break;
205                                                 fprintf(out, "%s", buffer);
206                                         }
207                                 } else {
208                                         printf("--------\n");
209                                 }
210                         }
211
212                         do {
213                                 fprintf(out, "%s", field);
214                                 if (!rapid && !sigint)
215                                         printf("%s", field);
216                         } while (state == BODY &&
217                                         (state = m_getfld(state, name,
218                                         field, sizeof(field), in)));
219
220                         if (prepend || !qbody)
221                                 break;
222
223                         printf("--------Enter additional text\n");
224 has_no_body:
225                         fflush(stdout);
226                         for (;;) {
227                                 getln(field, sizeof(field));
228                                 if (!*field)
229                                         break;
230                                 fprintf(out, "%s", field);
231                         }
232                         break;
233
234                 default:
235                         adios(NULL, "skeleton is poorly formatted");
236                 }
237                 break;
238         }
239
240         if (qbody)
241                 printf("--------\n");
242
243         fflush(stdout);
244         fclose(in);
245         fclose(out);
246         SIGNAL(SIGINT, SIG_IGN);
247
248         if ((fdi = open(tmpfil, O_RDONLY)) == NOTOK)
249                 adios(tmpfil, "unable to re-open");
250         if ((fdo = creat(drft, m_gmprot())) == NOTOK)
251                 adios(drft, "unable to write");
252         cpydata(fdi, fdo, tmpfil, drft);
253         close(fdi);
254         close(fdo);
255         unlink(tmpfil);
256
257         context_save();  /* save the context file */
258         return 0;
259 }
260
261
262 int
263 getln(char *buffer, int n)
264 {
265         int c;
266         char *cp;
267
268         cp = buffer;
269         *cp = '\0';
270
271         switch (setjmp(sigenv)) {
272         case 0:
273                 wtuser = 1;
274                 break;
275
276         case DONE:
277                 wtuser = 0;
278                 return 0;
279
280         default:
281                 wtuser = 0;
282                 return NOTOK;
283         }
284
285         for (;;) {
286                 switch (c = getchar()) {
287                 case EOF:
288                         clearerr(stdin);
289                         longjmp(sigenv, DONE);
290
291                 case '\n':
292                         if (cp[-1] == '\\') {
293                                 cp[-1] = c;
294                                 wtuser = 0;
295                                 return 1;
296                         }
297                         *cp++ = c;
298                         *cp = '\0';
299                         wtuser = 0;
300                         return 0;
301
302                 default:
303                         if (cp < buffer + n)
304                                 *cp++ = c;
305                         *cp = '\0';
306                 }
307         }
308 }
309
310
311 static void
312 intrser(int i)
313 {
314         if (wtuser)
315                 longjmp(sigenv, NOTOK);
316         sigint++;
317 }