ncurses 5.1
[ncurses.git] / ncurses / tinfo / captoinfo.c
1 /****************************************************************************
2  * Copyright (c) 1998,1999,2000 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  ****************************************************************************/
33
34 /*
35  *      captoinfo.c --- conversion between termcap and terminfo formats
36  *
37  *      The captoinfo() code was swiped from Ross Ridge's mytinfo package,
38  *      adapted to fit ncurses by Eric S. Raymond <esr@snark.thyrsus.com>.
39  *
40  *      There is just one entry point:
41  *
42  *      char *captoinfo(n, s, parametrized)
43  *
44  *      Convert value s for termcap string capability named n into terminfo
45  *      format.
46  *
47  *      This code recognizes all the standard 4.4BSD %-escapes:
48  *
49  *      %%       output `%'
50  *      %d       output value as in printf %d
51  *      %2       output value as in printf %2d
52  *      %3       output value as in printf %3d
53  *      %.       output value as in printf %c
54  *      %+x      add x to value, then do %.
55  *      %>xy     if value > x then add y, no output
56  *      %r       reverse order of two parameters, no output
57  *      %i       increment by one, no output
58  *      %n       exclusive-or all parameters with 0140 (Datamedia 2500)
59  *      %B       BCD (16*(value/10)) + (value%10), no output
60  *      %D       Reverse coding (value - 2*(value%16)), no output (Delta Data).
61  *
62  *      Also, %02 and %03 are accepted as synonyms for %2 and %3.
63  *
64  *      Besides all the standard termcap escapes, this translator understands
65  *      the following extended escapes:
66  *
67  *      used by GNU Emacs termcap libraries
68  *              %a[+*-/=][cp]x  GNU arithmetic.
69  *              %m              xor the first two parameters by 0177
70  *              %b              backup to previous parameter
71  *              %f              skip this parameter
72  *
73  *      used by the University of Waterloo (MFCF) termcap libraries
74  *              %-x      subtract parameter FROM char x and output it as a char
75  *              %ax      add the character x to parameter
76  *
77  *      If #define WATERLOO is on, also enable these translations:
78  *
79  *              %sx      subtract parameter FROM the character x
80  *
81  *      By default, this Waterloo translations are not compiled in, because
82  *      the Waterloo %s conflicts with the way terminfo uses %s in strings for
83  *      function programming.
84  *
85  *      Note the two definitions of %a: the GNU definition is translated if the
86  *      characters after the 'a' are valid for it, otherwise the UW definition
87  *      is translated.
88  */
89
90 #include <curses.priv.h>
91
92 #include <ctype.h>
93 #include <tic.h>
94
95 MODULE_ID("$Id: captoinfo.c,v 1.37 2000/04/01 20:07:34 tom Exp $")
96
97 #define MAX_PUSHED      16      /* max # args we can push onto the stack */
98
99 static int stack[MAX_PUSHED];   /* the stack */
100 static int stackptr;            /* the next empty place on the stack */
101 static int onstack;             /* the top of stack */
102 static int seenm;               /* seen a %m */
103 static int seenn;               /* seen a %n */
104 static int seenr;               /* seen a %r */
105 static int param;               /* current parameter */
106 static char *dp;                /* pointer to end of the converted string */
107
108 static char *my_string;
109 static size_t my_length;
110
111 static char *
112 init_string(void)
113 /* initialize 'my_string', 'my_length' */
114 {
115     if (my_string == 0)
116         my_string = typeMalloc(char, my_length = 256);
117     if (my_string == 0)
118         _nc_err_abort("Out of memory");
119
120     *my_string = '\0';
121     return my_string;
122 }
123
124 static char *
125 save_string(char *d, const char *const s)
126 {
127     size_t have = (d - my_string);
128     size_t need = have + strlen(s) + 2;
129     if (need > my_length) {
130         my_string = (char *) realloc(my_string, my_length = (need + need));
131         if (my_string == 0)
132             _nc_err_abort("Out of memory");
133         d = my_string + have;
134     }
135     (void) strcpy(d, s);
136     return d + strlen(d);
137 }
138
139 static inline char *
140 save_char(char *s, char c)
141 {
142     static char temp[2];
143     temp[0] = c;
144     return save_string(s, temp);
145 }
146
147 static void
148 push(void)
149 /* push onstack on to the stack */
150 {
151     if (stackptr > MAX_PUSHED)
152         _nc_warning("string too complex to convert");
153     else
154         stack[stackptr++] = onstack;
155 }
156
157 static void
158 pop(void)
159 /* pop the top of the stack into onstack */
160 {
161     if (stackptr == 0) {
162         if (onstack == 0)
163             _nc_warning("I'm confused");
164         else
165             onstack = 0;
166     } else
167         onstack = stack[--stackptr];
168     param++;
169 }
170
171 static int
172 cvtchar(register const char *sp)
173 /* convert a character to a terminfo push */
174 {
175     unsigned char c = 0;
176     int len;
177
178     switch (*sp) {
179     case '\\':
180         switch (*++sp) {
181         case '\'':
182         case '$':
183         case '\\':
184         case '%':
185             c = *sp;
186             len = 2;
187             break;
188         case '\0':
189             c = '\\';
190             len = 1;
191             break;
192         case '0':
193         case '1':
194         case '2':
195         case '3':
196             len = 1;
197             while (isdigit(*sp)) {
198                 c = 8 * c + (*sp++ - '0');
199                 len++;
200             }
201             break;
202         default:
203             c = *sp;
204             len = 2;
205             break;
206         }
207         break;
208     case '^':
209         c = (*++sp & 0x1f);
210         len = 2;
211         break;
212     default:
213         c = *sp;
214         len = 1;
215     }
216     if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
217         dp = save_string(dp, "%\'");
218         dp = save_char(dp, c);
219         dp = save_char(dp, '\'');
220     } else {
221         dp = save_string(dp, "%{");
222         if (c > 99)
223             dp = save_char(dp, c / 100 + '0');
224         if (c > 9)
225             dp = save_char(dp, ((int) (c / 10)) % 10 + '0');
226         dp = save_char(dp, c % 10 + '0');
227         dp = save_char(dp, '}');
228     }
229     return len;
230 }
231
232 static void
233 getparm(int parm, int n)
234 /* push n copies of param on the terminfo stack if not already there */
235 {
236     if (seenr) {
237         if (parm == 1)
238             parm = 2;
239         else if (parm == 2)
240             parm = 1;
241     }
242     if (onstack == parm) {
243         if (n > 1) {
244             _nc_warning("string may not be optimal");
245             dp = save_string(dp, "%Pa");
246             while (n--) {
247                 dp = save_string(dp, "%ga");
248             }
249         }
250         return;
251     }
252     if (onstack != 0)
253         push();
254
255     onstack = parm;
256
257     while (n--) {
258         dp = save_string(dp, "%p");
259         dp = save_char(dp, '0' + parm);
260     }
261
262     if (seenn && parm < 3) {
263         dp = save_string(dp, "%{96}%^");
264     }
265
266     if (seenm && parm < 3) {
267         dp = save_string(dp, "%{127}%^");
268     }
269 }
270
271 char *
272 _nc_captoinfo(
273 /* convert a termcap string to terminfo format */
274     register const char *cap,   /* relevant terminfo capability index */
275     register const char *s,     /* string value of the capability */
276     int const parametrized      /* do % translations if 1, pad translations if >=0 */
277 )
278 {
279     const char *capstart;
280
281     stackptr = 0;
282     onstack = 0;
283     seenm = 0;
284     seenn = 0;
285     seenr = 0;
286     param = 1;
287
288     dp = init_string();
289
290     /* skip the initial padding (if we haven't been told not to) */
291     capstart = 0;
292     if (s == 0)
293         s = "";
294     if (parametrized >= 0 && isdigit(*s))
295         for (capstart = s;; s++)
296             if (!(isdigit(*s) || *s == '*' || *s == '.'))
297                 break;
298
299     while (*s != '\0') {
300         switch (*s) {
301         case '%':
302             s++;
303             if (parametrized < 1) {
304                 dp = save_char(dp, '%');
305                 break;
306             }
307             switch (*s++) {
308             case '%':
309                 dp = save_char(dp, '%');
310                 break;
311             case 'r':
312                 if (seenr++ == 1) {
313                     _nc_warning("saw %%r twice in %s", cap);
314                 }
315                 break;
316             case 'm':
317                 if (seenm++ == 1) {
318                     _nc_warning("saw %%m twice in %s", cap);
319                 }
320                 break;
321             case 'n':
322                 if (seenn++ == 1) {
323                     _nc_warning("saw %%n twice in %s", cap);
324                 }
325                 break;
326             case 'i':
327                 dp = save_string(dp, "%i");
328                 break;
329             case '6':
330             case 'B':
331                 getparm(param, 1);
332                 dp = save_string(dp, "%{10}%/%{16}%*");
333                 getparm(param, 1);
334                 dp = save_string(dp, "%{10}%m%+");
335                 break;
336             case '8':
337             case 'D':
338                 getparm(param, 2);
339                 dp = save_string(dp, "%{2}%*%-");
340                 break;
341             case '>':
342                 getparm(param, 2);
343                 /* %?%{x}%>%t%{y}%+%; */
344                 dp = save_string(dp, "%?");
345                 s += cvtchar(s);
346                 dp = save_string(dp, "%>%t");
347                 s += cvtchar(s);
348                 dp = save_string(dp, "%+%;");
349                 break;
350             case 'a':
351                 if ((*s == '=' || *s == '+' || *s == '-'
352                         || *s == '*' || *s == '/')
353                     && (s[1] == 'p' || s[1] == 'c')
354                     && s[2] != '\0') {
355                     int l;
356                     l = 2;
357                     if (*s != '=')
358                         getparm(param, 1);
359                     if (s[1] == 'p') {
360                         getparm(param + s[2] - '@', 1);
361                         if (param != onstack) {
362                             pop();
363                             param--;
364                         }
365                         l++;
366                     } else
367                         l += cvtchar(s + 2);
368                     switch (*s) {
369                     case '+':
370                         dp = save_string(dp, "%+");
371                         break;
372                     case '-':
373                         dp = save_string(dp, "%-");
374                         break;
375                     case '*':
376                         dp = save_string(dp, "%*");
377                         break;
378                     case '/':
379                         dp = save_string(dp, "%/");
380                         break;
381                     case '=':
382                         if (seenr) {
383                             if (param == 1)
384                                 onstack = 2;
385                             else if (param == 2)
386                                 onstack = 1;
387                             else
388                                 onstack = param;
389                         } else
390                             onstack = param;
391                         break;
392                     }
393                     s += l;
394                     break;
395                 }
396                 getparm(param, 1);
397                 s += cvtchar(s);
398                 dp = save_string(dp, "%+");
399                 break;
400             case '+':
401                 getparm(param, 1);
402                 s += cvtchar(s);
403                 dp = save_string(dp, "%+%c");
404                 pop();
405                 break;
406             case 's':
407 #ifdef WATERLOO
408                 s += cvtchar(s);
409                 getparm(param, 1);
410                 dp = save_string(dp, "%-");
411 #else
412                 getparm(param, 1);
413                 dp = save_string(dp, "%s");
414                 pop();
415 #endif /* WATERLOO */
416                 break;
417             case '-':
418                 s += cvtchar(s);
419                 getparm(param, 1);
420                 dp = save_string(dp, "%-%c");
421                 pop();
422                 break;
423             case '.':
424                 getparm(param, 1);
425                 dp = save_string(dp, "%c");
426                 pop();
427                 break;
428             case '0':           /* not clear any of the historical termcaps did this */
429                 if (*s == '3')
430                     goto see03;
431                 else if (*s != '2')
432                     goto invalid;
433                 /* FALLTHRU */
434             case '2':
435                 getparm(param, 1);
436                 dp = save_string(dp, "%2d");
437                 pop();
438                 break;
439             case '3':
440               see03:
441                 getparm(param, 1);
442                 dp = save_string(dp, "%3d");
443                 pop();
444                 break;
445             case 'd':
446                 getparm(param, 1);
447                 dp = save_string(dp, "%d");
448                 pop();
449                 break;
450             case 'f':
451                 param++;
452                 break;
453             case 'b':
454                 param--;
455                 break;
456             case '\\':
457                 dp = save_string(dp, "%\\");
458                 break;
459             default:
460               invalid:
461                 dp = save_char(dp, '%');
462                 s--;
463                 _nc_warning("unknown %% code %s (%#x) in %s",
464                     unctrl(*s), (*s) & 0xff, cap);
465                 break;
466             }
467             break;
468 #ifdef REVISIBILIZE
469         case '\\':
470             dp = save_char(dp, *s++);
471             dp = save_char(dp, *s++);
472             break;
473         case '\n':
474             dp = save_string(dp, "\\n");
475             s++;
476             break;
477         case '\t':
478             dp = save_string(dp, "\\t");
479             s++;
480             break;
481         case '\r':
482             dp = save_string(dp, "\\r");
483             s++;
484             break;
485         case '\200':
486             dp = save_string(dp, "\\0");
487             s++;
488             break;
489         case '\f':
490             dp = save_string(dp, "\\f");
491             s++;
492             break;
493         case '\b':
494             dp = save_string(dp, "\\b");
495             s++;
496             break;
497         case ' ':
498             dp = save_string(dp, "\\s");
499             s++;
500             break;
501         case '^':
502             dp = save_string(dp, "\\^");
503             s++;
504             break;
505         case ':':
506             dp = save_string(dp, "\\:");
507             s++;
508             break;
509         case ',':
510             dp = save_string(dp, "\\,");
511             s++;
512             break;
513         default:
514             if (*s == '\033') {
515                 dp = save_string(dp, "\\E");
516                 s++;
517             } else if (*s > 0 && *s < 32) {
518                 dp = save_char(dp, '^');
519                 dp = save_char(dp, *s + '@');
520                 s++;
521             } else if (*s <= 0 || *s >= 127) {
522                 dp = save_char(dp, '\\');
523                 dp = save_char(dp, ((*s & 0300) >> 6) + '0');
524                 dp = save_char(dp, ((*s & 0070) >> 3) + '0');
525                 dp = save_char(dp, (*s & 0007) + '0');
526                 s++;
527             } else
528                 dp = save_char(dp, *s++);
529             break;
530 #else
531         default:
532             dp = save_char(dp, *s++);
533             break;
534 #endif
535         }
536     }
537
538     /*
539      * Now, if we stripped off some leading padding, add it at the end
540      * of the string as mandatory padding.
541      */
542     if (capstart) {
543         dp = save_string(dp, "$<");
544         for (s = capstart;; s++)
545             if (isdigit(*s) || *s == '*' || *s == '.')
546                 dp = save_char(dp, *s);
547             else
548                 break;
549         dp = save_string(dp, "/>");
550     }
551
552     (void) save_char(dp, '\0');
553     return (my_string);
554 }
555
556 /*
557  * Check for an expression that corresponds to "%B" (BCD):
558  *      (parameter / 10) * 16 + (parameter % 10)
559  */
560 static int
561 bcd_expression(const char *str)
562 {
563     /* leave this non-const for HPUX */
564     static char fmt[] = "%%p%c%%{10}%%/%%{16}%%*%%p%c%%{10}%%m%%+";
565     int len = 0;
566     char ch1, ch2;
567
568     if (sscanf(str, fmt, &ch1, &ch2) == 2
569         && isdigit(ch1)
570         && isdigit(ch2)
571         && (ch1 == ch2)) {
572         len = 28;
573 #ifndef NDEBUG
574         {
575             char buffer[80];
576             int tst;
577             sprintf(buffer, fmt, ch1, ch2);
578             tst = strlen(buffer) - 1;
579             assert(len == tst);
580         }
581 #endif
582     }
583     return len;
584 }
585
586 static char *
587 save_tc_char(char *bufptr, int c1)
588 {
589     char temp[80];
590
591     if (is7bits(c1) && isprint(c1)) {
592         if (c1 == ':' || c1 == '\\')
593             bufptr = save_char(bufptr, '\\');
594         bufptr = save_char(bufptr, c1);
595     } else {
596         if (c1 == (c1 & 0x1f))  /* iscntrl() returns T on 255 */
597             (void) strcpy(temp, unctrl(c1));
598         else
599             (void) sprintf(temp, "\\%03o", c1);
600         bufptr = save_string(bufptr, temp);
601     }
602     return bufptr;
603 }
604
605 static char *
606 save_tc_inequality(char *bufptr, int c1, int c2)
607 {
608     bufptr = save_string(bufptr, "%>");
609     bufptr = save_tc_char(bufptr, c1);
610     bufptr = save_tc_char(bufptr, c2);
611     return bufptr;
612 }
613
614 /*
615  * Here are the capabilities infotocap assumes it can translate to:
616  *
617  *     %%       output `%'
618  *     %d       output value as in printf %d
619  *     %2       output value as in printf %2d
620  *     %3       output value as in printf %3d
621  *     %.       output value as in printf %c
622  *     %+c      add character c to value, then do %.
623  *     %>xy     if value > x then add y, no output
624  *     %r       reverse order of two parameters, no output
625  *     %i       increment by one, no output
626  *     %n       exclusive-or all parameters with 0140 (Datamedia 2500)
627  *     %B       BCD (16*(value/10)) + (value%10), no output
628  *     %D       Reverse coding (value - 2*(value%16)), no output (Delta Data).
629  *     %m       exclusive-or all parameters with 0177 (not in 4.4BSD)
630  */
631
632 char *
633 _nc_infotocap(
634 /* convert a terminfo string to termcap format */
635     register const char *cap GCC_UNUSED,        /* relevant termcap capability index */
636     register const char *str,   /* string value of the capability */
637     int const parametrized      /* do % translations if 1, pad translations if >=0 */
638 )
639 {
640     int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0;
641     const char *padding;
642     const char *trimmed = 0;
643     char ch1 = 0, ch2 = 0;
644     char *bufptr = init_string();
645     int len;
646     bool syntax_error = FALSE;
647
648     /* we may have to move some trailing mandatory padding up front */
649     padding = str + strlen(str) - 1;
650     if (*padding == '>' && *--padding == '/') {
651         --padding;
652         while (isdigit(*padding) || *padding == '.' || *padding == '*')
653             padding--;
654         if (*padding == '<' && *--padding == '$')
655             trimmed = padding;
656         padding += 2;
657
658         while (isdigit(*padding) || *padding == '.' || *padding == '*')
659             bufptr = save_char(bufptr, *padding++);
660     }
661
662     for (; *str && str != trimmed; str++) {
663         int c1, c2;
664         char *cp = 0;
665
666         if (str[0] == '\\' && (str[1] == '^' || str[1] == ',')) {
667             bufptr = save_char(bufptr, *++str);
668         } else if (str[0] == '$' && str[1] == '<') {    /* discard padding */
669             str += 2;
670             while (isdigit(*str) || *str == '.' || *str == '*' || *str ==
671                 '/' || *str == '>')
672                 str++;
673             --str;
674         } else if (str[0] == '%' && str[1] == '%') {    /* escaped '%' */
675             bufptr = save_string(bufptr, "%%");
676         } else if (*str != '%' || (parametrized < 1)) {
677             bufptr = save_char(bufptr, *str);
678         } else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1, &c2) == 2) {
679             str = strchr(str, ';');
680             bufptr = save_tc_inequality(bufptr, c1, c2);
681         } else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1, &ch2) == 2) {
682             str = strchr(str, ';');
683             bufptr = save_tc_inequality(bufptr, c1, c2);
684         } else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1, &c2) == 2) {
685             str = strchr(str, ';');
686             bufptr = save_tc_inequality(bufptr, c1, c2);
687         } else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2) {
688             str = strchr(str, ';');
689             bufptr = save_tc_inequality(bufptr, c1, c2);
690         } else if ((len = bcd_expression(str)) != 0) {
691             str += len;
692             bufptr = save_string(bufptr, "%B");
693         } else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1
694                     || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1)
695             && (cp = strchr(str, '+'))) {
696             str = cp + 2;
697             bufptr = save_string(bufptr, "%+");
698
699             if (ch1)
700                 c1 = ch1;
701             bufptr = save_tc_char(bufptr, c1);
702         }
703         /* FIXME: this "works" for 'delta' */
704         else if (strncmp(str, "%{2}%*%-", 8) == 0) {
705             str += 7;
706             bufptr = save_string(bufptr, "%D");
707         } else if (strncmp(str, "%{96}%^", 7) == 0) {
708             str += 6;
709             if (saw_m++ == 0) {
710                 bufptr = save_string(bufptr, "%n");
711             }
712         } else if (strncmp(str, "%{127}%^", 8) == 0) {
713             str += 7;
714             if (saw_n++ == 0) {
715                 bufptr = save_string(bufptr, "%m");
716             }
717         } else {                /* cm-style format element */
718             str++;
719             switch (*str) {
720             case '%':
721                 bufptr = save_char(bufptr, '%');
722                 break;
723
724             case '0':
725             case '1':
726             case '2':
727             case '3':
728             case '4':
729             case '5':
730             case '6':
731             case '7':
732             case '8':
733             case '9':
734                 bufptr = save_char(bufptr, '%');
735                 while (isdigit(*str))
736                     bufptr = save_char(bufptr, *str++);
737                 if (strchr("doxX.", *str)) {
738                     if (*str != 'd')    /* termcap doesn't have octal, hex */
739                         return 0;
740                 }
741                 break;
742
743             case 'd':
744                 bufptr = save_string(bufptr, "%d");
745                 break;
746
747             case 'c':
748                 bufptr = save_string(bufptr, "%.");
749                 break;
750
751                 /*
752                  * %s isn't in termcap, but it's convenient to pass it through
753                  * so we can represent things like terminfo pfkey strings in
754                  * termcap notation.
755                  */
756             case 's':
757                 bufptr = save_string(bufptr, "%s");
758                 break;
759
760             case 'p':
761                 str++;
762                 if (*str == '1')
763                     seenone = 1;
764                 else if (*str == '2') {
765                     if (!seenone && !seentwo) {
766                         bufptr = save_string(bufptr, "%r");
767                         seentwo++;
768                     }
769                 } else if (*str >= '3')
770                     return (0);
771                 break;
772
773             case 'i':
774                 bufptr = save_string(bufptr, "%i");
775                 break;
776
777             default:
778                 bufptr = save_char(bufptr, *str);
779                 syntax_error = TRUE;
780                 break;
781             }                   /* endswitch (*str) */
782         }                       /* endelse (*str == '%') */
783
784         if (*str == '\0')
785             break;
786
787     }                           /* endwhile (*str) */
788
789     return (syntax_error ? NULL : my_string);
790 }
791
792 #ifdef MAIN
793
794 int curr_line;
795
796 int
797 main(int argc, char *argv[])
798 {
799     int c, tc = FALSE;
800
801     while ((c = getopt(argc, argv, "c")) != EOF)
802         switch (c) {
803         case 'c':
804             tc = TRUE;
805             break;
806         }
807
808     curr_line = 0;
809     for (;;) {
810         char buf[BUFSIZ];
811
812         ++curr_line;
813         if (fgets(buf, sizeof(buf), stdin) == 0)
814             break;
815         buf[strlen(buf) - 1] = '\0';
816         _nc_set_source(buf);
817
818         if (tc) {
819             char *cp = _nc_infotocap("to termcap", buf, 1);
820
821             if (cp)
822                 (void) fputs(cp, stdout);
823         } else
824             (void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout);
825         (void) putchar('\n');
826     }
827     return (0);
828 }
829 #endif /* MAIN */
830
831 /* captoinfo.c ends here */