1 /****************************************************************************
2  * Copyright (c) 2000-2006,2008 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: Thomas E. Dickey                                                *
31  ****************************************************************************/
32 
33 #include <curses.priv.h>
34 
35 #include <ctype.h>
36 #include <termcap.h>
37 
38 MODULE_ID("$Id: lib_tgoto.c,v 1.13 2008/08/16 19:29:32 tom Exp $")
39 
40 #if !PURE_TERMINFO
41 static bool
42 is_termcap(const char *string)
43 {
44     bool result = TRUE;
45 
46     if (string == 0 || *string == '\0') {
47 	result = FALSE;		/* tparm() handles empty strings */
48     } else {
49 	while ((*string != '\0') && result) {
50 	    if (*string == '%') {
51 		switch (*++string) {
52 		case 'p':
53 		    result = FALSE;
54 		    break;
55 		case '\0':
56 		    string--;
57 		    break;
58 		}
59 	    } else if (string[0] == '$' && string[1] == '<') {
60 		result = FALSE;
61 	    }
62 	    string++;
63 	}
64     }
65     return result;
66 }
67 
68 static char *
69 tgoto_internal(const char *string, int x, int y)
70 {
71     static char *result;
72     static size_t length;
73 
74     int swap_arg;
75     int param[3];
76     size_t used = 0;
77     size_t need = 10;
78     int *value = param;
79     bool need_BC = FALSE;
80 
81     if (BC)
82 	need += strlen(BC);
83 
84     param[0] = y;
85     param[1] = x;
86     param[2] = 0;
87 
88     while (*string != 0) {
89 	if ((used + need) > length) {
90 	    length += (used + need);
91 	    if ((result = typeRealloc(char, length, result)) == 0) {
92 		length = 0;
93 		break;
94 	    }
95 	}
96 	if (*string == '%') {
97 	    const char *fmt = 0;
98 
99 	    switch (*++string) {
100 	    case '\0':
101 		string--;
102 		break;
103 	    case 'd':
104 		fmt = "%d";
105 		break;
106 	    case '2':
107 		fmt = "%02d";
108 		*value %= 100;
109 		break;
110 	    case '3':
111 		fmt = "%03d";
112 		*value %= 1000;
113 		break;
114 	    case '+':
115 		*value += UChar(*++string);
116 		/* FALLTHRU */
117 	    case '.':
118 		/*
119 		 * Guard against tputs() seeing a truncated string.  The
120 		 * termcap documentation refers to a similar fixup for \n
121 		 * and \r, but I don't see that it could work -TD
122 		 */
123 		if (*value == 0) {
124 		    if (BC != 0) {
125 			*value += 1;
126 			need_BC = TRUE;
127 		    } else {
128 			*value = 0200;	/* tputs will treat this as \0 */
129 		    }
130 		}
131 		result[used++] = (char) *value++;
132 		break;
133 	    case '%':
134 		result[used++] = *string;
135 		break;
136 	    case 'r':
137 		swap_arg = param[0];
138 		param[0] = param[1];
139 		param[1] = swap_arg;
140 		break;
141 	    case 'i':
142 		param[0] += 1;
143 		param[1] += 1;
144 		break;
145 	    case '>':
146 		if (*value > string[1])
147 		    *value += string[2];
148 		string += 2;
149 		break;
150 	    case 'n':		/* Datamedia 2500 */
151 		param[0] ^= 0140;
152 		param[1] ^= 0140;
153 		break;
154 	    case 'B':		/* BCD */
155 		*value = 16 * (*value / 10) + (*value % 10);
156 		break;
157 	    case 'D':		/* Reverse coding (Delta Data) */
158 		*value -= 2 * (*value % 16);
159 		break;
160 	    }
161 	    if (fmt != 0) {
162 		sprintf(result + used, fmt, *value++);
163 		used += strlen(result + used);
164 		fmt = 0;
165 	    }
166 	    if (value - param > 2) {
167 		value = param + 2;
168 		*value = 0;
169 	    }
170 	} else {
171 	    result[used++] = *string;
172 	}
173 	string++;
174     }
175     if (result != 0) {
176 	if (need_BC) {
177 	    strcpy(result + used, BC);
178 	    used += strlen(BC);
179 	}
180 	result[used] = '\0';
181     }
182     return result;
183 }
184 #endif
185 
186 /*
187  * Retained solely for upward compatibility.  Note the intentional reversing of
188  * the last two arguments when invoking tparm().
189  */
190 NCURSES_EXPORT(char *)
191 tgoto(const char *string, int x, int y)
192 {
193     char *result;
194 
195     T((T_CALLED("tgoto(%s, %d, %d)"), _nc_visbuf(string), x, y));
196 #if !PURE_TERMINFO
197     if (is_termcap(string))
198 	result = tgoto_internal(string, x, y);
199     else
200 #endif
201 	result = TPARM_2((NCURSES_CONST char *) string, y, x);
202     returnPtr(result);
203 }
204