source: trunk/dll/literal.c@ 1844

Last change on this file since 1844 was 1673, checked in by Gregg Young, 13 years ago

Update to Doxygen comment style Ticket 55. Also some minor code cleanup.

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