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 |