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

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

Implemented .Def to WLINK directives/options converter.

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