3 * prompter.c -- simple prompting editor front-end
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.
12 #include <h/signals.h>
37 static struct swit switches[] = {
67 static struct termios tio;
68 # define ERASE tio.c_cc[VERASE]
69 # define KILL tio.c_cc[VKILL]
70 # define INTR tio.c_cc[VINTR]
73 static struct termio tio;
74 # define ERASE tio.c_cc[VERASE]
75 # define KILL tio.c_cc[VKILL]
76 # define INTR tio.c_cc[VINTR]
78 static struct sgttyb tio;
79 static struct tchars tc;
80 # define ERASE tio.sg_erase
81 # define KILL tio.sg_kill
82 # define INTR tc.t_intrc
86 static int wtuser = 0;
87 static int sigint = 0;
88 static jmp_buf sigenv;
93 int getln (char *, int);
94 static int chrcnv (char *);
95 static void chrdsp (char *, char);
96 static RETSIGTYPE intrser (int);
100 main (int argc, char **argv)
102 int body = 1, prepend = 1, rapid = 0;
103 int doteof = 0, fdi, fdo, i, state;
104 char *cp, *drft = NULL, *erasep = NULL;
105 char *killp = NULL, name[NAMESZ], field[BUFSIZ];
106 char buffer[BUFSIZ], tmpfil[BUFSIZ];
107 char **arguments, **argp;
112 setlocale(LC_ALL, "");
114 invo_name = r1bindex (argv[0], '/');
116 /* read user profile/context */
119 arguments = getarguments (invo_name, argc, argv, 1);
122 while ((cp = *argp++))
124 switch (smatch (++cp, switches)) {
126 ambigsw (cp, switches);
129 adios (NULL, "-%s unknown", cp);
132 snprintf (buffer, sizeof(buffer), "%s [switches] file",
134 print_help (buffer, switches, 1);
137 print_version(invo_name);
141 if (!(erasep = *argp++) || *erasep == '-')
142 adios (NULL, "missing argument to %s", argp[-2]);
145 if (!(killp = *argp++) || *killp == '-')
146 adios (NULL, "missing argument to %s", argp[-2]);
183 adios (NULL, "usage: %s [switches] file", invo_name);
184 if ((in = fopen (drft, "r")) == NULL)
185 adios (drft, "unable to open");
187 tfile = m_mktemp2(NULL, invo_name, NULL, &out);
188 if (tfile == NULL) adios("prompter", "unable to create temporary file");
189 chmod (tmpfil, 0600);
190 strncpy (tmpfil, tfile, sizeof(tmpfil));
193 * Are we changing the kill or erase character?
195 if (killp || erasep) {
196 #ifdef HAVE_TERMIOS_H
197 cc_t save_erase, save_kill;
199 int save_erase, save_kill;
202 /* get the current terminal attributes */
203 #ifdef HAVE_TERMIOS_H
206 # ifdef HAVE_TERMIO_H
207 ioctl(0, TCGETA, &tio);
209 ioctl (0, TIOCGETP, (char *) &tio);
210 ioctl (0, TIOCGETC, (char *) &tc);
214 /* save original kill, erase character for later */
218 /* set new kill, erase character in terminal structure */
219 KILL = killp ? chrcnv (killp) : save_kill;
220 ERASE = erasep ? chrcnv (erasep) : save_erase;
222 /* set the new terminal attributes */
223 #ifdef HAVE_TERMIOS_H
224 tcsetattr(0, TCSADRAIN, &tio);
226 # ifdef HAVE_TERMIO_H
227 ioctl(0, TCSETAW, &tio);
229 ioctl (0, TIOCSETN, (char *) &tio);
233 /* print out new kill erase characters */
234 chrdsp ("erase", ERASE);
235 chrdsp (", kill", KILL);
236 chrdsp (", intr", INTR);
241 * We set the kill and erase character back to original
242 * setup in terminal structure so we can easily
243 * restore it upon exit.
250 SIGNAL2 (SIGINT, intrser);
253 * Loop through the lines of the draft skeleton.
255 for (state = FLD;;) {
256 switch (state = m_getfld (state, name, field, sizeof(field), in)) {
261 * Check if the value of field contains anything
262 * other than space or tab.
264 for (cp = field; *cp; cp++)
265 if (*cp != ' ' && *cp != '\t')
268 /* If so, just add header line to draft */
269 if (*cp++ != '\n' || *cp != 0) {
270 printf ("%s:%s", name, field);
271 fprintf (out, "%s:%s", name, field);
272 while (state == FLDPLUS) {
274 m_getfld (state, name, field, sizeof(field), in);
275 printf ("%s", field);
276 fprintf (out, "%s", field);
279 /* Else, get value of header field */
280 printf ("%s: ", name);
282 i = getln (field, sizeof(field));
285 if (killp || erasep) {
286 #ifdef HAVE_TERMIOS_H
287 tcsetattr(0, TCSADRAIN, &tio);
290 ioctl (0, TCSETA, &tio);
292 ioctl (0, TIOCSETN, (char *) &tio);
299 if (i != 0 || (field[0] != '\n' && field[0] != 0)) {
300 fprintf (out, "%s:", name);
302 if (field[0] != ' ' && field[0] != '\t')
304 fprintf (out, "%s", field);
306 && (i = getln (field, sizeof(field))) >= 0);
312 if (state == FLDEOF) { /* moby hack */
313 fprintf (out, "--------\n");
314 printf ("--------\n");
326 fprintf (out, "--------\n");
327 if (field[0] == 0 || !prepend)
328 printf ("--------\n");
330 if (prepend && body) {
331 printf ("\n--------Enter initial text\n\n");
334 getln (buffer, sizeof(buffer));
335 if (doteof && buffer[0] == '.' && buffer[1] == '\n')
339 fprintf (out, "%s", buffer);
344 fprintf (out, "%s", field);
345 if (!rapid && !sigint)
346 printf ("%s", field);
347 } while (state == BODY &&
348 (state = m_getfld (state, name, field, sizeof(field), in)));
349 if (prepend || !body)
352 printf ("\n--------Enter additional text\n\n");
357 getln (field, sizeof(field));
358 if (doteof && field[0] == '.' && field[1] == '\n')
362 fprintf (out, "%s", field);
367 adios (NULL, "skeleton is poorly formatted");
373 printf ("--------\n");
378 SIGNAL (SIGINT, SIG_IGN);
380 if (killp || erasep) {
381 #ifdef HAVE_TERMIOS_H
382 tcsetattr(0, TCSADRAIN, &tio);
384 # ifdef HAVE_TERMIO_H
385 ioctl (0, TCSETAW, &tio);
387 ioctl (0, TIOCSETN, (char *) &tio);
392 if ((fdi = open (tmpfil, O_RDONLY)) == NOTOK)
393 adios (tmpfil, "unable to re-open");
394 if ((fdo = creat (drft, m_gmprot ())) == NOTOK)
395 adios (drft, "unable to write");
396 cpydata (fdi, fdo, tmpfil, drft);
401 context_save (); /* save the context file */
408 getln (char *buffer, int n)
416 switch (setjmp (sigenv)) {
431 switch (c = getchar ()) {
434 longjmp (sigenv, DONE);
437 if (cp[-1] == QUOTE) {
459 #ifndef RELIABLE_SIGNALS
460 SIGNAL (SIGINT, intrser);
464 longjmp (sigenv, NOTOK);
472 return (*cp != QUOTE ? *cp : m_atoi (++cp));
477 chrdsp (char *s, char c)
480 if (c < ' ' || c == 0177)
481 printf ("^%c", c ^ 0100);