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

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

Parameter change.

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