]> diplodocus.org Git - nmh/blob - uip/prompter.c
Removed temporary probes added in commit
[nmh] / uip / prompter.c
1
2 /*
3 * prompter.c -- simple prompting editor front-end
4 *
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
8 */
9
10 #include <h/mh.h>
11 #include <fcntl.h>
12 #include <h/signals.h>
13 #include <setjmp.h>
14
15 #include <termios.h>
16
17 #define QUOTE '\\'
18
19 #ifndef CKILL
20 # define CKILL '@'
21 #endif
22
23 #ifndef CERASE
24 # define CERASE '#'
25 #endif
26
27 #define PROMPTER_SWITCHES \
28 X("erase chr", 0, ERASESW) \
29 X("kill chr", 0, KILLSW) \
30 X("prepend", 0, PREPSW) \
31 X("noprepend", 0, NPREPSW) \
32 X("rapid", 0, RAPDSW) \
33 X("norapid", 0, NRAPDSW) \
34 X("body", -4, BODYSW) \
35 X("nobody", -6, NBODYSW) \
36 X("doteof", 0, DOTSW) \
37 X("nodoteof", 0, NDOTSW) \
38 X("version", 0, VERSIONSW) \
39 X("help", 0, HELPSW) \
40
41 #define X(sw, minchars, id) id,
42 DEFINE_SWITCH_ENUM(PROMPTER);
43 #undef X
44
45 #define X(sw, minchars, id) { sw, minchars, id },
46 DEFINE_SWITCH_ARRAY(PROMPTER, switches);
47 #undef X
48
49
50 static struct termios tio;
51 #define ERASE tio.c_cc[VERASE]
52 #define KILL tio.c_cc[VKILL]
53 #define INTR tio.c_cc[VINTR]
54
55 static int wtuser = 0;
56 static int sigint = 0;
57 static jmp_buf sigenv;
58
59 /*
60 * prototypes
61 */
62 int getln (char *, int);
63 static int chrcnv (char *);
64 static void chrdsp (char *, char);
65 static void intrser (int);
66
67
68 int
69 main (int argc, char **argv)
70 {
71 int body = 1, prepend = 1, rapid = 0;
72 int doteof = 0, fdi, fdo, i, state;
73 char *cp, *drft = NULL, *erasep = NULL;
74 char *killp = NULL, name[NAMESZ], field[BUFSIZ];
75 char buffer[BUFSIZ], tmpfil[BUFSIZ];
76 char **arguments, **argp;
77 FILE *in, *out;
78 char *tfile = NULL;
79 m_getfld_state_t gstate = 0;
80
81 #ifdef LOCALE
82 setlocale(LC_ALL, "");
83 #endif
84 invo_name = r1bindex (argv[0], '/');
85
86 /* read user profile/context */
87 context_read();
88
89 arguments = getarguments (invo_name, argc, argv, 1);
90 argp = arguments;
91
92 while ((cp = *argp++))
93 if (*cp == '-') {
94 switch (smatch (++cp, switches)) {
95 case AMBIGSW:
96 ambigsw (cp, switches);
97 done (1);
98 case UNKWNSW:
99 adios (NULL, "-%s unknown", cp);
100
101 case HELPSW:
102 snprintf (buffer, sizeof(buffer), "%s [switches] file",
103 invo_name);
104 print_help (buffer, switches, 1);
105 done (0);
106 case VERSIONSW:
107 print_version(invo_name);
108 done (0);
109
110 case ERASESW:
111 if (!(erasep = *argp++) || *erasep == '-')
112 adios (NULL, "missing argument to %s", argp[-2]);
113 continue;
114 case KILLSW:
115 if (!(killp = *argp++) || *killp == '-')
116 adios (NULL, "missing argument to %s", argp[-2]);
117 continue;
118
119 case PREPSW:
120 prepend++;
121 continue;
122 case NPREPSW:
123 prepend = 0;
124 continue;
125
126 case RAPDSW:
127 rapid++;
128 continue;
129 case NRAPDSW:
130 rapid = 0;
131 continue;
132
133 case BODYSW:
134 body++;
135 continue;
136 case NBODYSW:
137 body = 0;
138 continue;
139
140 case DOTSW:
141 doteof++;
142 continue;
143 case NDOTSW:
144 doteof = 0;
145 continue;
146 }
147 } else {
148 if (!drft)
149 drft = cp;
150 }
151
152 if (!drft)
153 adios (NULL, "usage: %s [switches] file", invo_name);
154 if ((in = fopen (drft, "r")) == NULL)
155 adios (drft, "unable to open");
156
157 tfile = m_mktemp2(NULL, invo_name, NULL, &out);
158 if (tfile == NULL) adios("prompter", "unable to create temporary file");
159 chmod (tmpfil, 0600);
160 strncpy (tmpfil, tfile, sizeof(tmpfil));
161
162 /*
163 * Are we changing the kill or erase character?
164 */
165 if (killp || erasep) {
166 cc_t save_erase, save_kill;
167
168 /* get the current terminal attributes */
169 tcgetattr(0, &tio);
170
171 /* save original kill, erase character for later */
172 save_kill = KILL;
173 save_erase = ERASE;
174
175 /* set new kill, erase character in terminal structure */
176 KILL = killp ? chrcnv (killp) : save_kill;
177 ERASE = erasep ? chrcnv (erasep) : save_erase;
178
179 /* set the new terminal attributes */
180 tcsetattr(0, TCSADRAIN, &tio);
181
182 /* print out new kill erase characters */
183 chrdsp ("erase", ERASE);
184 chrdsp (", kill", KILL);
185 chrdsp (", intr", INTR);
186 putchar ('\n');
187 fflush (stdout);
188
189 /*
190 * We set the kill and erase character back to original
191 * setup in terminal structure so we can easily
192 * restore it upon exit.
193 */
194 KILL = save_kill;
195 ERASE = save_erase;
196 }
197
198 sigint = 0;
199 SIGNAL2 (SIGINT, intrser);
200
201 /*
202 * Loop through the lines of the draft skeleton.
203 */
204 for (;;) {
205 int fieldsz = sizeof field;
206 switch (state = m_getfld (&gstate, name, field, &fieldsz, in)) {
207 case FLD:
208 case FLDPLUS:
209 /*
210 * Check if the value of field contains anything
211 * other than space or tab.
212 */
213 for (cp = field; *cp; cp++)
214 if (*cp != ' ' && *cp != '\t')
215 break;
216
217 /* If so, just add header line to draft */
218 if (*cp++ != '\n' || *cp != 0) {
219 printf ("%s:%s", name, field);
220 fprintf (out, "%s:%s", name, field);
221 while (state == FLDPLUS) {
222 fieldsz = sizeof field;
223 state = m_getfld (&gstate, name, field, &fieldsz, in);
224 printf ("%s", field);
225 fprintf (out, "%s", field);
226 }
227 } else {
228 /* Else, get value of header field */
229 printf ("%s: ", name);
230 fflush (stdout);
231 i = getln (field, sizeof(field));
232 if (i == -1) {
233 abort:
234 if (killp || erasep) {
235 tcsetattr(0, TCSADRAIN, &tio);
236 }
237 unlink (tmpfil);
238 done (1);
239 }
240 if (i != 0 || (field[0] != '\n' && field[0] != 0)) {
241 fprintf (out, "%s:", name);
242 do {
243 if (field[0] != ' ' && field[0] != '\t')
244 putc (' ', out);
245 fprintf (out, "%s", field);
246 } while (i == 1
247 && (i = getln (field, sizeof(field))) >= 0);
248 if (i == -1)
249 goto abort;
250 }
251 }
252
253 continue;
254
255 case BODY:
256 case FILEEOF:
257 if (!body)
258 break;
259 fprintf (out, "--------\n");
260 if (field[0] == 0 || !prepend)
261 printf ("--------\n");
262 if (field[0]) {
263 if (prepend && body) {
264 printf ("\n--------Enter initial text\n\n");
265 fflush (stdout);
266 for (;;) {
267 getln (buffer, sizeof(buffer));
268 if (doteof && buffer[0] == '.' && buffer[1] == '\n')
269 break;
270 if (buffer[0] == 0)
271 break;
272 fprintf (out, "%s", buffer);
273 }
274 }
275
276 do {
277 fprintf (out, "%s", field);
278 if (!rapid && !sigint)
279 printf ("%s", field);
280 } while (state == BODY &&
281 (fieldsz = sizeof field,
282 state = m_getfld (&gstate, name, field, &fieldsz, in)));
283 if (prepend || !body)
284 break;
285 else
286 printf ("\n--------Enter additional text\n\n");
287 }
288
289 fflush (stdout);
290 for (;;) {
291 getln (field, sizeof(field));
292 if (doteof && field[0] == '.' && field[1] == '\n')
293 break;
294 if (field[0] == 0)
295 break;
296 fprintf (out, "%s", field);
297 }
298 break;
299
300 default:
301 adios (NULL, "skeleton is poorly formatted");
302 }
303 break;
304 }
305 m_getfld_state_destroy (&gstate);
306
307 if (body)
308 printf ("--------\n");
309
310 fflush (stdout);
311 fclose (in);
312 fclose (out);
313 SIGNAL (SIGINT, SIG_IGN);
314
315 if (killp || erasep) {
316 tcsetattr(0, TCSADRAIN, &tio);
317 }
318
319 if ((fdi = open (tmpfil, O_RDONLY)) == NOTOK)
320 adios (tmpfil, "unable to re-open");
321 if ((fdo = creat (drft, m_gmprot ())) == NOTOK)
322 adios (drft, "unable to write");
323 cpydata (fdi, fdo, tmpfil, drft);
324 close (fdi);
325 close (fdo);
326 unlink (tmpfil);
327
328 context_save (); /* save the context file */
329 done (0);
330 return 1;
331 }
332
333
334 int
335 getln (char *buffer, int n)
336 {
337 int c;
338 char *cp;
339
340 cp = buffer;
341 *cp = 0;
342
343 switch (setjmp (sigenv)) {
344 case OK:
345 wtuser = 1;
346 break;
347
348 case DONE:
349 wtuser = 0;
350 return 0;
351
352 default:
353 wtuser = 0;
354 return NOTOK;
355 }
356
357 for (;;) {
358 switch (c = getchar ()) {
359 case EOF:
360 clearerr (stdin);
361 longjmp (sigenv, DONE);
362
363 case '\n':
364 if (cp[-1] == QUOTE) {
365 cp[-1] = c;
366 wtuser = 0;
367 return 1;
368 }
369 *cp++ = c;
370 *cp = 0;
371 wtuser = 0;
372 return 0;
373
374 default:
375 if (cp < buffer + n)
376 *cp++ = c;
377 *cp = 0;
378 }
379 }
380 }
381
382
383 static void
384 intrser (int i)
385 {
386 NMH_UNUSED (i);
387
388 if (wtuser)
389 longjmp (sigenv, NOTOK);
390 sigint++;
391 }
392
393
394 static int
395 chrcnv (char *cp)
396 {
397 return (*cp != QUOTE ? *cp : m_atoi (++cp));
398 }
399
400
401 static void
402 chrdsp (char *s, char c)
403 {
404 printf ("%s ", s);
405 if (c < ' ' || c == 0177)
406 printf ("^%c", c ^ 0100);
407 else
408 printf ("%c", c);
409 }