source: trunk/dll/literal.c@ 1416

Last change on this file since 1416 was 1416, checked in by Gregg Young, 16 years ago

The palettes and system clock now work from the config toolbar (Ticket 352); Steven's cleanup of wildcard code.

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