source: trunk/tools/database/StateUpd.cpp@ 1935

Last change on this file since 1935 was 1935, checked in by bird, 26 years ago

Added new statuses for Open32.

File size: 47.6 KB
Line 
1/* $Id: StateUpd.cpp,v 1.2 1999-12-02 12:05:47 bird Exp $ */
2/*
3 * StateUpd - Scans source files for API functions and imports data on them.
4 *
5 * Copyright (c) 1999 knut st. osmundsen
6 *
7 */
8
9/*******************************************************************************
10* Header Files *
11*******************************************************************************/
12#define INCL_DOSFILEMGR
13#define INCL_DOSERRORS
14#include <os2.h>
15#include <stdio.h>
16#include <string.h>
17#include <malloc.h>
18#include <assert.h>
19
20#include "StateUpd.h"
21#include "db.h"
22
23
24
25/*******************************************************************************
26* Global Variables *
27*******************************************************************************/
28static FILE *phLog = NULL;
29static FILE *phSignal = NULL;
30
31
32/*******************************************************************************
33* Internal Functions *
34*******************************************************************************/
35static void syntax(void);
36static void openLogs(void);
37static void closeLogs(void);
38static unsigned long processDir(char *pszDir, BOOL fFile, POPTIONS pOptions);
39static unsigned long processFile(const char *pszFilename, POPTIONS pOptions);
40static unsigned long processAPI(char **papszLines, int i, int &iRet, const char *pszFilename, POPTIONS pOptions);
41static unsigned long analyseFnHdr(PFNDESC pFnDesc, char **papszLines, int i, const char *pszFilename, POPTIONS pOptions);
42static unsigned long analyseFnDcl(PFNDESC pFnDesc, char **papszLines, int i, int &iRet, const char *pszFilename, POPTIONS pOptions);
43static BOOL isFunction(char **papszLines, int i, POPTIONS pOptions);
44static char *skipInsignificantChars(char **papszLines, int &i, char *psz);
45static char *readFileIntoMemory(const char *pszFilename);
46static char **createLineArray(char *pszFile);
47static char *findEndOfWord(char *psz);
48static char *findStartOfWord(char *psz, const char *pszStart);
49static char *trim(char *psz);
50static void copy(char *psz, int jFrom, int iFrom, int jTo, int iTo, char **papszLines);
51static void copy(char *psz, char *pszFrom, int iFrom, char *pszTo, int iTo, char **papszLines);
52static char *stristr(const char *pszStr, const char *pszSubStr);
53
54
55/**
56 * Main function.
57 * @returns Number of signals.
58 * @param argc Argument count.
59 * @param argv Argument array.
60 */
61int main(int argc, char **argv)
62{
63 int argi;
64 BOOL fFatal = FALSE;
65 unsigned long ulRc = 0;
66 OPTIONS options = {TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE};
67 unsigned long ulRc2;
68 char *pszErrorDesc = NULL;
69 char *pszHost = "localhost";
70 char *pszDatabase = "Odin32";
71 char *pszUser = "root";
72 char *pszPasswd = "";
73
74 /**************************************************************************
75 * parse arguments.
76 * options: -h or -? Syntax help.
77 * -ib<[+]|-> Integrity check at start.
78 * -ie<[+]|-> Integrity check at end.
79 * -io Integrity check only.
80 * -s Scan subdirectories.
81 * -Old <[+]|-> Old API Style.
82 * -OS2<[+]|-> Removes 'OS2'-prefix from function name.
83 * -COMCTL32<[+]|-> Removes 'COMCTL32'-prefix from function name.
84 * -VERSION<[+]|-> Removes 'VERSION'-prefix from function name.
85 * -d:<dbname> Database name
86 * -p:<passwd> Password
87 * -u:<user> Userid
88 * -h:<host> Hostname/IP-address
89 **************************************************************************/
90 argi = 1;
91 while (argi < argc && !fFatal)
92 {
93 if(argv[argi][0] == '-' || argv[argi][0] == '/')
94 {
95 switch (argv[argi][1])
96 {
97 case 'd':
98 case 'D':
99 if (argv[argi][2] == ':')
100 pszDatabase = &argv[argi][3];
101 else
102 fprintf(stderr, "warning: option '-d:' requires database name.\n");
103 break;
104
105 case 'h':
106 case 'H':
107 if (argv[argi][2] == ':')
108 {
109 pszHost = &argv[argi][3];
110 break;
111 }
112 case '?':
113 syntax();
114 return 0;
115
116 case 'i': /* Integrity */
117 case 'I':
118 switch (argv[argi][2])
119 {
120 case 'b':
121 case 'B':
122 options.fIntegrityBefore = argv[argi][3] != '-';
123 break;
124
125 case 'e':
126 case 'E':
127 options.fIntegrityAfter = argv[argi][3] != '-';
128 break;
129
130 case 'o':
131 case 'O':
132 options.fIntegrityOnly = argv[argi][3] != '-';
133 break;
134
135 default:
136 fprintf(stderr, "incorrect parameter. (argi=%d, argv[argi]=%s)\n", argi, argv[argi]);
137 fFatal = TRUE;
138 }
139 break;
140
141 case 'o':
142 case 'O':
143 if (stricmp(&argv[argi][1], "OS2") == 0)
144 options.fOS2 = argv[argi][4] != '-';
145 else if (stricmp(&argv[argi][1], "Old") == 0)
146 options.fOld = argv[argi][4] != '-';
147 else
148 {
149 fprintf(stderr, "incorrect parameter. (argi=%d, argv[argi]=%s)\n", argi, argv[argi]);
150 fFatal = TRUE;
151 }
152 break;
153
154 case 'p':
155 case 'P':
156 if (argv[argi][2] == ':')
157 pszPasswd = &argv[argi][3];
158 else
159 fprintf(stderr, "warning: option '-p:' requires password.\n");
160 break;
161
162 case 's':
163 case 'S':
164 options.fRecursive = TRUE;
165 break;
166
167 case 'u':
168 case 'U':
169 if (argv[argi][2] == ':')
170 pszUser = &argv[argi][3];
171 else
172 fprintf(stderr, "error: option '-u:' requires userid.\n");
173 break;
174
175 default:
176 fprintf(stderr, "incorrect parameter. (argi=%d, argv[argi]=%s)\n", argi, argv[argi]);
177 fFatal = TRUE;
178 break;
179 }
180 }
181 else
182 break; /* files has started */
183 argi++;
184 }
185
186 if (!fFatal)
187 {
188 /* open database */
189 if (!dbConnect(pszHost, pszUser, pszPasswd, pszDatabase))
190 {
191 fprintf(stderr, "Could not connect to database (%s). \n\terror description: %s\n",
192 pszDatabase, dbGetLastErrorDesc());
193 return 0x00010001;
194 }
195
196 /* open the logs */
197 openLogs();
198
199 /* check db integrity */
200 if (options.fIntegrityBefore)
201 {
202 pszErrorDesc = (char*)malloc(1048768); assert(pszErrorDesc != NULL);
203 *pszErrorDesc = '\0';
204 ulRc2 = dbCheckIntegrity(pszErrorDesc);
205 if (ulRc2 != 0)
206 {
207 fprintf(phSignal, "-,-: integrity errors:\n\t%s\n", pszErrorDesc);
208 ulRc += ulRc2 << 16;
209 }
210 free(pszErrorDesc);
211 }
212
213 if (!options.fIntegrityOnly)
214 {
215 /* processing */
216 if (argv[argi] == NULL)
217 ulRc = processDir(".", FALSE, &options);
218 else
219 while (argv[argi] != NULL)
220 {
221 ulRc += processDir(argv[argi], TRUE, &options);
222 argi++;
223 }
224
225 /* create new history rows */
226 pszErrorDesc = (char*)malloc(1048768); assert(pszErrorDesc != NULL);
227 *pszErrorDesc = '\0';
228 ulRc2 = dbCreateHistory(pszErrorDesc);
229 if (ulRc2 != 0)
230 {
231 fprintf(phSignal, "-,-: errors which occurred while creating history:\n\t%s\n", pszErrorDesc);
232 ulRc += ulRc2 << 16;
233 }
234 free(pszErrorDesc);
235
236 /* check db integrity */
237 if (options.fIntegrityAfter)
238 {
239 pszErrorDesc = (char*)malloc(1048768); assert(pszErrorDesc != NULL);
240 *pszErrorDesc = '\0';
241 ulRc2 = dbCheckIntegrity(pszErrorDesc);
242 if (ulRc2 != 0)
243 {
244 fprintf(phSignal, "-,-: integrity errors:\n\t%s\n", pszErrorDesc);
245 ulRc += ulRc2 << 16;
246 }
247 free(pszErrorDesc);
248 }
249 }
250
251 /* close the logs */
252 closeLogs();
253
254 /* close database */
255 dbDisconnect();
256
257 /* warn if error during processing. */
258 fprintf(stdout,"Number of successfully processed APIs: %4ld\n", (long)(0x0000FFFF & ulRc));
259 fprintf(stdout,"Number of signals: %4ld\n", (long)(ulRc >> 16));
260 if ((int)(ulRc >> 16) > 0)
261 fprintf(stderr, "Check signal file 'Signals.Log'.\n");
262 }
263
264 return (int)(ulRc >> 16);
265}
266
267
268
269/**
270 * Displays syntax.
271 */
272static void syntax()
273{
274 printf("\n"
275 "StateUpd v%01d.%02d - Odin32 API Database utility\n"
276 "----------------------------------------------\n"
277 "syntax: StateUpd.exe [-h|-?] [options] [file1 [file2 [file3 ...]]]\n"
278 "\n"
279 " -h or -? Syntax help. (this)\n"
280 " -ib<[+]|-> Integrity check at start. default: enabled\n"
281 " -ie<[+]|-> Integrity check at end. default: enabled\n"
282 " -io Integrity check only. default: disabled\n"
283 " -s Scan subdirectories. default: disabled\n"
284 " -Old Use old API style. default: disabled\n"
285 " -OS2 Ignore 'OS2'-prefix on APIs. default: disabled\n"
286 " -h:<hostname> Database server hostname. default: localhost\n"
287 " -u:<username> Username on the server. default: root\n"
288 " -p:<password> Password. default: <empty>\n"
289 " -d:<database> Database to use. default: Odin32\n"
290 "\n"
291 "Scans files for API functions. This util will extract data about the API\n"
292 "and insert it into the database.\n"
293 "\n"
294 "If no files are given, then all *.c and *.cpp files will be scanned.\n"
295 "NOTE: When files are given, only *.c and *.cpp files will be scanned.\n"
296 "Wildchars are allowed in the file spesifications.\n"
297 "\n"
298 "Copyright (c) 1999 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)",
299 MAJOR_VER, MINOR_VER
300 );
301}
302
303
304/**
305 * Open logs, StateUpd.log and Signals.log (error log).
306 */
307static void openLogs(void)
308{
309 if (phLog == NULL)
310 {
311 phLog = fopen("StateUpd.Log", "w");
312 if (phLog == NULL)
313 {
314 fprintf(stderr,"error occured while opening log file - will use stderr instead.\n");
315 phLog = stderr;
316 }
317 }
318
319 if (phSignal == NULL)
320 {
321 phSignal = fopen("Signals.Log", "w");
322 if (phSignal == NULL)
323 {
324 fprintf(stderr,"error occured while opening signal file - will use stdout instead.\n");
325 phSignal = stdout;
326 }
327 }
328}
329
330
331/**
332 * Closes the logs.
333 */
334static void closeLogs(void)
335{
336 if (phLog != stderr && phLog != NULL)
337 fclose(phLog);
338 if (phSignal != stdout && phSignal != NULL)
339 fclose(phSignal);
340}
341
342
343/**
344 * Processes a subdirectory and files.
345 * @returns high word = number of signals
346 * low word = number of APIs processed. (1 or 0).
347 * @param pszDir Directory or file, see fFile.
348 * @param fFile File indicator, TRUE: pszDir is a file, FALSE: pszDir is a dir.
349 * @param pOptions Pointer to options.
350 * @sketch 0. Interpret parameters.
351 * 1. Scan current directory for *.cpp and *.c files and process them.
352 * 2. If recusion option is enabled:
353 * Scan current directory for sub-directories, scan them using recursion.
354 */
355static unsigned long processDir(char *pszDir, BOOL fFile, POPTIONS pOptions)
356{
357 unsigned long ulRc = 0; /* high word = #signals, low word = #APIs successfully processed */
358 char szFileSpec[CCHMAXPATH];
359 APIRET rc;
360 FILEFINDBUF3 ffb;
361 ULONG ul = 1;
362 HDIR hDir = (HDIR)HDIR_CREATE;
363 char *pszFile;
364
365 /* O. */
366 if (fFile)
367 {
368 if ((pszFile = strrchr(pszDir, '\\')) == NULL)
369 pszFile = strrchr(pszDir, '/');
370 if (pszFile != NULL)
371 *pszFile++ = '\0';
372 else
373 {
374 pszFile = pszDir;
375 pszDir = ".";
376 }
377 }
378 else
379 pszFile = NULL;
380
381
382 /* 1. */
383 if (fFile)
384 strcat(strcat(strcpy(&szFileSpec[0], pszDir), "\\"), pszFile);
385 else
386 strcat(strcpy(&szFileSpec[0], pszDir), "\\*.c*");
387 rc = DosFindFirst((PCSZ)&szFileSpec[0], &hDir,
388 FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_ARCHIVED,
389 (PVOID)&ffb, sizeof(ffb), &ul, FIL_STANDARD);
390 while (rc == NO_ERROR && ul == 1)
391 {
392 char *psz = strrchr(&ffb.achName[0], '.');
393 if (psz != NULL && (!stricmp(psz, ".cpp") || !stricmp(psz, ".c")))
394 ulRc += processFile(strcat(strcat(strcpy(&szFileSpec[0], pszDir), "\\"), &ffb.achName[0]), pOptions);
395
396 /* next */
397 ul = 1;
398 rc = DosFindNext(hDir, &ffb, sizeof(ffb), &ul);
399 }
400 DosFindClose(hDir);
401
402 /* 2. */
403 if (pOptions->fRecursive)
404 {
405 strcat(strcpy(&szFileSpec[0], pszDir), "\\*");
406
407 hDir = (HDIR)HDIR_CREATE;
408 ul = 1; /* important on TVFS, not on HPFS... */
409 rc = DosFindFirst((PCSZ)&szFileSpec[0], &hDir,
410 MUST_HAVE_DIRECTORY,
411 (PVOID)&ffb, sizeof(ffb), &ul, FIL_STANDARD);
412 while (rc == NO_ERROR && ul == 1)
413 {
414 if (strcmp(&ffb.achName[0], ".") != 0 && strcmp(&ffb.achName[0], "..") != 0)
415 {
416 strcat(strcat(strcpy(&szFileSpec[0], pszDir), "\\"), &ffb.achName[0]);
417 if (fFile)
418 strcat(strcat(&szFileSpec[0], "\\"), pszFile);
419 ulRc += processDir(&szFileSpec[0], fFile, pOptions);
420 }
421
422 /* next */
423 ul = 1;
424 rc = DosFindNext(hDir, &ffb, sizeof(ffb), &ul);
425 }
426 DosFindClose(hDir);
427 }
428
429 return ulRc;
430}
431
432
433/**
434 * Processes a file.
435 * @returns high word = number of signals
436 * low word = number of APIs processed. (1 or 0).
437 * @param pszFilename Filename
438 * @param pOptions Pointer to options.
439 * @sketch 1. read file into memory.
440 * 2. create line array.
441 * (3. simple preprocessing - TODO)
442 * 4. scan thru the line array, looking for APIs.
443 * 4b. when API is found, process it.
444 */
445static unsigned long processFile(const char *pszFilename, POPTIONS pOptions)
446{
447 unsigned long cSignals = 0;
448 unsigned long cAPIs = 0;
449 char *pszFile;
450
451 fprintf(phLog, "Processing '%s':\n", pszFilename);
452 /* 1.*/
453 pszFile = readFileIntoMemory(pszFilename);
454 if (pszFile != NULL)
455 {
456 char **papszLines;
457
458 /* 2.*/
459 papszLines = createLineArray(pszFile);
460 if (papszLines != NULL)
461 {
462 int i = 0;
463
464 /* 3. - TODO */
465
466 /* 4.*/
467 while (papszLines[i] != NULL)
468 {
469 if (isFunction(papszLines, i, pOptions))
470 {
471 unsigned long ulRc;
472 ulRc = processAPI(papszLines, i, i, pszFilename, pOptions);
473 cAPIs += 0x0000ffff & ulRc;
474 cSignals += ulRc >> 16;
475 }
476 else
477 i++;
478 }
479
480 free(papszLines);
481 }
482 else
483 {
484 fprintf(phSignal,"%s: error dividing file into lines.\n", pszFilename);
485 cSignals++;
486 }
487 free(pszFile);
488 }
489 else
490 {
491 fprintf(phSignal,"%s: error reading file.\n", pszFilename);
492 cSignals++;
493 }
494 fprintf(phLog, "Processing of '%s' is completed.\n\n", pszFilename);
495
496
497 return (unsigned long)((cSignals << 16) | cAPIs);
498}
499
500
501/**
502 * Processes an API function.
503 * @returns high word = number of signals
504 * low word = number of APIs processed. (1 or 0).
505 * @param papszLines Array of lines in the file.
506 * @param i Index into papszLines.
507 * @param iRet Index into papszLines. Where to resume search.
508 * @param pszFilename Filename used in the signal log.
509 * @param pOptions Pointer to options.
510 */
511static unsigned long processAPI(char **papszLines, int i, int &iRet, const char *pszFilename, POPTIONS pOptions)
512{
513 unsigned long ulRc;
514 int j;
515 FNDESC FnDesc;
516 memset(&FnDesc, 0, sizeof(FnDesc));
517
518 /* default value */
519 FnDesc.lStatus = 99;
520
521 /* precondition: isFunction is true.
522 * brief algorithm:
523 * 1. Analyse function declaration.
524 * 2. Analyse function header.
525 * 3. Log data (for debug purpose).
526 * 4. Update database
527 */
528
529 /* 1.*/
530 ulRc = analyseFnDcl(&FnDesc, papszLines, i, iRet, pszFilename, pOptions);
531 if (0x0000ffff & ulRc) /* if low word is 0 the fatal */
532 {
533 unsigned long ulRcTmp;
534 char szErrorDesc[2113]; /* due to some limitation in the latest EMX release size is 2112 and not 4096 as initially implemented. */
535
536 /* 2.*/
537 ulRcTmp = analyseFnHdr(&FnDesc, papszLines, i, pszFilename, pOptions);
538 if (ulRcTmp == ~0UL) /* check for fatal error */
539 return (0xffff0000UL & ulRc) + 0x00010000UL;
540 ulRc += 0xffff0000UL & ulRcTmp;
541
542 /* 3.*/
543 fprintf(phLog, "Name: '%s' (refcode=%ld)\n", FnDesc.pszName, FnDesc.lRefCode);
544 fprintf(phLog, " Returns: '%s'\n", FnDesc.pszReturnType != NULL ? FnDesc.pszReturnType : "<missing>");
545 fprintf(phLog, " cParams: %2d\n", FnDesc.cParams);
546 for (j = 0; j < FnDesc.cParams; j++)
547 fprintf(phLog, " Param %2d: type '%s' %*s name '%s'\n", j, FnDesc.apszParamType[j],
548 (int)(15 - strlen(FnDesc.apszParamType[j])), "", FnDesc.apszParamName[j]);
549 fprintf(phLog, " Status: %ld - '%s'\n", FnDesc.lStatus, FnDesc.pszStatus != NULL ? FnDesc.pszStatus : "<missing>");
550 fprintf(phLog, " cAuthors: %2d\n", FnDesc.cAuthors);
551 for (j = 0; j < FnDesc.cAuthors; j++)
552 fprintf(phLog, " Author %d: '%s' (refcode=%ld)\n", j, FnDesc.apszAuthor[j], FnDesc.alAuthorRefCode[j]);
553
554 /* 4.*/
555 ulRcTmp = dbUpdateFunction(&FnDesc, &szErrorDesc[0]);
556 if (ulRcTmp != 0)
557 {
558 fprintf(phSignal, "%s,%s: %s\n", pszFilename, FnDesc.pszName, &szErrorDesc[0]);
559 ulRc += ulRcTmp << 16;
560 }
561 }
562
563 return ulRc;
564}
565
566
567/**
568 * Analyses the function declaration.
569 * @returns high word = number of signals
570 * low word = number of APIs processed. (1 or 0).
571 * @param papszLines Array of lines in the file.
572 * @param i Index into papszLines.
573 * @param iRet Index into papszLines. Where to start searching again.
574 * @param pszFilename Filename used in the signal log.
575 * @param pOptions Pointer to options.
576 */
577static unsigned long analyseFnDcl(PFNDESC pFnDesc, char **papszLines, int i, int &iRet,
578 const char *pszFilename, POPTIONS pOptions)
579{
580 static long lPrevFnDll = -1L; /* fix for duplicate dlls */
581 FNFINDBUF FnFindBuf;
582 char *pszOS2;
583 char *pszP1;
584 int iP1;
585 char *pszP2;
586 int iP2;
587 char *psz;
588 unsigned long ulRc = 0x000000001;
589 int iFn = 0;
590
591 iRet = i+1;
592
593 /* brief algorithm:
594 * 1. find function name and start and end parentese. (evt. return type.)
595 * 2. copy to szFnDclBuffer.
596 * 3. extract name, and do a database lookup on the name.
597 * 3b. if more that one match, write a signal. (TODO: a simple fix is done, but there are holes.)
598 * 4. analyse parameters. (evt. return type)
599 */
600
601 /* 1.*/
602 if (!pOptions->fOld)
603 { /* new API naming convention */
604 pszP1 = strchr(papszLines[i], '(');
605 iP1 = i;
606 pszOS2 = pszP1 - 1;
607 while (pszOS2 > papszLines[i] && *pszOS2 == ' ')
608 pszOS2--;
609 pszOS2 = findStartOfWord(pszOS2, papszLines[i]);
610 }
611 else
612 { /* old API naming convention */
613 pszOS2 = strstr(papszLines[i], "OS2");
614 iP1 = i;
615 pszP1 = findEndOfWord(pszOS2);
616 pszP1 = skipInsignificantChars(papszLines, iP1, pszP1);
617 }
618 iP2 = iP1;
619 pszP2 = pszP1 + 1;
620 while (*pszP2 != ')')
621 if (*pszP2++ == '\0')
622 if ((pszP2 = papszLines[++iP2]) == NULL)
623 break;
624
625 iRet = iP2 + 1; //assumes: only one function on a single line!
626
627 /* 2. */
628 psz = &pFnDesc->szFnDclBuffer[0];
629 /* copy name */
630 if (pOptions->fOS2 && strncmp(pszOS2, "OS2", 3) == 0)
631 {
632 if (iP1 == i)
633 strncpy(psz, pszOS2+3, pszP1 - (pszOS2+3));
634 else
635 strcpy(psz, pszOS2+3);
636 }
637 else if (pOptions->fCOMCTL32 && strncmp(pszOS2, "COMCTL32", 8) == 0)
638 {
639 if (iP1 == i)
640 strncpy(psz, pszOS2+8, pszP1 - (pszOS2+8));
641 else
642 strcpy(psz, pszOS2+8);
643 }
644 else if (pOptions->fVERSION && strncmp(pszOS2, "VERSION", 7) == 0)
645 {
646 if (iP1 == i)
647 strncpy(psz, pszOS2+7, pszP1 - (pszOS2+7));
648 else
649 strcpy(psz, pszOS2+7);
650 }
651 else
652 {
653 if (!pOptions->fOld)
654 { /* new API naming convention */
655 if (iP1 == i)
656 strncpy(psz, pszOS2, pszP1 - pszOS2);
657 else
658 strcpy(psz, pszOS2);
659 }
660 else
661 { /* old API naming convention */
662 if (iP1 == i)
663 strncpy(psz, pszOS2+3, pszP1 - (pszOS2+3));
664 else
665 strcpy(psz, pszOS2+3);
666 }
667 }
668 trim(psz);
669 pFnDesc->pszName = psz;
670 psz += strlen(psz) + 1;
671
672 copy(psz, pszP1, iP1, pszP2, iP2, papszLines);
673
674 /* 3.*/
675 if (!dbFindFunction(pFnDesc->pszName, &FnFindBuf))
676 {
677 fprintf(phSignal, "%s, %s: error occured while reading from database, %s\n",
678 pszFilename, pFnDesc->pszName, dbGetLastErrorDesc());
679 return 0x00010000;
680 }
681
682 if (FnFindBuf.cFns == 0)
683 {
684 fprintf(phLog, "%s was not an API\n", pFnDesc->pszName);
685 return 0;
686 }
687 else if (FnFindBuf.cFns > 1)
688 { /* 3b.*/
689 while (iFn < (int)FnFindBuf.cFns && FnFindBuf.alDllRefCode[iFn] != lPrevFnDll)
690 iFn++;
691 if (lPrevFnDll == -1L && iFn >= (int)FnFindBuf.cFns)
692 {
693 fprintf(phSignal, "%s, %s: error - more than one function by the name '%s'\n",
694 pszFilename, pFnDesc->pszName, pFnDesc->pszName);
695 return 0x00010000;
696 }
697 }
698 pFnDesc->lRefCode = FnFindBuf.alRefCode[iFn];
699 lPrevFnDll = FnFindBuf.alDllRefCode[iFn];
700
701 /* 4.*/
702 pFnDesc->cParams = 0;
703 if (stricmp(psz, "(void)") != 0 && strcmp(psz, "()") != 0 && strcmp(psz, "( )"))
704 {
705 psz++; /* skip '(' */
706 while (*psz != '\0' && *psz != ')')
707 {
708 char *pszName;
709 char *pszEnd = psz;
710
711 while (*pszEnd != '\0' && *pszEnd != ',' && *pszEnd != ')')
712 pszEnd++;
713
714 /* fix - if pszEnd == '\0' then there is something wrong */
715 if (*pszEnd == '\0')
716 {
717 fprintf(phLog, "internal error (not fatal): pszEnd = '\\0' when it shouldn't, %d\n", __LINE__);
718 break;
719 }
720 *pszEnd = '\0';
721
722 /* paranoia test */
723 if (pszEnd <= psz)
724 {
725 fprintf(phSignal, "%s: error - pszEnd <= psz\n", pszFilename);
726 return 0x00010000;
727 }
728
729 pszName = findStartOfWord(pszEnd - 1, psz);
730 if (pszName > psz)
731 {
732 pszName[-1] = '\0'; /* this is required to be space! */
733 pFnDesc->apszParamType[pFnDesc->cParams] = trim(psz);
734 }
735 else
736 pFnDesc->apszParamType[pFnDesc->cParams] = ""; /* no parameter type (parameter is usualy a define) */
737 pFnDesc->apszParamName[pFnDesc->cParams] = trim(pszName);
738
739 /* next */
740 pFnDesc->cParams++;
741 psz = pszEnd + 1;
742 }
743 }
744
745 return ulRc;
746}
747
748
749/**
750 * Analyses the function header.
751 * @returns high word = number of signals
752 * low word = number of APIs processed. (1 or 0).
753 * @param papszLines Array of lines in the file.
754 * @param i Index into papszLines.
755 * @param pszFilename Filename used in the signal log.
756 * @param pOptions Pointer to options.
757 * @sketch 1. Search backwards (start at i-1) for a comment or code.
758 * 2. If comment: (else fail)
759 * 2a. find start and end of comment.
760 * 2b. check for function header characteristics
761 * - lots of '*'s.
762 * - fields 'Status', 'Author' and 'Name'
763 * or if SDS, check for:
764 * - at least two '*'s at the begining.
765 * - fields '@status' and/or '@author'
766 * 2c. check that content of the 'Name' field matches (not SDS)
767 * 2d. read the status and author fields.
768 * @remark Supports both types of function headers, Odin32-common and SDS.
769 */
770static unsigned long analyseFnHdr(PFNDESC pFnDesc, char **papszLines, int i, const char *pszFilename, POPTIONS pOptions)
771{
772 int iStatus, iAuthor, iName, iStart, iEnd;
773 int j, jStart;
774 int fFound;
775 int fSDS = 0;
776 char *psz, *pszB;
777 char *pszAuthor = NULL;
778 unsigned long ulRc = 0x00000001;
779
780 pOptions = pOptions;
781
782 if (i < 0) /* parameter validation */
783 return 0;
784
785 /* 1. + 2a.*/
786 iEnd = i-1; /* find end */
787 j = strlen(papszLines[iEnd]);
788 j -= j > 0 ? 1 : 0;
789 fFound = 0;
790 while (iEnd >= 0 && i - iEnd < 7 && papszLines[iEnd][j] != '}' &&
791 !(fFound = (papszLines[iEnd][j] == '*' && papszLines[iEnd][j+1] == '/')))
792 if (j-- == 0)
793 if (iEnd-- > 0)
794 {
795 j = strlen(papszLines[iEnd]);
796 j -= j > 0 ? 1 : 0;
797 }
798 if (!fFound) /* fail if not found */
799 return 0;
800
801 iStart = iEnd; /* find start */
802 if (j < 2)
803 j -= (j = strlen(papszLines[--iStart])) > 1 ? 2 : j;
804 else
805 j -= 2;
806 fFound = 0;
807 while (iStart >= 0 &&
808 !(fFound = (papszLines[iStart][j] == '/' && papszLines[iStart][j+1] == '*')))
809 if (j-- == 0)
810 if (iStart-- > 0)
811 {
812 j = strlen(papszLines[iStart]);
813 j -= j > 1 ? 2 : j;
814 }
815
816 if (!fFound) /* fail if not found */
817 return 0;
818 jStart = j;
819
820 /* 2b.*/
821 if (strncmp(&papszLines[iStart][jStart], "/**", 3) != 0) /* checks that there are more than one star at start of comment */
822 return 0;
823
824 iName = iStart; /* Odin32 common */
825 while (iName <= iEnd &&
826 stristr(papszLines[iName], "* Name") == NULL)
827 iName++;
828 iStatus = iStart;
829 while (iStatus <= iEnd &&
830 stristr(papszLines[iStatus], "* Status") == NULL)
831 iStatus++;
832 iAuthor = iStart;
833 while (iAuthor <= iEnd &&
834 stristr(papszLines[iAuthor], "* Author") == NULL)
835 iAuthor++;
836
837 if (!(iName <= iEnd || iStatus <= iEnd || iAuthor <= iEnd)) /* if not found try SDS */
838 {
839 iStatus = iStart;
840 while (iStatus <= iEnd &&
841 stristr(papszLines[iStatus], "@status") == NULL)
842 iStatus++;
843 iAuthor = iStart;
844 while (iAuthor <= iEnd &&
845 stristr(papszLines[iAuthor], "@author") == NULL)
846 iAuthor++;
847 if (!(iStatus <= iEnd || iAuthor <= iEnd))
848 return 0;
849 fSDS = 1;
850 }
851
852 /* 2c.*/
853 if (iName <= iEnd && strstr(papszLines[iName], pFnDesc->pszName) == NULL)
854 fprintf(phLog, "Warning: a matching function name is not found in the name Field\n");
855
856 /* 2d.*/
857 pszB = &pFnDesc->szFnHdrBuffer[0];
858 if (!fSDS)
859 { /* Odin32 common */
860 if (iStatus <= iEnd) /* Status */
861 {
862 psz = stristr(papszLines[iStatus], "* Status") + sizeof("* Status") - 1;
863 while (*psz != '\0' && (*psz == ' ' || *psz == ':'))
864 psz++;
865 strcpy(pszB, psz);
866 trim(pszB);
867 if (*pszB != '\0' && pszB[strlen(pszB)-1] == '*') /* just in case some have an right hand '*' column */
868 {
869 pszB[strlen(pszB)-1] = '\0';
870 trim(pszB);
871 }
872 pFnDesc->pszStatus = pszB;
873 pszB += strlen(pszB) + 1;
874 }
875
876 if (iAuthor <= iEnd) /* Author(s) */
877 {
878 pszAuthor = pszB;
879 psz = stristr(papszLines[iAuthor], "* Author") + sizeof("* Author") - 1;
880 do
881 {
882 while (*psz != '\0' && (*psz == ' ' || *psz == ':'))
883 psz++;
884 strcpy(pszB, psz);
885 trim(pszB);
886 if (*pszB != '\0' && pszB[strlen(pszB)-1] == '*') /* just in case some have an right hand '*' column */
887 {
888 pszB[strlen(pszB)-1] = '\0';
889 trim(pszB);
890 }
891 if (*pszB != '\0' && pszB[strlen(pszB)-1] != ',')
892 strcat(pszB, ",");
893 pszB += strlen(pszB);
894
895 /* next */
896 psz = papszLines[++iAuthor] + 1;
897 j = 0;
898 while (*psz == ' ' && j++ < 5) psz++;
899 if (*psz == '*')
900 psz++;
901 } while (iAuthor < iEnd && *psz == ' ');
902 pszB++;
903 }
904 }
905 else
906 { /* SDS */
907 if (iStatus <= iEnd)
908 {
909 psz = stristr(papszLines[iStatus], "@status") + sizeof("@status");
910 while (*psz == ' ')
911 psz++;
912 strcpy(pszB, psz);
913 trim(pszB);
914 pszB += strlen(pszB) + 1;
915 }
916
917 if (iAuthor <= iEnd)
918 {
919 pszAuthor = pszB;
920 psz = stristr(papszLines[iAuthor], "@author") + sizeof("@author");
921 do
922 {
923 while (*psz == ' ')
924 psz++;
925 strcpy(pszB, psz);
926 trim(pszB);
927 if (*pszB != '\0' && pszB[strlen(pszB)-1] != ',')
928 strcat(pszB, ",");
929 pszB += strlen(pszB) + 1;
930
931 /* next */
932 psz = papszLines[++iAuthor] + 1;
933 j = 0;
934 while (*psz == ' ' && j++ < 5) psz++;
935 if (*psz == '*')
936 psz++;
937 } while (iAuthor <= iEnd && (*psz == ' ' || *psz == '@'));
938 pszB++;
939 }
940 }
941
942 /* Status - refcodes are hardcoded here! */
943 if (pFnDesc->pszStatus != NULL && *pFnDesc->pszStatus != '\0')
944 {
945 if (strstr(pFnDesc->pszStatus, "STUB") != NULL || *pFnDesc->pszStatus == '1')
946 pFnDesc->lStatus = 1; /* STUB */
947 else if (stristr(pFnDesc->pszStatus, "Partially") != NULL || *pFnDesc->pszStatus == '2' || *pFnDesc->pszStatus == '3')
948 {
949 if (stristr(pFnDesc->pszStatus, "Tested") == NULL || *pFnDesc->pszStatus == '2')
950 pFnDesc->lStatus = 2; /* STUB */
951 else
952 pFnDesc->lStatus = 3; /* STUB */
953 if (stristr(pFnDesc->pszStatus, "Open32") != NULL
954 || *pFnDesc->pszStatus == '5' || *pFnDesc->pszStatus == '7')
955 pFnDesc->lStatus += 4;
956 }
957 else if (stristr(pFnDesc->pszStatus, "Completely") != NULL || *pFnDesc->pszStatus == '4' || *pFnDesc->pszStatus == '5')
958 {
959 if (stristr(pFnDesc->pszStatus, "Tested") == NULL || *pFnDesc->pszStatus == '4')
960 pFnDesc->lStatus = 4; /* STUB */
961 else
962 pFnDesc->lStatus = 5; /* STUB */
963 if (stristr(pFnDesc->pszStatus, "Open32") != NULL
964 || *pFnDesc->pszStatus == '8' || *pFnDesc->pszStatus == '9')
965 pFnDesc->lStatus += 4;
966 }
967 else
968 {
969 fprintf(phSignal, "%s, %s: '%s' is not a valid status code.\n",
970 pszFilename, pFnDesc->pszName, pFnDesc->pszStatus);
971 ulRc += 0x00010000;
972 }
973 }
974
975 /* Author */
976 if (pszAuthor)
977 { /* author1, author2, author3 */
978 j = 0;
979 psz = trim(pszAuthor);
980 pFnDesc->cAuthors = 0;
981 while (*psz != '\0' && pFnDesc->cAuthors < (int)(sizeof(pFnDesc->apszAuthor) / sizeof(pFnDesc->apszAuthor[0])))
982 {
983 char *pszBr1 = strchr(psz, '[');
984 char *pszBr2 = strchr(psz, ']');
985 char *pszComma;
986
987 /* remove '[text]' text - this is usualy used for time/date */
988 if (pszBr1 != NULL && pszBr2 != NULL && pszBr1 < pszBr2)
989 while (pszBr1 <= pszBr2)
990 *pszBr1++ = ' ';
991
992 /* terminate string */
993 pszComma = strchr(psz, ',');
994 if (pszComma != NULL)
995 {
996 pszAuthor = pszComma + 1;
997 *pszComma = '\0';
998 }
999
1000 pFnDesc->apszAuthor[pFnDesc->cAuthors] = trim(psz);
1001 pFnDesc->alAuthorRefCode[pFnDesc->cAuthors] =
1002 dbFindAuthor(pFnDesc->apszAuthor[pFnDesc->cAuthors]);
1003
1004 if (pFnDesc->alAuthorRefCode[pFnDesc->cAuthors] == -1)
1005 {
1006 fprintf(phSignal, "%s, %s: author '%s' is not recognized.\n", pszFilename, pFnDesc->pszName,
1007 pFnDesc->apszAuthor[pFnDesc->cAuthors]);
1008 ulRc += 0x00010000;
1009 }
1010
1011 /* next */
1012 pFnDesc->cAuthors++;
1013 psz = trim(pszAuthor);
1014 }
1015 }
1016
1017 return ulRc;
1018}
1019
1020
1021/**
1022 * Checks if there may be an function starting at the current line.
1023 * @returns TRUE if API found, else FALSE.
1024 * @param papszLines Array of lines in the file.
1025 * @param i Index into papszLines.
1026 * @param pOptions Pointer to options.
1027 */
1028static BOOL isFunction(char **papszLines, int i, POPTIONS pOptions)
1029{
1030 if (!pOptions->fOld)
1031 { /* new API naming style */
1032 /* brief algorithm:
1033 * check that line don't start with '\\', '{' or '}'
1034 * search for '('.
1035 * if found then do
1036 * find c-word previous to '('
1037 * if found then do
1038 * check that the following condition are true:
1039 * 1. word is not 'for', 'while', 'do', 'if', 'else' or 'switch'
1040 * 2. first significant char after '(' should not be a '*'. (Fix for functionnames in function header, "BackupRead(".)
1041 * 3. find the matching ')' and check that the first significant char after it is '{'.
1042 * if 1, 2 and 3 are all true return true
1043 * return false.
1044 *
1045 * Note, for 2: spaces, newlines and comments are ignored, all other chars are significant.
1046 */
1047 char *pszP1 = papszLines[i];
1048
1049 while (*pszP1 != '\0' && *pszP1 == ' ')
1050 pszP1--;
1051 if (*pszP1 != '\0' && *pszP1 != '\\' && pszP1[1] != '\\'
1052 && *pszP1 != '{' && *pszP1 != '}')
1053 {
1054 pszP1 = strchr(papszLines[i], '(');
1055 if (pszP1 != NULL && pszP1 > papszLines[i])
1056 {
1057 int cchFnName = 0;
1058 char *pszFnName = pszP1 - 1;
1059
1060 while (pszFnName - cchFnName > papszLines[i] && pszFnName[cchFnName] == ' ')
1061 cchFnName--;
1062
1063 pszFnName = findStartOfWord(pszFnName, papszLines[i]);
1064 cchFnName += pszP1 - pszFnName;
1065 if (cchFnName >= 0)
1066 {
1067 /* 1. */
1068 if (
1069 strncmp(pszFnName, "for", cchFnName) != 0 &&
1070 strncmp(pszFnName, "while", cchFnName) != 0 &&
1071 strncmp(pszFnName, "do", cchFnName) != 0 &&
1072 strncmp(pszFnName, "if", cchFnName) != 0 &&
1073 strncmp(pszFnName, "else", cchFnName) != 0 &&
1074 strncmp(pszFnName, "switch", cchFnName) != 0
1075 )
1076 {
1077 /* 2. */
1078 int j = i;
1079 char *psz = skipInsignificantChars(papszLines, j, pszP1+1);
1080 if (psz != NULL && *psz != '*')
1081 {
1082 char *pszB = pszP1; /*'{'*/
1083
1084 /* 3. */
1085 while (*pszB != ')')
1086 if (*pszB++ == '\0')
1087 if ((pszB = papszLines[++i]) == NULL)
1088 break;
1089 if (pszB != NULL)
1090 {
1091 pszB = skipInsignificantChars(papszLines, i, pszB+1);
1092 if (pszB != NULL && *pszB == '{')
1093 {
1094 fprintf(phLog, "Function found: %.*s\n", cchFnName, pszFnName);
1095 return TRUE;
1096 }
1097 }
1098 }
1099 }
1100 }
1101 }
1102 }
1103 }
1104 else
1105 { /* old API naming style */
1106 char *pszOS2;
1107
1108 /* brief algorithm:
1109 * search for function prefix, 'OS2'.
1110 * if found then do
1111 * check that the following condition are true:
1112 * 1. char before 'OS2' is either start-of-line (no char), space or '*'.
1113 * 2. first significant char after the 'OS2' prefixed word is a '('.
1114 * 3. find the matching ')' and check that the first significant char after it is '{'.
1115 * if 1,2 and 3 all are true return true
1116 * return false.
1117 *
1118 * Note, for 2 and 3 spaces, newlines and comments are ignored, all other chars are significant.
1119 */
1120 pszOS2 = strstr(papszLines[i], "OS2");
1121 if (pszOS2 != NULL)
1122 {
1123 /* 1.*/
1124 if (pszOS2 == papszLines[i] || pszOS2[-1] == ' ' || pszOS2[-1] == '*')
1125 {
1126 char *pszP1; /*'('*/
1127 int cchFnName;
1128
1129 /* 2. */
1130 pszP1 = findEndOfWord(pszOS2);
1131 cchFnName = pszP1 - pszOS2;
1132 pszP1 = skipInsignificantChars(papszLines, i, pszP1);
1133
1134 if (pszP1 != NULL && *pszP1 == '(')
1135 {
1136 char *pszB = pszP1; /*'{'*/
1137
1138 /* 3. */
1139 while (*pszB != ')')
1140 if (*pszB++ == '\0')
1141 if ((pszB = papszLines[++i]) == NULL)
1142 break;
1143 if (pszB != NULL)
1144 {
1145 pszB = skipInsignificantChars(papszLines, i, pszB+1);
1146 if (pszB != NULL && *pszB == '{')
1147 {
1148 fprintf(phLog, "Possible API: %.*s\n", cchFnName, pszOS2);
1149 return TRUE;
1150 }
1151 }
1152 }
1153 }
1154 }
1155 }
1156
1157 return FALSE;
1158}
1159
1160
1161/**
1162 * Skips insignificant chars (spaces, new-lines and comments)
1163 * @returns pointer to new string posision. NULL if end of file.
1164 * @param papszLines Pointer to line table.
1165 * @param i Index into line table. (current line)
1166 * @param psz Pointer where to start (within the current line).
1167 */
1168static char *skipInsignificantChars(char **papszLines, int &i, char *psz)
1169{
1170 BOOL fComment = *psz == '/' && psz[1] == '*';
1171
1172 while (fComment || *psz == ' ' || *psz == '\0' || (*psz == '/' && psz[1] == '/'))
1173 {
1174 if (*psz == '\0' || (*psz == '/' && psz[1] == '/' && !fComment))
1175 {
1176 if ((psz = papszLines[++i]) == NULL)
1177 break;
1178 }
1179 else
1180 psz++;
1181
1182 if (fComment)
1183 {
1184 if (!(fComment = *psz != '*' || psz[1] != '/'))
1185 psz += 2;
1186 else
1187 continue;
1188 }
1189
1190 if ((fComment = *psz == '/' && psz[1] == '*') == TRUE)
1191 psz += 1 + (psz[2] != '*'); // don't add two when there is a possible end comment following.
1192 }
1193
1194 return psz;
1195}
1196
1197
1198/**
1199 * Reads a file into memory.
1200 * @returns Pointer to file. This should be freed using 'free' when processing
1201 * the file is not needed.
1202 * @param pszFilename Name of file to read.
1203 * @remark Current implementation reads the file as a binary file.
1204 */
1205static char *readFileIntoMemory(const char *pszFilename)
1206{
1207 char *pszFile = NULL;
1208 int cbFile = 0; /* don't have to initialized, but it removes gcc warning (release) */
1209 FILE *phFile;
1210
1211 phFile = fopen(pszFilename, "rb");
1212 if (phFile != NULL)
1213 {
1214 if (!fseek(phFile, 0, SEEK_END)
1215 && (cbFile = (int)ftell(phFile)) > 0
1216 && !fseek(phFile, 0, SEEK_SET)
1217 )
1218 {
1219 pszFile = (char*)malloc(cbFile + 1);
1220 if (pszFile != NULL)
1221 {
1222 #if 1
1223 memset((void*)pszFile, 0, cbFile + 1);
1224 if (fread((void*)pszFile, 1, cbFile, phFile) == 1)
1225 {
1226 free(pszFile);
1227 pszFile = NULL;
1228 }
1229 #else
1230 int cLines = 0;
1231 int cch = 0;
1232 char *psz = pszFile;
1233
1234 while (!feof(phFile) && cch < cbFile &&
1235 fgets(psz, cbFile - cch, phFile) != NULL)
1236 {
1237 int cchLine;
1238 cch += cchLine = strlen(psz);
1239 psz += cchLine;
1240 cLines++;
1241 }
1242
1243 /* error check */
1244 if (cch > cbFile || !feof(phFile))
1245 {
1246 free(pszFile);
1247 pszFile = NULL;
1248 }
1249 else
1250 *psz = '\0';
1251 #endif
1252 }
1253 }
1254 fclose(phFile);
1255 }
1256
1257 return pszFile;
1258}
1259
1260
1261/**
1262 * Creates an array of lines from a "memory" file. The last entry in the array contains NULL.
1263 * @returns Pointer to the array of lines.
1264 * @param pszFile Pointer to "memory" file.
1265 */
1266static char **createLineArray(char *pszFile)
1267{
1268 char *psz = pszFile;
1269 char **papszLines = NULL;
1270 int cLines = 0;
1271
1272 while (*psz != '\0')
1273 {
1274 if (*psz == '\r')
1275 {
1276 if (psz[1] == '\n')
1277 psz++;
1278 cLines++;
1279 } else if (*psz == '\n')
1280 cLines++;
1281 psz++;
1282 }
1283 fprintf(phLog, "%d lines\n", cLines);
1284
1285 papszLines = (char**)calloc(cLines + 1, sizeof(char *));
1286 if (papszLines != NULL)
1287 {
1288 cLines = 0;
1289 psz = pszFile;
1290 while (*psz != '\0')
1291 {
1292 if (*psz == '\r')
1293 {
1294 if (psz[1] == '\n')
1295 *psz++ = '\0';
1296 papszLines[cLines++] = psz + 1;
1297 *psz = '\0';
1298 } else if (*psz == '\n')
1299 {
1300 *psz = '\0';
1301 papszLines[cLines++] = psz + 1;
1302 }
1303 psz++;
1304 }
1305 papszLines[cLines] = NULL; /* Strictly, this is not needed as we use calloc. */
1306 }
1307
1308
1309 return papszLines;
1310}
1311
1312
1313/** first char after word */
1314static char *findEndOfWord(char *psz)
1315{
1316
1317 while (*psz != '\0' &&
1318 (
1319 (*psz >= 'A' && *psz <= 'Z') || (*psz >= 'a' && *psz <= 'z')
1320 ||
1321 (*psz >= '0' && *psz <= '9')
1322 ||
1323 *psz == '_'
1324 )
1325 )
1326 ++psz;
1327 return psz;
1328}
1329
1330
1331/** staring char of word */
1332static char *findStartOfWord(char *psz, const char *pszStart)
1333{
1334 char *pszR = psz;
1335 while (psz > pszStart &&
1336 (
1337 (*psz >= 'A' && *psz <= 'Z') || (*psz >= 'a' && *psz <= 'z')
1338 ||
1339 (*psz >= '0' && *psz <= '9')
1340 ||
1341 *psz == '_'
1342 )
1343 )
1344 pszR = psz--;
1345 return pszR;
1346}
1347
1348
1349static char *trim(char *psz)
1350{
1351 int i;
1352 if (psz == NULL)
1353 return NULL;
1354 while (*psz == ' ')
1355 psz++;
1356 i = strlen(psz) - 1;
1357 while (i >= 0 && psz[i] == ' ')
1358 i--;
1359 psz[i+1] = '\0';
1360 return psz;
1361}
1362
1363/* copy: remove remarks, and unneeded spaces, ensuring no space after '(',
1364 * ensuring space after '*', ensuring no space before ',' and ')'.
1365 */
1366
1367static void copy(char *psz, char *pszFrom, int iFrom, char *pszTo, int iTo, char **papszLines)
1368{
1369 copy(psz, pszFrom - papszLines[iFrom], iFrom, pszTo - papszLines[iTo], iTo, papszLines);
1370}
1371
1372
1373static void copy(char *psz, int jFrom, int iFrom, int jTo, int iTo, char **papszLines)
1374{
1375 char chPrev = '\n';
1376 int i, j;
1377 int fComment = 0;
1378
1379 i = iFrom;
1380 j = jFrom;
1381 while (i < iTo || (i == iTo && j <= jTo))
1382 {
1383 if (papszLines[i][j] != '\0' &&
1384 !(papszLines[i][j] == '/' && papszLines[i][j+1] == '/') /* '//' coments */
1385 )
1386 {
1387 /* copy char ? */
1388 if (!fComment)
1389 {
1390 fComment = papszLines[i][j] == '/' && papszLines[i][j+1] == '*';
1391 if (!fComment && !(chPrev == ' ' && papszLines[i][j] == ' ') /* only one space char */
1392 && !(chPrev == '(' && papszLines[i][j] == ' ') /* no space after '(' */
1393 )
1394 {
1395 if (chPrev == ' ' && (papszLines[i][j] == ',' || papszLines[i][j] == ')'))
1396 psz[-1] = papszLines[i][j]; /* no space before ',' and ')' */
1397 else
1398 {
1399 chPrev = *psz++ = papszLines[i][j];
1400 if (chPrev == '*') /* ensure ' ' after '*' */
1401 chPrev = *psz++ = ' ';
1402 }
1403 }
1404 }
1405 else
1406 if ((fComment = papszLines[i][j] != '*' || papszLines[i][j+1] != '/') == 0)
1407 j++;
1408 j++;
1409 }
1410 else
1411 {
1412 /* next */
1413 j = 0;
1414 i++;
1415 if (chPrev != ' ' && chPrev != '(')
1416 chPrev = *psz++ = ' ';
1417 }
1418 }
1419 *psz = '\0';
1420}
1421
1422
1423/**
1424 * Upcases a char.
1425 * @returns Upper case of the char given in ch.
1426 * @param ch Char to capitalize.
1427 */
1428inline char upcase(char ch)
1429{
1430 return ch >= 'a' && ch <= 'z' ? (char)(ch - ('a' - 'A')) : ch;
1431}
1432
1433
1434/**
1435 * Searches for a substring in a string.
1436 * @returns Pointer to start of substring when found, NULL when not found.
1437 * @param pszStr String to be searched.
1438 * @param pszSubStr String to be searched.
1439 * @remark Depends on the upcase function.
1440 */
1441static char *stristr(const char *pszStr, const char *pszSubStr)
1442{
1443 int cchSubStr = strlen(pszSubStr);
1444 int i = 0;
1445
1446 while (*pszStr != '\0' && i < cchSubStr)
1447 {
1448 i = 0;
1449 while (i < cchSubStr && pszStr[i] != '\0' &&
1450 (upcase(pszStr[i]) == upcase(pszSubStr[i])))
1451 i++;
1452 pszStr++;
1453 }
1454
1455 return (char*)(*pszStr != '\0' ? pszStr - 1 : NULL);
1456}
1457
Note: See TracBrowser for help on using the repository browser.