source: trunk/dll/literal.c@ 1160

Last change on this file since 1160 was 1160, checked in by John Small, 17 years ago

Ticket 187: Draft 1: Functions only

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