source: trunk/dll/literal.c@ 1047

Last change on this file since 1047 was 1047, checked in by Gregg Young, 17 years ago

Minor code cleanup

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.9 KB
Line 
1
2/***********************************************************************
3
4 $Id: literal.c 1047 2008-07-06 23:43:17Z gyoung $
5
6 string quoting utilities
7 wildcarding utilities
8
9 Copyright (c) 1993-98 M. Kimes
10 Copyright (c) 2004, 2007 Steven H.Levine
11
12 Archive containers
13
14 01 Aug 04 SHL Rework fixup to avoid overflows
15 16 Jun 06 SHL liternal: comments
16 22 Jul 06 SHL Check more run time errors
17 20 Aug 07 GKY Move #pragma alloc_text to end for OpenWatcom compat
18 16 Nov 07 SHL Report fixup buffer overflow
19 15 Mar 08 KOMH Fix wildcard for multiple dots
20
21***********************************************************************/
22
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26
27#define INCL_OS2
28#define INCL_WIN
29#define INCL_LONGLONG // dircnrs.h
30
31#include "errutil.h" // Dos_Error...
32#include "fm3dll.h"
33#include "fortify.h"
34
35static PSZ pszSrcFile = __FILE__;
36
37static INT index(const CHAR * s, const CHAR c);
38
39/* Get index of char in string
40 * @parm s string to search
41 * @parm c char to search for
42 * @return 0 relative index of c in s or -1
43 */
44
45static INT index(const CHAR * s, const CHAR c)
46{
47 CHAR *p;
48
49 p = strchr(s, c);
50 if (p == NULL || !*p)
51 return -1;
52 return (INT) (p - s);
53}
54
55/* literal()
56 * Translate a string with \ escape tokens to binary equivalent
57 * Translates in place
58 *
59 * 1. \x1b translates to CHAR(0x1b)
60 * 2. \27 translates to CHAR(27)
61 * 3. \" translates to "
62 * 4. \' translates to '
63 * 5. \\ translates to \
64 * 6. \r translates to carriage return
65 * 7. \n translates to linefeed
66 * 8. \b translates to backspace
67 * 9. \t translates to tab
68 * 10. \a translates to bell
69 * 11. \f translates to formfeed
70 *
71 * Synopsis
72 * *s = "this\x20is\32a test of \\MSC\\CSM\7"
73 * literal(s);
74 *
75 * ( s now equals "this is a test of \MSC\CSM")
76 *
77 * Return converted character count like strlen()
78 * Count does not include terminating nul
79 */
80
81#define HEX "0123456789ABCDEF"
82#define DEC "0123456789"
83
84UINT literal(PSZ pszBuf)
85{
86 INT wpos;
87 INT iBuf;
88 UINT cBufBytes;
89 INT iBufSave;
90 PSZ pszOut;
91 PSZ pszWork;
92 CHAR wchar;
93
94 if (!pszBuf || !*pszBuf)
95 return 0;
96 cBufBytes = strlen(pszBuf) + 1;
97 pszWork = pszOut = xmalloc(cBufBytes + 1, pszSrcFile, __LINE__);
98 if (!pszWork)
99 return 0;
100
101 iBuf = 0; /* set index to first character */
102 while (pszBuf[iBuf]) {
103 switch (pszBuf[iBuf]) {
104 case '\\':
105 switch (pszBuf[iBuf + 1]) {
106 case 'x': /* hexadecimal */
107 wchar = 0;
108 iBuf += 2; /* get past "\x" */
109 if (index(HEX, (CHAR) toupper(pszBuf[iBuf])) != -1) {
110 iBufSave = iBuf;
111 while (((wpos = index(HEX, (CHAR) toupper(pszBuf[iBuf]))) != -1) &&
112 iBuf < iBufSave + 2) {
113 wchar = (CHAR) (wchar << 4) + (CHAR) wpos;
114 iBuf++;
115 }
116 }
117 else
118 wchar = 'x'; /* just an x */
119 iBuf--;
120 *pszOut++ = wchar;
121 break;
122
123 case '\\': /* we want a "\" */
124 iBuf++;
125 *pszOut++ = '\\';
126 break;
127
128 case 't': /* tab CHAR */
129 iBuf++;
130 *pszOut++ = '\t';
131 break;
132
133 case 'n': /* new line */
134 iBuf++;
135 *pszOut++ = '\n';
136 break;
137
138 case 'r': /* carr return */
139 iBuf++;
140 *pszOut++ = '\r';
141 break;
142
143 case 'b': /* back space */
144 iBuf++;
145 *pszOut++ = '\b';
146 break;
147
148 case 'f': /* formfeed */
149 iBuf++;
150 *pszOut++ = '\x0c';
151 break;
152
153 case 'a': /* bell */
154 iBuf++;
155 *pszOut++ = '\07';
156 break;
157
158 case '\'': /* single quote */
159 iBuf++;
160 *pszOut++ = '\'';
161 break;
162
163 case '\"': /* double quote */
164
165 iBuf++;
166 *pszOut++ = '\"';
167 break;
168
169 default: /* decimal */
170 iBuf++; /* get past "\" */
171 wchar = 0;
172 if (index(DEC, pszBuf[iBuf]) != -1) {
173 iBufSave = iBuf;
174 do { /* cvt to binary */
175 wchar = (CHAR) (wchar * 10 + (pszBuf[iBuf++] - 48));
176 } while (index(DEC, pszBuf[iBuf]) != -1 && iBuf < iBufSave + 3);
177 iBuf--;
178 }
179 else
180 wchar = pszBuf[iBuf];
181 *pszOut++ = wchar;
182 break;
183 } // switch
184 break;
185
186 default:
187 *pszOut++ = pszBuf[iBuf];
188 break;
189 } // switch
190 iBuf++;
191 } // while
192 *pszOut = 0; /* Always terminate, even if not string */
193
194 cBufBytes = pszOut - pszWork; /* Calc string length excluding terminator */
195 memcpy(pszBuf, pszWork, cBufBytes + 1); /* Overwrite including terminator */
196 free(pszWork);
197
198 return cBufBytes; /* Return string length */
199}
200
201/** Check wildcard match
202 * @parm pszBuf Buffer to check
203 * @parm pszWildCard wildcard to match
204 * @parm fNotFileSpec TRUE if generic match else filespec match
205 * @return TRUE if matched else FALSE
206 */
207
208BOOL wildcard(const PSZ pszBuf, const PSZ pszWildCard,
209 const BOOL fNotFileSpec)
210{
211 PSZ fstr = pszBuf;
212 PSZ fcard = pszWildCard;
213
214 while (*fstr && *fcard) {
215 switch (*fcard) {
216 case '*' :
217 {
218 PSZ fstr1;
219
220 // find next non-wild character in wildcard
221 while (*fcard && ( *fcard == '*' || *fcard == '?'))
222 fcard++;
223
224 // if last char of wildcard is *, it matches
225 if (!*fcard)
226 return TRUE;
227
228 fstr1 = fstr;
229 while (*fstr1) {
230 // skip until partition, match, or eos
231 while (*fstr1 && toupper( *fstr1 ) != toupper( *fcard ) &&
232 (fNotFileSpec || ( *fstr1 != '/' && *fstr1 != '\\')))
233 fstr1++;
234
235 if (!*fstr1 || ( !fNotFileSpec && ( *fstr1 == '/' || *fstr1 == '\\')))
236 break;
237
238 if (wildcard( fstr1, fcard, fNotFileSpec ) == TRUE)
239 return TRUE;
240
241 fstr1++;
242 }
243
244 fstr = fstr1;
245 break;
246 }
247
248 case '?' : // character substitution
249 fcard++;
250
251 if (fNotFileSpec || ( *fstr != '.' && *fstr != '/' && *fstr != '\\'))
252 fstr++; // skip (match) next character
253 break;
254
255 default :
256 if (fNotFileSpec || (*fstr != '/' && *fstr != '\\') ||
257 (*fcard != '/' && *fcard != '\\')) {
258 if (toupper( *fstr ) != toupper( *fcard))
259 return FALSE;
260 }
261
262 fcard++;
263 fstr++;
264 break;
265 }
266 }
267
268 if (!*fstr) {
269 // remove trailing * and ?
270 while (*fcard && ( *fcard == '?' || *fcard == '*'))
271 fcard++;
272
273 if (!fNotFileSpec) {
274 // remove trailing .
275 while (*fcard && *fcard == '.')
276 fcard++;
277 }
278 }
279
280 return (*fstr == *fcard);
281}
282
283// fixup - quote literal character array
284
285PSZ fixup(const PCH pachIn, PSZ pszOutBuf, const UINT cBufBytes,
286 const UINT cInBytes)
287{
288 PCH pchIn = pachIn;
289 PCH pchOut = pszOutBuf;
290
291 // input is a character array, not a string - may not be null terminated
292 // cBufBytes is buffer size
293 if (pachIn) {
294 // 16 Nov 07 SHL fixme to optimize counting and speed
295 // Ensure room for null and possible \ escape
296 while (pchIn - pachIn < cInBytes) {
297 if (pchOut - pszOutBuf + 4 >= cBufBytes) {
298 *pchOut = 0;
299 Runtime_Error(pszSrcFile, __LINE__, "buffer too small for %s", pszOutBuf);
300 break;
301 }
302
303 if (!isprint(*pchIn)) {
304 if (*pchIn == '\r') {
305 *pchOut++ = '\\';
306 *pchOut++ = 'r';
307 }
308 else if (*pchIn == '\n') {
309 *pchOut++ = '\\';
310 *pchOut++ = 'n';
311 }
312 else if (*pchIn == '\b') {
313 *pchOut++ = '\\';
314 *pchOut++ = 'b';
315 }
316 else {
317 sprintf(pchOut, "\\x%02x", (UCHAR)*pchIn);
318 pchOut += 4;
319 }
320 pchIn++;
321 }
322 else if (*pchIn == '\\') {
323 *pchOut++ = '\\';
324 *pchOut++ = '\\';
325 pchIn++;
326 }
327 else
328 *pchOut++ = *pchIn++;
329 } // while
330
331 } // if pachIn
332 *pchOut = 0;
333 return pszOutBuf;
334}
335
336#pragma alloc_text(LITERAL,literal,index,fixup,wildcard)
337
Note: See TracBrowser for help on using the repository browser.