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