ncurses 5.9 - patch 20141018
[ncurses.git] / progs / tput.c
1 /****************************************************************************
2  * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28
29 /****************************************************************************
30  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32  *     and: Thomas E. Dickey                        1996-on                 *
33  ****************************************************************************/
34
35 /*
36  * tput.c -- shellscript access to terminal capabilities
37  *
38  * by Eric S. Raymond <esr@snark.thyrsus.com>, portions based on code from
39  * Ross Ridge's mytinfo package.
40  */
41
42 #include <tparm_type.h>
43
44 #if !PURE_TERMINFO
45 #include <dump_entry.h>
46 #include <termsort.c>
47 #endif
48 #include <transform.h>
49
50 MODULE_ID("$Id: tput.c,v 1.50 2014/05/21 16:57:16 tom Exp $")
51
52 #define PUTS(s)         fputs(s, stdout)
53 #define PUTCHAR(c)      putchar(c)
54 #define FLUSH           fflush(stdout)
55
56 static char *prg_name;
57 static bool is_init = FALSE;
58 static bool is_reset = FALSE;
59
60 static void
61 quit(int status, const char *fmt,...)
62 {
63     va_list argp;
64
65     va_start(argp, fmt);
66     fprintf(stderr, "%s: ", prg_name);
67     vfprintf(stderr, fmt, argp);
68     fprintf(stderr, "\n");
69     va_end(argp);
70     ExitProgram(status);
71 }
72
73 static void
74 usage(void)
75 {
76     fprintf(stderr, "usage: %s [-V] [-S] [-T term] capname\n", prg_name);
77     ExitProgram(EXIT_FAILURE);
78 }
79
80 static void
81 check_aliases(const char *name)
82 {
83     is_init = same_program(name, PROG_INIT);
84     is_reset = same_program(name, PROG_RESET);
85 }
86
87 static int
88 exit_code(int token, int value)
89 {
90     int result = 99;
91
92     switch (token) {
93     case BOOLEAN:
94         result = !value;        /* TRUE=0, FALSE=1 */
95         break;
96     case NUMBER:
97         result = 0;             /* always zero */
98         break;
99     case STRING:
100         result = value;         /* 0=normal, 1=missing */
101         break;
102     }
103     return result;
104 }
105
106 static int
107 tput(int argc, char *argv[])
108 {
109     NCURSES_CONST char *name;
110     char *s;
111     int i, j, c;
112     int status;
113     FILE *f;
114 #if !PURE_TERMINFO
115     bool termcap = FALSE;
116 #endif
117
118     if ((name = argv[0]) == 0)
119         name = "";
120     check_aliases(name);
121     if (is_reset || is_init) {
122         if (init_prog != 0) {
123             system(init_prog);
124         }
125         FLUSH;
126
127         if (is_reset && reset_1string != 0) {
128             PUTS(reset_1string);
129         } else if (init_1string != 0) {
130             PUTS(init_1string);
131         }
132         FLUSH;
133
134         if (is_reset && reset_2string != 0) {
135             PUTS(reset_2string);
136         } else if (init_2string != 0) {
137             PUTS(init_2string);
138         }
139         FLUSH;
140
141 #ifdef set_lr_margin
142         if (set_lr_margin != 0) {
143             PUTS(TPARM_2(set_lr_margin, 0, columns - 1));
144         } else
145 #endif
146 #ifdef set_left_margin_parm
147             if (set_left_margin_parm != 0
148                 && set_right_margin_parm != 0) {
149             PUTS(TPARM_1(set_left_margin_parm, 0));
150             PUTS(TPARM_1(set_right_margin_parm, columns - 1));
151         } else
152 #endif
153             if (clear_margins != 0
154                 && set_left_margin != 0
155                 && set_right_margin != 0) {
156             PUTS(clear_margins);
157             if (carriage_return != 0) {
158                 PUTS(carriage_return);
159             } else {
160                 PUTCHAR('\r');
161             }
162             PUTS(set_left_margin);
163             if (parm_right_cursor) {
164                 PUTS(TPARM_1(parm_right_cursor, columns - 1));
165             } else {
166                 for (i = 0; i < columns - 1; i++) {
167                     PUTCHAR(' ');
168                 }
169             }
170             PUTS(set_right_margin);
171             if (carriage_return != 0) {
172                 PUTS(carriage_return);
173             } else {
174                 PUTCHAR('\r');
175             }
176         }
177         FLUSH;
178
179         if (init_tabs != 8) {
180             if (clear_all_tabs != 0 && set_tab != 0) {
181                 for (i = 0; i < columns - 1; i += 8) {
182                     if (parm_right_cursor) {
183                         PUTS(TPARM_1(parm_right_cursor, 8));
184                     } else {
185                         for (j = 0; j < 8; j++)
186                             PUTCHAR(' ');
187                     }
188                     PUTS(set_tab);
189                 }
190                 FLUSH;
191             }
192         }
193
194         if (is_reset && reset_file != 0) {
195             f = fopen(reset_file, "r");
196             if (f == 0) {
197                 quit(4 + errno, "Can't open reset_file: '%s'", reset_file);
198             }
199             while ((c = fgetc(f)) != EOF) {
200                 PUTCHAR(c);
201             }
202             fclose(f);
203         } else if (init_file != 0) {
204             f = fopen(init_file, "r");
205             if (f == 0) {
206                 quit(4 + errno, "Can't open init_file: '%s'", init_file);
207             }
208             while ((c = fgetc(f)) != EOF) {
209                 PUTCHAR(c);
210             }
211             fclose(f);
212         }
213         FLUSH;
214
215         if (is_reset && reset_3string != 0) {
216             PUTS(reset_3string);
217         } else if (init_3string != 0) {
218             PUTS(init_3string);
219         }
220         FLUSH;
221         return 0;
222     }
223
224     if (strcmp(name, "longname") == 0) {
225         PUTS(longname());
226         return 0;
227     }
228 #if !PURE_TERMINFO
229   retry:
230 #endif
231     if ((status = tigetflag(name)) != -1) {
232         return exit_code(BOOLEAN, status);
233     } else if ((status = tigetnum(name)) != CANCELLED_NUMERIC) {
234         (void) printf("%d\n", status);
235         return exit_code(NUMBER, 0);
236     } else if ((s = tigetstr(name)) == CANCELLED_STRING) {
237 #if !PURE_TERMINFO
238         if (!termcap) {
239             const struct name_table_entry *np;
240
241             termcap = TRUE;
242             if ((np = _nc_find_entry(name, _nc_get_hash_table(termcap))) != 0) {
243                 switch (np->nte_type) {
244                 case BOOLEAN:
245                     if (bool_from_termcap[np->nte_index])
246                         name = boolnames[np->nte_index];
247                     break;
248
249                 case NUMBER:
250                     if (num_from_termcap[np->nte_index])
251                         name = numnames[np->nte_index];
252                     break;
253
254                 case STRING:
255                     if (str_from_termcap[np->nte_index])
256                         name = strnames[np->nte_index];
257                     break;
258                 }
259                 goto retry;
260             }
261         }
262 #endif
263         quit(4, "unknown terminfo capability '%s'", name);
264     } else if (s != ABSENT_STRING) {
265         if (argc > 1) {
266             int k;
267             int ignored;
268             long numbers[1 + NUM_PARM];
269             char *strings[1 + NUM_PARM];
270             char *p_is_s[NUM_PARM];
271
272             /* Nasty hack time. The tparm function needs to see numeric
273              * parameters as numbers, not as pointers to their string
274              * representations
275              */
276
277             for (k = 1; k < argc; k++) {
278                 char *tmp = 0;
279                 strings[k] = argv[k];
280                 numbers[k] = strtol(argv[k], &tmp, 0);
281                 if (tmp == 0 || *tmp != 0)
282                     numbers[k] = 0;
283             }
284             for (k = argc; k <= NUM_PARM; k++) {
285                 numbers[k] = 0;
286                 strings[k] = 0;
287             }
288
289             switch (tparm_type(name)) {
290             case Num_Str:
291                 s = TPARM_2(s, numbers[1], strings[2]);
292                 break;
293             case Num_Str_Str:
294                 s = TPARM_3(s, numbers[1], strings[2], strings[3]);
295                 break;
296             case Numbers:
297             default:
298                 (void) _nc_tparm_analyze(s, p_is_s, &ignored);
299 #define myParam(n) (p_is_s[n - 1] != 0 ? ((TPARM_ARG) strings[n]) : numbers[n])
300                 s = TPARM_9(s,
301                             myParam(1),
302                             myParam(2),
303                             myParam(3),
304                             myParam(4),
305                             myParam(5),
306                             myParam(6),
307                             myParam(7),
308                             myParam(8),
309                             myParam(9));
310                 break;
311             }
312         }
313
314         /* use putp() in order to perform padding */
315         putp(s);
316         return exit_code(STRING, 0);
317     }
318     return exit_code(STRING, 1);
319 }
320
321 int
322 main(int argc, char **argv)
323 {
324     char *term;
325     int errret;
326     bool cmdline = TRUE;
327     int c;
328     char buf[BUFSIZ];
329     int result = 0;
330
331     check_aliases(prg_name = _nc_rootname(argv[0]));
332
333     term = getenv("TERM");
334
335     while ((c = getopt(argc, argv, "ST:V")) != -1) {
336         switch (c) {
337         case 'S':
338             cmdline = FALSE;
339             break;
340         case 'T':
341             use_env(FALSE);
342             term = optarg;
343             break;
344         case 'V':
345             puts(curses_version());
346             ExitProgram(EXIT_SUCCESS);
347         default:
348             usage();
349             /* NOTREACHED */
350         }
351     }
352
353     /*
354      * Modify the argument list to omit the options we processed.
355      */
356     if (is_reset || is_init) {
357         if (optind-- < argc) {
358             argc -= optind;
359             argv += optind;
360         }
361         argv[0] = prg_name;
362     } else {
363         argc -= optind;
364         argv += optind;
365     }
366
367     if (term == 0 || *term == '\0')
368         quit(2, "No value for $TERM and no -T specified");
369
370     if (setupterm(term, STDOUT_FILENO, &errret) != OK && errret <= 0)
371         quit(3, "unknown terminal \"%s\"", term);
372
373     if (cmdline) {
374         if ((argc <= 0) && !is_reset && !is_init)
375             usage();
376         ExitProgram(tput(argc, argv));
377     }
378
379     while (fgets(buf, sizeof(buf), stdin) != 0) {
380         char *argvec[16];       /* command, 9 parms, null, & slop */
381         int argnum = 0;
382         char *cp;
383
384         /* crack the argument list into a dope vector */
385         for (cp = buf; *cp; cp++) {
386             if (isspace(UChar(*cp))) {
387                 *cp = '\0';
388             } else if (cp == buf || cp[-1] == 0) {
389                 argvec[argnum++] = cp;
390                 if (argnum >= (int) SIZEOF(argvec) - 1)
391                     break;
392             }
393         }
394         argvec[argnum] = 0;
395
396         if (argnum != 0
397             && tput(argnum, argvec) != 0) {
398             if (result == 0)
399                 result = 4;     /* will return value >4 */
400             ++result;
401         }
402     }
403
404     ExitProgram(result);
405 }