source: trunk/tools/common/kFileDef.cpp@ 4426

Last change on this file since 4426 was 4426, checked in by bird, 25 years ago

Implemented buffering of read and write in class kFile.

File size: 22.7 KB
Line 
1/*
2 * kFileDef - Definition files.
3 *
4 * Copyright (c) 1999 knut st. osmundsen
5 *
6 */
7
8/*******************************************************************************
9* Defined Constants *
10*******************************************************************************/
11#define StringCase(psz, pszMatch) (strnicmp(psz, pszMatch, sizeof(pszMatch)-1) == 0)
12
13/*******************************************************************************
14* Header Files *
15*******************************************************************************/
16#include <os2.h>
17#include <stdio.h>
18#include <string.h>
19#include <stdlib.h>
20#include <assert.h>
21
22#include "kFile.h"
23#include "kFileFormatBase.h"
24#include "kFileDef.h"
25
26
27/*******************************************************************************
28* Internal Functions *
29*******************************************************************************/
30static char *dupeString(const char *psz, BOOL fSkipFirstWord = FALSE);
31static char *trim(char *psz);
32static char *ltrim(const char *psz);
33static char *removeFnutts(char *pszStr);
34inline char upcase(char ch);
35static char *stristr(const char *pszStr, const char *pszSubStr);
36
37
38/**
39 * Duplicates a string.
40 * @returns Pointer to stringcopy. Remeber to delete this!
41 * @param psz Pointer to string to duplicate.
42 * @param fSkipFirstWord Skips the first word before duplicating the string.
43 */
44static char *dupeString(const char *psz, BOOL fSkipFirstWord/* = FALSE*/)
45{
46 char *pszDupe;
47 if (psz == NULL)
48 return NULL;
49
50 if (fSkipFirstWord)
51 {
52 while (*psz != ' ' && *psz != '\t' && *psz != '\n' && *psz != '\r' && *psz != '\0')
53 psz++;
54 psz = ltrim(psz);
55 }
56
57 pszDupe = new char[strlen(psz)+1];
58 strcpy(pszDupe, psz);
59 if (fSkipFirstWord)
60 return removeFnutts(pszDupe);
61 return pszDupe;
62}
63
64
65/**
66 * Trims a string, that is removing blank spaces at start and end.
67 * @returns Pointer to first non-blank char.
68 * @param psz Pointer to string.
69 * @result Blank at end of string is removed. ('\0' is moved to the left.)
70 */
71static char *trim(char *psz)
72{
73 int i;
74 if (psz == NULL)
75 return NULL;
76 while (*psz == ' ' || *psz == '\t')
77 psz++;
78 i = strlen(psz) - 1;
79 while (i >= 0 && (psz[i] == ' ' || psz[i] == '\t'))
80 i--;
81 psz[i+1] = '\0';
82 return psz;
83}
84
85
86/**
87 * Trims a string, that is removing blank spaces at start and end.
88 * @returns Pointer to first non-blank char.
89 * @param psz Pointer to string.
90 * @result Blank at end of string is removed. ('\0' is moved to the left.)
91 */
92static char *ltrim(const char *psz)
93{
94 if (psz == NULL)
95 return NULL;
96
97 while (*psz == ' ' || *psz == '\t')
98 psz++;
99 return (char *)psz;
100}
101
102
103
104kFileDef::kFileDef(kFile *pFile) throw(int)
105 :pszType(NULL), pszModName(NULL), pszBase(NULL), pszCode(NULL), pszData(NULL), pszDescription(NULL),
106 pszExeType(NULL), pszHeapSize(NULL), pszOld(NULL), pszProtmode(NULL), pszStackSize(NULL),
107 pszStub(NULL), pSegments(NULL), pImports(NULL), pExports(NULL),
108 fProgram(FALSE), fLibrary(FALSE), fPhysicalDevice(FALSE), fVirtualDevice(FALSE),
109 fInitInstance(FALSE), fTermInstance(FALSE), fInitGlobal(FALSE), fTermGlobal(FALSE),
110 chAppType(kFileDef::unknown)
111{
112 /* determin file size */
113
114 if (pFile->start())
115 {
116 try
117 {
118 this->read(pFile);
119 }
120 catch (int err)
121 {
122 throw (err);
123 }
124 }
125 else
126 throw (0x001);
127}
128
129
130/**
131 * Destructor. Frees used memory.
132 */
133kFileDef::~kFileDef()
134{
135 if (pszType != NULL) delete pszType;
136 if (pszBase != NULL) delete pszBase;
137 if (pszCode != NULL) delete pszCode;
138 if (pszData != NULL) delete pszData;
139 if (pszDescription != NULL) delete pszDescription;
140 if (pszExeType != NULL) delete pszExeType;
141 if (pszHeapSize != NULL) delete pszHeapSize;
142 if (pszOld != NULL) delete pszOld;
143 if (pszProtmode != NULL) delete pszProtmode;
144 if (pszStackSize != NULL) delete pszStackSize;
145 if (pszStub != NULL) delete pszStub;
146 while (pSegments != NULL)
147 {
148 PDEFSEGMENT p = pSegments;
149 pSegments = pSegments->pNext;
150 if (p->psz != NULL) delete p->psz;
151 delete p;
152 }
153 while (pImports != NULL)
154 {
155 PDEFIMPORT p = pImports;
156 pImports = pImports->pNext;
157 if (p->pszName != NULL) delete p->pszName;
158 if (p->pszDll != NULL) delete p->pszDll;
159 if (p->pszIntName != NULL) delete p->pszIntName;
160 delete p;
161 }
162 while (pExports != NULL)
163 {
164 PDEFEXPORT p = pExports;
165 pExports = p->pNext;
166 if (p->pszName != NULL) delete p->pszName;
167 if (p->pszIntName != NULL) delete p->pszIntName;
168 delete p;
169 }
170}
171
172
173/**
174 * Read/parse the Definition file.
175 * @param pFile Pointer to fileobject.
176 * @remark throws errorcode on error (TODO: errorhandling)
177 */
178void kFileDef::read(kFile *pFile) throw (int)
179{
180 char *pszTmp;
181 char *psz;
182 char szBuffer[256];
183
184 /* readloop */
185 psz = readln(pFile, &szBuffer[0], sizeof(szBuffer));
186 while (psz != NULL)
187 {
188 BOOL fNext = TRUE;
189
190 /* if-switch */
191 if (StringCase(psz, "LIBRARY"))
192 {
193 if (pszType != NULL) throw (0x101);
194 pszType = dupeString(psz);
195 fLibrary = TRUE;
196 if (!setModuleName())
197 throw (0x107);
198 fInitInstance = stristr(pszType, "INITINSTANCE") != NULL;
199 fInitGlobal = stristr(pszType, "INITGLOBAL") != NULL || !fInitInstance;
200 fTermInstance = stristr(pszType, "TERMINSTANCE") != NULL;
201 fTermGlobal = stristr(pszType, "TERMGLOBAL") != NULL || !fTermInstance;
202 }
203 else if (StringCase(psz, "NAME"))
204 {
205 if (pszType != NULL) throw (0x101);
206 pszType = dupeString(psz);
207 fProgram = TRUE;
208 setModuleName();
209 if (stristr(pszType, "WINDOWAPI"))
210 chAppType = kFileDef::pm;
211 else if (stristr(pszType, "NOTWINDOWCOMPAT"))
212 chAppType = kFileDef::fullscreen;
213 else if (stristr(pszType, "WINDOWCOMPAT"))
214 chAppType = kFileDef::pmvio;
215 else
216 chAppType = kFileDef::unknown;
217 }
218 else if (StringCase(psz, "PHYSICAL DEVICE")) //gap is fixed to one space, this may be fixed in readln.
219 {
220 if (pszType != NULL) throw (0x101);
221 pszType = dupeString(psz);
222 fPhysicalDevice = TRUE;
223 setModuleName();
224 }
225 else if (StringCase(psz, "VIRTUAL DEVICE")) //gap is fixed to one space, this may be fixed in readln.
226 {
227 if (pszType != NULL) throw (0x101);
228 pszType = dupeString(psz);
229 fVirtualDevice = TRUE;
230 setModuleName();
231 }
232 else if (StringCase(psz, "BASE"))
233 pszBase = dupeString(psz, TRUE);
234 else if (StringCase(psz, "CODE"))
235 pszCode = dupeString(psz, TRUE);
236 else if (StringCase(psz, "DATA"))
237 pszData = dupeString(psz, TRUE);
238 else if (StringCase(psz, "DESCRIPTION"))
239 pszDescription = dupeString(psz, TRUE);
240 else if (StringCase(psz, "EXETYPE"))
241 pszExeType = dupeString(psz, TRUE);
242 else if (StringCase(psz, "HEAPSIZE"))
243 pszHeapSize = dupeString(psz, TRUE);
244 else if (StringCase(psz, "OLD"))
245 pszOld = dupeString(psz, TRUE);
246 else if (StringCase(psz, "PROTMODE"))
247 pszProtmode = dupeString(psz, TRUE);
248 else if (StringCase(psz, "STACKSIZE"))
249 pszStackSize = dupeString(psz, TRUE);
250 else if (StringCase(psz, "STUB"))
251 pszStub = dupeString(psz, TRUE);
252 else if (StringCase(psz, "SEGMENTS"))
253 {
254 PDEFSEGMENT *pps = &pSegments;
255 while (!isKeyword(psz = readln(pFile, &szBuffer[0], sizeof(szBuffer))) && psz != NULL)
256 {
257 *pps = new DEFSEGMENT; memset(*pps, 0, sizeof(**pps));
258 (**pps).psz = dupeString(psz);
259 pps = &(**pps).pNext;
260 }
261 fNext = FALSE;
262 }
263 else if (StringCase(psz, "IMPORTS"))
264 {
265 PDEFIMPORT *ppi = &pImports;
266 while (!isKeyword(psz = readln(pFile, &szBuffer[0], sizeof(szBuffer))) && psz != NULL)
267 {
268 //DOSCALL1.154 or DosQueryHeaderInfo = DOSCALL1.154
269 *ppi = new DEFIMPORT; memset(*ppi, 0, sizeof(**ppi));
270 (**ppi).ulOrdinal = 0xffffffffUL;
271
272 if ((pszTmp = strchr(psz, '=')) != NULL)
273 {
274 *pszTmp = '\0';
275 (**ppi).pszIntName = dupeString(trim(psz));
276 psz = pszTmp + 1;
277 }
278 if ((pszTmp = strchr(psz, '.')) != NULL)
279 {
280 *pszTmp = '\0';
281 (**ppi).pszDll = dupeString(trim(psz));
282 psz = pszTmp + 1;
283 }
284 psz = trim(psz);
285 if (*psz >= '0' && *psz <= '9')
286 {
287 (**ppi).ulOrdinal = strtol(psz, &pszTmp, 0);
288 if (psz ==pszTmp) throw(0x102);
289 }
290 else
291 (**ppi).pszName = dupeString(psz);
292 ppi = &(**ppi).pNext;
293 }
294 fNext = FALSE;
295 }
296 else if (StringCase(psz, "EXPORTS"))
297 {
298 PDEFEXPORT *ppe = &pExports;
299 while (!isKeyword(psz = readln(pFile, &szBuffer[0], sizeof(szBuffer))) && psz != NULL)
300 {
301 /* CloseHandle = CloseHandle@4 @1234 RESIDENTNAME 2 */
302 *ppe = new DEFEXPORT; memset(*ppe, 0, sizeof(**ppe));
303 (**ppe).ulOrdinal = 0xffffffffUL;
304 (**ppe).cParam = 0xffffffffUL;
305
306 /* look for '=' */
307 pszTmp = strchr(psz, '=');
308 if (pszTmp != NULL)
309 { /* CloseHandle = CloseHandle@4 */
310 *pszTmp ='\0';
311 (**ppe).pszName = dupeString(trim(psz));
312 psz = trim(pszTmp + 1);
313
314 pszTmp = strchr(psz, ' ');
315 if (pszTmp != NULL)
316 *pszTmp = '\0';
317 (**ppe).pszIntName = dupeString(trim(psz));
318 if (pszTmp != NULL)
319 psz = pszTmp + 1;
320 else
321 psz = NULL;
322 }
323 else
324 { /* CloseHandle (no '= CloseHandle@4')*/
325 pszTmp = strchr(psz, ' ');
326 if (pszTmp != NULL)
327 *pszTmp = '\0';
328 (**ppe).pszName = dupeString(trim(psz));
329 if (pszTmp != NULL)
330 psz = pszTmp + 1;
331 else
332 psz = NULL;
333 }
334
335 if (psz != NULL)
336 { /* @1234 RESIDENTNAME 2 */
337 pszTmp = strchr(psz, '@');
338 if (pszTmp)
339 { /* @1234 RESIDENTNAME 2 */
340 psz = pszTmp + 1;
341 (**ppe).ulOrdinal = strtol(psz, &pszTmp, 0);
342 if (pszTmp == psz) throw (0x103);
343 psz = trim(pszTmp);
344
345 if (*psz != '\0')
346 { /* RESIDENTNAME 2 */
347 if (StringCase(psz, "RESIDENTNAME"))
348 {
349 (**ppe).fResident = TRUE;
350 psz = trim(psz + sizeof("RESIDENTNAME") - 1);
351 }
352 else if (StringCase(psz, "NONAME"))
353 {
354 (**ppe).fResident = FALSE;
355 psz = trim(psz + sizeof("NONAME") - 1);
356 }
357 }
358 else
359 {
360 (**ppe).fResident = (**ppe).ulOrdinal == 0xffffffffUL;
361 }
362 }
363
364 if (*psz != '\0')
365 { /* 2 */
366 (**ppe).cParam = strtol(psz, &pszTmp, 0);
367 if (pszTmp == psz) throw (0x104);
368 }
369 }
370
371 removeFnutts((**ppe).pszIntName);
372 removeFnutts((**ppe).pszName);
373 ppe = &(**ppe).pNext;
374 }
375 fNext = FALSE;
376 }
377 else
378 throw(0x105);
379
380 /* next ? */
381 if (fNext)
382 psz = readln(pFile, &szBuffer[0], sizeof(szBuffer));
383 }
384
385 /* sanity check */
386 if (pszType == NULL)
387 throw ((int)0x106);
388}
389
390
391/**
392 * Reads first meaning full line from a file into a buffer.
393 * @returns Pointer to buffer on success; NULL on error.
394 * @param pFile Pointer to fileobject to read line from.
395 * @param pszBuffer Pointer to buffer.
396 * @param cbBuffer Size of buffer.
397 * @remark tabs are expanded. string is trimmed. comments removed.
398 */
399char *kFileDef::readln(kFile *pFile, char *pszBuffer, int cbBuffer) throw (int)
400{
401 int i;
402 int cch;
403
404 do
405 {
406 /* read line */
407 if (!pFile->readln(pszBuffer, cbBuffer))
408 {
409 if (!pFile->isEOF())
410 throw (0x201);
411 return FALSE;
412 }
413
414 /* check for and remove comments, and get string length. */
415 cch = 0;
416 while (pszBuffer[cch] != '\0' && pszBuffer[cch] != ';')
417 cch++;
418 pszBuffer[cch] = '\0';
419
420 if (cch > 0)
421 {
422 /* remove '\t' - tab is trouble some! */
423 for (i = 0; i < cch; i++)
424 if (pszBuffer[i] == '\t')
425 pszBuffer[i] = ' ';
426
427 /* trim line - right */
428 i = cch - 1;
429 while (i >= 0 &&
430 (
431 pszBuffer[i] == '\n' ||
432 pszBuffer[i] == '\r' ||
433 pszBuffer[i] == ' '
434 ))
435 i--;
436 pszBuffer[++i] = '\0';
437 cch = i;
438
439 /* trim line - left */
440 i = 0;
441 while (i < cch && pszBuffer[i] == ' ')
442 i++;
443 cch -= i;
444 if (i > 0)
445 memmove(pszBuffer, &pszBuffer[i], cch + 1);
446 }
447 } while ((*pszBuffer == ';' || cch == 0) && !pFile->isEOF());
448
449 return !(*pszBuffer == ';' || cch == 0) ? pszBuffer : NULL;
450}
451
452
453/**
454 * Checks for keyword.
455 * @returns TRUE - keyword; FALSE - not keyword;
456 * @param psz Pointer to word/string to check.
457 * @remark TODO - we are going to check WORDS.
458 */
459BOOL kFileDef::isKeyword(const char *psz)
460{
461 return psz != NULL
462 &&
463 (
464 StringCase(psz, "LIBRARY") ||
465 StringCase(psz, "NAME") ||
466 StringCase(psz, "PHYSICAL DEVICE") || //gap is fixed to one space, this may be fixed in readln.
467 StringCase(psz, "VIRTUAL DEVICE") || //gap is fixed to one space, this may be fixed in readln.
468 StringCase(psz, "BASE") ||
469 StringCase(psz, "CODE") ||
470 StringCase(psz, "DATA") ||
471 StringCase(psz, "DESCRIPTION") ||
472 StringCase(psz, "EXETYPE") ||
473 StringCase(psz, "HEAPSIZE") ||
474 StringCase(psz, "OLD") ||
475 StringCase(psz, "STACKSIZE") ||
476 StringCase(psz, "STUB") ||
477 StringCase(psz, "SEGMENTS") ||
478 StringCase(psz, "IMPORTS") ||
479 StringCase(psz, "EXPORTS")
480 );
481}
482
483
484/**
485 * Extracts the module name from the pszType string.
486 * @returns Success indicator.
487 * @param pszBuffer Pointer to string buffer which is to hold the module name upon return.
488 * @remark Assumes that pszBuffer is large enough.
489 */
490BOOL kFileDef::setModuleName(void)
491{
492 char *pszEnd;
493 char *pszStart;
494
495 assert(pszType);
496
497 /* skip the first word */
498 pszStart = strpbrk(pszType, " \t");
499 if (pszStart != NULL)
500 {
501 pszStart = ltrim(pszStart);
502 pszEnd = strpbrk(pszStart, " \t");
503 if (pszEnd == NULL)
504 pszEnd = pszStart + strlen(pszStart);
505 pszModName = new char[pszEnd - pszStart + 1];
506 memcpy(pszModName, pszStart, pszEnd - pszStart);
507 pszModName[pszEnd - pszStart] = '\0';
508 }
509 else
510 return !StringCase(pszType, "LIBRARY");
511 return TRUE;
512}
513
514
515/**
516 * Query for the module name.
517 * @returns Success indicator. TRUE / FALSE.
518 * @param pszBuffer Pointer to buffer which to put the name into.
519 */
520BOOL kFileDef::queryModuleName(char *pszBuffer)
521{
522 if (pszModName == NULL)
523 return FALSE;
524
525 strcpy(pszBuffer, pszModName);
526
527 return TRUE;
528}
529
530
531/**
532 * Finds the first exports.
533 * @returns Success indicator. TRUE / FALSE.
534 * @param pExport Pointer to export structure.
535 * @remark
536 */
537BOOL kFileDef::findFirstExport(PEXPORTENTRY pExport)
538{
539 if (pExports != NULL && pExport != NULL)
540 {
541 pExport->ulOrdinal = pExports->ulOrdinal;
542 if (pExports->pszName != NULL)
543 strcpy(&pExport->achName[0], pExports->pszName);
544 else
545 pExport->achName[0] = '\0';
546 if (pExports->pszIntName)
547 strcpy(&pExport->achIntName[0], pExports->pszIntName);
548 else
549 pExport->achIntName[0] = '\0';
550 pExport->pv = (void*)pExports->pNext;
551 }
552 else
553 return FALSE;
554 return TRUE;
555}
556
557
558/**
559 * Finds the next export.
560 * @returns Success indicator. TRUE / FALSE.
561 * @param pExport Pointer to export structure.
562 * @remark
563 */
564BOOL kFileDef::findNextExport(PEXPORTENTRY pExport)
565{
566 if (pExport != NULL && pExport->pv != NULL)
567 {
568 PDEFEXPORT pExp = (PDEFEXPORT)pExport->pv;
569
570 pExport->ulOrdinal = pExp->ulOrdinal;
571 if (pExp->pszName != NULL)
572 strcpy(&pExport->achName[0], pExp->pszName);
573 else
574 pExport->achName[0] = '\0';
575 if (pExp->pszIntName)
576 strcpy(&pExport->achIntName[0], pExp->pszIntName);
577 else
578 pExport->achIntName[0] = '\0';
579 pExport->pv = (void*)pExp->pNext;
580 }
581 else
582 return FALSE;
583 return TRUE;
584}
585
586
587/**
588 * Make a Watcom Linker parameter file addtition of this definition file.
589 * @returns Success indicator.
590 * @param pFile File which we're to write to (append).
591 * Appends at current posistion.
592 * @sketch
593 * @status
594 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
595 * @remark
596 */
597BOOL kFileDef::makeWatcomLinkFileAddtion(kFile *pFile) throw(int)
598{
599 PDEFSEGMENT pSeg;
600 PDEFIMPORT pImp;
601 PDEFEXPORT pExp;
602 pFile->setThrowOnErrors();
603
604 /*
605 * Write a little remark first to tell that converted stuff starts here.
606 */
607 pFile->printf("#\n# Directives generated from .DEF-file.\n#\n");
608
609 /* Format - Module type */
610 pFile->printf("FORMAT OS2 LX %s %s %s\n",
611 fLibrary ? "DLL" :
612 (fProgram ? (chAppType == pm ? "PM"
613 : (chAppType == fullscreen ? "FULLSCREEN"
614 : "PMCOMPATIBLE"))
615 : (fVirtualDevice ? "VIRTDEVICE"
616 : "PHYSDEVICE" )),
617 fLibrary ? (fInitGlobal ? "INITGLOBAL" : "INITINSTANCE") : "",
618 fLibrary ? (fTermGlobal ? "TERMGLOBAL" : "TERMINSTANCE") : "");
619
620
621 /* Module name */
622 if (pszModName)
623 pFile->printf("OPTION MODNAME=%s\n", pszModName);
624
625 /* Description */
626 if (pszDescription)
627 pFile->printf("OPTION DESCRIPTION '%s'\n", pszDescription);
628
629 /* Base */
630 if (pszBase)
631 pFile->printf("OPTION OFFSET=%s\n", pszBase);
632
633 /* Stub */
634 if (pszStub)
635 pFile->printf("OPTION STUB='%s'\n", pszStub);
636
637 /* Old */
638 if (pszOld)
639 pFile->printf("OPTION OLDLIBRARY=%s\n", pszOld);
640
641 /* Protected mode */
642 if (pszProtmode)
643 pFile->printf("OPTION PROTMODE\n", pszProtmode);
644
645 /* Stacksize */
646 if (pszStackSize)
647 pFile->printf("OPTION STACK=%s\n", pszStackSize);
648
649 /* HeapSize */
650 if (pszHeapSize)
651 pFile->printf("OPTION HEAPSIZE=%s\n", pszHeapSize);
652
653 /* Code - not supported */
654
655 /* Data - not supported */
656
657 /*
658 * Segments.
659 */
660 pSeg = pSegments;
661 while (pSeg != NULL)
662 {
663 pFile->printf("SEGMENT %s\n", pSeg->psz);
664 pSeg = pSeg->pNext;
665 }
666
667 /*
668 * Imports.
669 */
670 pImp = pImports;
671 while (pImp != NULL)
672 {
673 if (pImp->pszName == NULL)
674 pFile->printf("IMPORT '%s' '%s'.%d\n", pImp->pszIntName, pImp->pszDll, pImp->ulOrdinal);
675 else
676 pFile->printf("IMPORT '%s' '%s'.'%s'\n", pImp->pszIntName, pImp->pszDll, pImp->pszName);
677 pImp = pImp->pNext;
678 }
679
680 /*
681 * Exports.
682 */
683 pExp = pExports;
684 while (pExp != NULL)
685 {
686 pFile->printf("EXPORT '%s'", pExp->pszName);
687 if (pExp->ulOrdinal != ~0UL)
688 pFile->printf(".%d", pExp->ulOrdinal);
689 if (pExp->pszIntName)
690 pFile->printf("='%s'", pExp->pszIntName);
691 if (pExp->fResident)
692 pFile->printf(" RESIDENT");
693 if (pExp->cParam != ~0UL)
694 pFile->printf(" %d", pExp->cParam * 2); /* .DEFs this is number of words. Watcom should have bytes. */
695 pFile->printf("\n");
696 pExp = pExp->pNext;
697 }
698
699 return TRUE;
700}
701
702
703
704
705/**
706 * Removes '"' and ''' at start and end of the string.
707 * @returns pszStr!
708 * @param pszStr String that is to have "s and 's removed.
709 */
710static char *removeFnutts(char *pszStr)
711{
712 if (pszStr != NULL)
713 {
714 int cch = strlen(pszStr);
715 if (cch > 0 && (pszStr[cch-1] == '"' || pszStr[cch-1] == '\''))
716 pszStr[cch-1] = '\0';
717
718 if (*pszStr == '"' || *pszStr == '\'')
719 memmove(pszStr, pszStr+1, cch-1);
720 }
721 return pszStr;
722}
723
724
725/**
726 * Upcases a char.
727 * @returns Upper case of the char given in ch.
728 * @param ch Char to capitalize.
729 */
730inline char upcase(char ch)
731{
732 return ch >= 'a' && ch <= 'z' ? (char)(ch - ('a' - 'A')) : ch;
733}
734
735
736/**
737 * Searches for a substring in a string.
738 * @returns Pointer to start of substring when found, NULL when not found.
739 * @param pszStr String to be searched.
740 * @param pszSubStr String to be searched.
741 * @remark Depends on the upcase function.
742 */
743static char *stristr(const char *pszStr, const char *pszSubStr)
744{
745 int cchSubStr = strlen(pszSubStr);
746 int i = 0;
747
748 while (*pszStr != '\0' && i < cchSubStr)
749 {
750 i = 0;
751 while (i < cchSubStr && pszStr[i] != '\0' &&
752 (upcase(pszStr[i]) == upcase(pszSubStr[i])))
753 i++;
754 pszStr++;
755 }
756
757 return (char*)(*pszStr != '\0' ? pszStr - 1 : NULL);
758}
759
Note: See TracBrowser for help on using the repository browser.