GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcurses/tinfo/captoinfo.c Lines: 0 316 0.0 %
Date: 2017-11-13 Branches: 0 290 0.0 %

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