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