xref: /openbsd-src/lib/libcurses/tinfo/comp_expand.c (revision feef4803a40c592364b218e74a951c67178917ec)
1 /*	$OpenBSD: comp_expand.c,v 1.2 1999/03/02 06:23:28 millert Exp $	*/
2 
3 /****************************************************************************
4  * Copyright (c) 1998 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: Thomas E. Dickey <dickey@clark.net> 1998                        *
33  ****************************************************************************/
34 
35 #include <curses.priv.h>
36 
37 #include <ctype.h>
38 #include <tic.h>
39 
40 MODULE_ID("$From: comp_expand.c,v 1.10 1999/02/23 23:14:59 tom Exp $")
41 
42 static int trailing_spaces(const char *src)
43 {
44 	while (*src == ' ')
45 		src++;
46 	return *src == 0;
47 }
48 
49 /* this deals with differences over whether 0x7f and 0x80..0x9f are controls */
50 #define CHAR_OF(s) (*(unsigned const char *)(s))
51 #define REALCTL(s) (CHAR_OF(s) < 127 && iscntrl(CHAR_OF(s)))
52 #define REALPRINT(s) (CHAR_OF(s) < 127 && isprint(CHAR_OF(s)))
53 
54 char *_nc_tic_expand(const char *srcp, bool tic_format, bool numbers)
55 {
56 static char *	buffer;
57 static size_t	length;
58 
59 int		bufp;
60 const char	*ptr, *str = VALID_STRING(srcp) ? srcp : "";
61 bool		islong = (strlen(str) > 3);
62 size_t		need = (2 + strlen(str)) * 4;
63 int		ch;
64 
65 	if (buffer == 0 || need > length) {
66 		if ((buffer = typeRealloc(char, length = need, buffer)) == 0)
67 			return 0;
68 	}
69 
70 	bufp = 0;
71 	ptr = str;
72 	while ((ch = (*str & 0xff)) != 0) {
73 		if (ch == '%' && REALPRINT(str+1)) {
74 			buffer[bufp++] = *str++;
75 			/*
76 			 * Though the character literals are more compact, most
77 			 * terminal descriptions use numbers and are not easy
78 			 * to read in character-literal form.  This is the
79 			 * default option for tic/infocmp.
80 			 */
81 			if (numbers
82 			 && str[0] == S_QUOTE
83 			 && str[1] != '\\'
84 			 && REALPRINT(str+1)
85 			 && str[2] == S_QUOTE) {
86 				sprintf(buffer+bufp, "{%d}", str[1]);
87 				bufp += strlen(buffer+bufp);
88 				str += 2;
89 			}
90 			/*
91 			 * If we have a "%{number}", try to translate it into
92 			 * a "%'char'" form, since that will run a little faster
93 			 * when we're interpreting it.  Also, having one form
94 			 * for the constant makes it simpler to compare terminal
95 			 * descriptions.
96 			 */
97 			else if (!numbers
98 			 && str[0] == L_BRACE
99 			 && isdigit(str[1])) {
100 				char *dst = 0;
101 				long value = strtol(str+1, &dst, 0);
102 				if (dst != 0
103 				 && *dst == R_BRACE
104 				 && value < 127
105 				 && value != '\\'	/* FIXME */
106 				 && isprint((int)value)) {
107 					ch = (int)value;
108 					buffer[bufp++] = S_QUOTE;
109 					if (ch == '\\'
110 					 || ch == S_QUOTE)
111 						buffer[bufp++] = '\\';
112 					buffer[bufp++] = ch;
113 					buffer[bufp++] = S_QUOTE;
114 					str = dst;
115 				} else {
116 					buffer[bufp++] = *str;
117 				}
118 			} else {
119 				buffer[bufp++] = *str;
120 			}
121 		}
122 		else if (ch == 128) {
123 			buffer[bufp++] = '\\';
124 			buffer[bufp++] = '0';
125 		}
126 		else if (ch == '\033') {
127 			buffer[bufp++] = '\\';
128 			buffer[bufp++] = 'E';
129 		}
130 		else if (ch == '\\' && tic_format && (str == srcp || str[-1] != '^')) {
131 			buffer[bufp++] = '\\';
132 			buffer[bufp++] = '\\';
133 		}
134 		else if (ch == ' ' && tic_format && (str == srcp || trailing_spaces(str))) {
135 			buffer[bufp++] = '\\';
136 			buffer[bufp++] = 's';
137 		}
138 		else if ((ch == ',' || ch == ':' || ch == '^') && tic_format) {
139 			buffer[bufp++] = '\\';
140 			buffer[bufp++] = ch;
141 		}
142 		else if (REALPRINT(str) && (ch != ',' && ch != ':' && !(ch == '!' && !tic_format) && ch != '^'))
143 			buffer[bufp++] = ch;
144 #if 0		/* FIXME: this would be more readable (in fact the whole 'islong' logic should be removed) */
145 		else if (ch == '\b') {
146 			buffer[bufp++] = '\\';
147 			buffer[bufp++] = 'b';
148 		}
149 		else if (ch == '\f') {
150 			buffer[bufp++] = '\\';
151 			buffer[bufp++] = 'f';
152 		}
153 		else if (ch == '\t' && islong) {
154 			buffer[bufp++] = '\\';
155 			buffer[bufp++] = 't';
156 		}
157 #endif
158 		else if (ch == '\r' && (islong || (strlen(srcp) > 2 && str[1] == '\0'))) {
159 			buffer[bufp++] = '\\';
160 			buffer[bufp++] = 'r';
161 		}
162 		else if (ch == '\n' && islong) {
163 			buffer[bufp++] = '\\';
164 			buffer[bufp++] = 'n';
165 		}
166 #define UnCtl(c) ((c) + '@')
167 		else if (REALCTL(str) && ch != '\\' && (!islong || isdigit(str[1])))
168 		{
169 			(void) sprintf(&buffer[bufp], "^%c", UnCtl(ch));
170 			bufp += 2;
171 		}
172 		else
173 		{
174 			(void) sprintf(&buffer[bufp], "\\%03o", ch);
175 			bufp += 4;
176 		}
177 
178 		str++;
179 	}
180 
181 	buffer[bufp] = '\0';
182 	return(buffer);
183 }
184