source: trunk/dll/literal.c@ 999

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

Fix from KO Myung-Hun for filename association containing multiple dots reformatted to FM/2 style (Ticket 235)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.2 KB
RevLine 
[117]1
2/***********************************************************************
3
4 $Id: literal.c 999 2008-03-15 18:34:05Z gyoung $
5
6 string quoting utilities
7 wildcarding utilities
8
9 Copyright (c) 1993-98 M. Kimes
[871]10 Copyright (c) 2004, 2007 Steven H.Levine
[117]11
12 Archive containers
13
[298]14 01 Aug 04 SHL Rework fixup to avoid overflows
15 16 Jun 06 SHL liternal: comments
[351]16 22 Jul 06 SHL Check more run time errors
[795]17 20 Aug 07 GKY Move #pragma alloc_text to end for OpenWatcom compat
[871]18 16 Nov 07 SHL Report fixup buffer overflow
[985]19 29 Feb 08 GKY Use xfree where appropriate
[999]20 15 Mar 08 KOMH Fix wildcard for multiple dots
[117]21
22***********************************************************************/
23
[907]24#include <stdlib.h>
25#include <string.h>
26#include <ctype.h>
27
[2]28#define INCL_OS2
29#define INCL_WIN
[907]30#define INCL_LONGLONG // dircnrs.h
[2]31
[907]32#include "errutil.h" // Dos_Error...
[2]33#include "fm3dll.h"
34
[351]35static PSZ pszSrcFile = __FILE__;
36
[551]37static INT index(const CHAR * s, const CHAR c);
[117]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 */
[2]44
[551]45static INT index(const CHAR * s, const CHAR c)
[117]46{
[551]47 CHAR *p;
[2]48
[551]49 p = strchr(s, c);
50 if (p == NULL || !*p)
51 return -1;
52 return (INT) (p - s);
[2]53}
54
[409]55/* literal()
56 * Translate a string with \ escape tokens to binary equivalent
[117]57 * Translates in place
58 *
[2]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")
[298]76 *
[409]77 * Return converted character count like strlen()
78 * Count does not include terminating nul
[2]79 */
80
81#define HEX "0123456789ABCDEF"
82#define DEC "0123456789"
83
[117]84UINT literal(PSZ pszBuf)
85{
[551]86 INT wpos;
87 INT iBuf;
88 UINT cBufBytes;
89 INT iBufSave;
90 PSZ pszOut;
91 PSZ pszWork;
92 CHAR wchar;
[2]93
[551]94 if (!pszBuf || !*pszBuf)
[2]95 return 0;
[117]96 cBufBytes = strlen(pszBuf) + 1;
[551]97 pszWork = pszOut = xmalloc(cBufBytes + 1, pszSrcFile, __LINE__);
[959]98 if (!pszWork)
99 return 0;
[2]100
[757]101 iBuf = 0; /* set index to first character */
[551]102 while (pszBuf[iBuf]) {
103 switch (pszBuf[iBuf]) {
104 case '\\':
105 switch (pszBuf[iBuf + 1]) {
[757]106 case 'x': /* hexadecimal */
[871]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;
[2]122
[757]123 case '\\': /* we want a "\" */
[871]124 iBuf++;
125 *pszOut++ = '\\';
126 break;
[2]127
[757]128 case 't': /* tab CHAR */
[871]129 iBuf++;
130 *pszOut++ = '\t';
131 break;
[2]132
[757]133 case 'n': /* new line */
[871]134 iBuf++;
135 *pszOut++ = '\n';
136 break;
[2]137
[757]138 case 'r': /* carr return */
[871]139 iBuf++;
140 *pszOut++ = '\r';
141 break;
[2]142
[757]143 case 'b': /* back space */
[871]144 iBuf++;
145 *pszOut++ = '\b';
146 break;
[2]147
[757]148 case 'f': /* formfeed */
[871]149 iBuf++;
150 *pszOut++ = '\x0c';
151 break;
[2]152
[757]153 case 'a': /* bell */
[871]154 iBuf++;
155 *pszOut++ = '\07';
156 break;
[2]157
[757]158 case '\'': /* single quote */
[871]159 iBuf++;
160 *pszOut++ = '\'';
161 break;
[2]162
[757]163 case '\"': /* double quote */
[2]164
[871]165 iBuf++;
166 *pszOut++ = '\"';
167 break;
[757]168
169 default: /* decimal */
[871]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;
[757]183 } // switch
[551]184 break;
185
186 default:
187 *pszOut++ = pszBuf[iBuf];
188 break;
[757]189 } // switch
[551]190 iBuf++;
[757]191 } // while
192 *pszOut = 0; /* Always terminate, even if not string */
[2]193
[757]194 cBufBytes = pszOut - pszWork; /* Calc string length excluding terminator */
195 memcpy(pszBuf, pszWork, cBufBytes + 1); /* Overwrite including terminator */
[985]196 xfree(pszWork);
[2]197
[757]198 return cBufBytes; /* Return string length */
[2]199}
200
[999]201/** Check wildcard match
[117]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 */
[2]207
[551]208BOOL wildcard(const PSZ pszBuf, const PSZ pszWildCard,
[999]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
284/*BOOL wildcard(const PSZ pszBuf, const PSZ pszWildCard,
[871]285 const BOOL fNotFileSpec)
[117]286{
[834]287 const CHAR *fstr = pszBuf;
288 PSZ fcard = pszWildCard;
289 CHAR *tcard;
290 INT wmatch = TRUE;
291 BOOL reverse = FALSE;
[832]292
[551]293 while (wmatch && *fcard && *fstr) {
[834]294 if (*fcard == '*' && fcard[strlen(fcard) - 1] == '*' && !reverse){
295 tcard = xstrdup(fcard + 1, __FILE__, __LINE__);
296 tcard[strlen(tcard) - 1] = 0;
297 if (!(strchr(tcard, '?')) && !(strchr(tcard, '*'))){
[871]298 if (strstr(fstr, tcard)){ //strstr match for *stuff* pattern no wildcards in "stuff"
299 xfree(tcard);
300 return TRUE;
301 }
302 else{
303 xfree(tcard);
304 return FALSE;
305 }
[834]306 }
307 xfree(tcard);
308 }
309 else //reverse search for *stuff pattern "stuff" can contain wildcards
310 if (*fcard == '*' && fcard[strlen(fcard) - 1] != '*'){
[871]311 fstr = strrev(pszBuf);
312 fcard = strrev(pszWildCard);
313 reverse = TRUE;
[832]314 }
[834]315 switch (*fcard) { //fm2 standard forward search for all other cases
[999]316 case '?': // character substitution /
[871]317 fcard++;
318 if (fNotFileSpec || (*fstr != '.' && *fstr != '/' && *fstr != '\\'))
[999]319 fstr++; // skip (match) next character
[871]320 break;
[834]321
322 case '*':
[999]323 // find next non-wild character in wildcard
[871]324 while (*fcard && (*fcard == '?' || *fcard == '*'))
325 fcard++;
[999]326 if (!*fcard){ // if last char of wildcard is *, it matches
[871]327 if (reverse){
328 fstr = strrev(pszBuf);
329 fcard = strrev(pszWildCard);
330 }
331 return TRUE;
332 }
[999]333 // skip until partition, match, or eos
[871]334 while (*fstr && toupper(*fstr) != toupper(*fcard) &&
335 (fNotFileSpec || (*fstr != '\\' &&
336 *fstr != '/' && *fstr != '.')))
337 fstr++;
[999]338 if (!fNotFileSpec && !*fstr) // implicit '.'
[871]339 if (*fcard == '.')
340 fcard++;
341 break;
[2]342
[834]343 default:
[871]344 if (!fNotFileSpec && ((*fstr == '/' || *fstr == '\\') &&
345 (*fcard == '/' || *fcard == '\\')))
346 wmatch = TRUE;
347 else
348 wmatch = (toupper(*fstr) == toupper(*fcard));
349 fstr++;
350 fcard++;
351 break;
[834]352 }
353 } //while
354
355 if ((*fcard && *fcard != '*') || *fstr){
356 if (reverse){
357 fstr = strrev(pszBuf);
358 fcard = strrev(pszWildCard);
[2]359 }
[832]360 return 0;
361 }
[834]362 else {
363 if (reverse){
364 fstr = strrev(pszBuf);
365 fcard = strrev(pszWildCard);
366 }
[832]367 return wmatch;
368 }
[999]369} */
[2]370
[832]371
[117]372// fixup - quote literal character array
[2]373
[551]374PSZ fixup(const PCH pachIn, PSZ pszOutBuf, const UINT cBufBytes,
[871]375 const UINT cInBytes)
[117]376{
[551]377 PCH pchIn = pachIn;
378 PCH pchOut = pszOutBuf;
[2]379
[117]380 // input is a character array, not a string - may not be null terminated
381 // cBufBytes is buffer size
382 if (pachIn) {
[871]383 // 16 Nov 07 SHL fixme to optimize counting and speed
[117]384 // Ensure room for null and possible \ escape
[871]385 while (pchIn - pachIn < cInBytes) {
386 if (pchOut - pszOutBuf + 4 >= cBufBytes) {
387 *pchOut = 0;
388 Runtime_Error(pszSrcFile, __LINE__, "buffer too small for %s", pszOutBuf);
389 break;
390 }
391
[551]392 if (!isprint(*pchIn)) {
[871]393 if (*pchIn == '\r') {
394 *pchOut++ = '\\';
395 *pchOut++ = 'r';
396 }
397 else if (*pchIn == '\n') {
398 *pchOut++ = '\\';
399 *pchOut++ = 'n';
400 }
401 else if (*pchIn == '\b') {
402 *pchOut++ = '\\';
403 *pchOut++ = 'b';
404 }
405 else {
406 sprintf(pchOut, "\\x%02x", (UCHAR)*pchIn);
407 pchOut += 4;
408 }
409 pchIn++;
[2]410 }
[551]411 else if (*pchIn == '\\') {
[871]412 *pchOut++ = '\\';
413 *pchOut++ = '\\';
414 pchIn++;
[2]415 }
[117]416 else
[871]417 *pchOut++ = *pchIn++;
418 } // while
419
420 } // if pachIn
[117]421 *pchOut = 0;
422 return pszOutBuf;
[2]423}
[795]424
[834]425#pragma alloc_text(LITERAL,literal,index,fixup,wildcard)
[795]426
Note: See TracBrowser for help on using the repository browser.