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

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

Odin32 DB.

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