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

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

Corrected dll argument process.

File size: 78.4 KB
Line 
1/* $Id: StateUpd.cpp,v 1.21 2000-03-14 16:31:17 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#define INCL_DOSPROCESS
16#include <os2.h>
17#include <malloc.h>
18#include <stdio.h>
19#include <string.h>
20#include <stdlib.h>
21#include <assert.h>
22
23#include "StateUpd.h"
24#include "db.h"
25
26
27
28/*******************************************************************************
29* Global Variables *
30*******************************************************************************/
31static FILE *phLog = NULL;
32static FILE *phSignal = NULL;
33
34static const char *pszCommonKeywords[] =
35{
36 "* Author", "* Status", "* Remark", "* Result",
37 "* Variable", "* Parameters", "* Purpose", NULL
38};
39
40
41/*******************************************************************************
42* Internal Functions *
43*******************************************************************************/
44static void syntax(void);
45static void openLogs(void);
46static void closeLogs(void);
47static unsigned long processDir(const char *pszDirOrFile, POPTIONS pOptions);
48static unsigned long processFile(const char *pszFilename, POPTIONS pOptions);
49static unsigned long processAPI(char **papszLines, int i, int &iRet, const char *pszFilename, POPTIONS pOptions);
50static unsigned long analyseFnHdr(PFNDESC pFnDesc, char **papszLines, int i, const char *pszFilename, POPTIONS pOptions);
51static unsigned long analyseFnDcl(PFNDESC pFnDesc, char **papszLines, int i, int &iRet, const char *pszFilename, POPTIONS pOptions);
52static unsigned long analyseFnDcl2(PFNDESC pFnDesc, char **papszLines, int i, int &iRet, const char *pszFilename, POPTIONS pOptions);
53static char *SDSCopyTextUntilNextTag(char *pszTarget, BOOL fHTML, int iStart, int iEnd, char **papszLines, const char *pszStart = NULL);
54static char *CommonCopyTextUntilNextTag(char *pszTarget, BOOL fHTML, int iStart, int iEnd, char **papszLines, const char *pszStart = NULL);
55static BOOL isFunction(char **papszLines, int i, POPTIONS pOptions);
56static long _System dbNotUpdatedCallBack(const char *pszValue, const char *pszFieldName, void *pvUser);
57static char *skipInsignificantChars(char **papszLines, int &i, char *psz);
58static char *readFileIntoMemory(const char *pszFilename);
59static char **createLineArray(char *pszFile);
60static char *findEndOfWord(const char *psz);
61static char *findStartOfWord(const char *psz, const char *pszStart);
62inline char *trim(char *psz);
63inline char *trimR(char *psz);
64inline char *skip(const char *psz);
65static void copy(char *psz, int jFrom, int iFrom, int jTo, int iTo, char **papszLines);
66static void copy(char *psz, char *pszFrom, int iFrom, char *pszTo, int iTo, char **papszLines);
67static char *stristr(const char *pszStr, const char *pszSubStr);
68static char *skipBackwards(const char *pszStopAt, const char *pszFrom, int &iLine, char **papszLines);
69static int findStrLine(const char *psz, int iStart, int iEnd, char **papszLines);
70
71
72/**
73 * Main function.
74 * @returns Number of signals.
75 * @param argc Argument count.
76 * @param argv Argument array.
77 */
78int main(int argc, char **argv)
79{
80 int argi;
81 BOOL fFatal = FALSE;
82 unsigned long ulRc = 0;
83 char szDLLName[64];
84 OPTIONS options = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, &szDLLName[0], -1};
85 unsigned long ulRc2;
86 char *pszErrorDesc = NULL;
87 char *pszHost = "localhost";
88 char *pszDatabase = "Odin32";
89 char *pszUser = "root";
90 char *pszPasswd = "";
91 ULONG ul0, ul1, ul2;
92
93 DosError(0x3);
94 DosSetPriority(PRTYS_PROCESSTREE, PRTYC_REGULAR, 1, 0);
95
96 /* get dll name from directory */
97 ul1 = ul2 = 0;
98 DosQueryCurrentDisk(&ul1, &ul2);
99 ul2 = sizeof(szDLLName);
100 DosQueryCurrentDir(ul1, &szDLLName[0], &ul2);
101 if (ul2 != 0)
102 {
103 if (szDLLName[ul2-1] == '\\' || szDLLName[ul2-1] == '/')
104 szDLLName[--ul2] = '\0';
105 ul1 = ul2;
106 while (ul1 != 0 && szDLLName[ul1-1] != '\\' && szDLLName[ul1-1] != '/')
107 ul1--;
108 if (ul1 != 0)
109 options.pszDLLName = &szDLLName[ul1];
110 }
111 else
112 szDLLName[0] = '\0';
113
114
115 /**************************************************************************
116 * parse arguments.
117 * options: -h or -? Syntax help.
118 * -ib<[+]|-> Integrity check at start.
119 * -ie<[+]|-> Integrity check at end.
120 * -io Integrity check only.
121 * -s Scan subdirectories.
122 * -Old <[+]|-> Old API Style.
123 * -OS2<[+]|-> Removes 'OS2'-prefix from function name.
124 * -COMCTL32<[+]|-> Removes 'COMCTL32'-prefix from function name.
125 * -VERSION<[+]|-> Removes 'VERSION'-prefix from function name.
126 * -Dll:<dllname> Name of the dll being processed.
127 * -d:<dbname> Database name
128 * -p:<passwd> Password
129 * -u:<user> Userid
130 * -h:<host> Hostname/IP-address
131 **************************************************************************/
132 argi = 1;
133 while (argi < argc && !fFatal)
134 {
135 if(argv[argi][0] == '-' || argv[argi][0] == '/')
136 {
137 switch (argv[argi][1])
138 {
139 case 'd':
140 case 'D':
141 if (&strnicmp(argv[argi][1], "dll:", 4) == 0 )
142 options.pszDLLName = &argv[argi][5];
143 else
144 {
145 if (argv[argi][2] == ':')
146 pszDatabase = &argv[argi][3];
147 else
148 fprintf(stderr, "warning: option '-d:' requires database name.\n");
149 }
150 break;
151
152 case 'h':
153 case 'H':
154 if (argv[argi][2] == ':')
155 {
156 pszHost = &argv[argi][3];
157 break;
158 }
159 case '?':
160 syntax();
161 return 0;
162
163 case 'i': /* Integrity */
164 case 'I':
165 switch (argv[argi][2])
166 {
167 case 'b':
168 case 'B':
169 options.fIntegrityBefore = argv[argi][3] != '-';
170 break;
171
172 case 'e':
173 case 'E':
174 options.fIntegrityAfter = argv[argi][3] != '-';
175 break;
176
177 case 'o':
178 case 'O':
179 options.fIntegrityOnly = argv[argi][3] != '-';
180 break;
181
182 default:
183 fprintf(stderr, "incorrect parameter. (argi=%d, argv[argi]=%s)\n", argi, argv[argi]);
184 fFatal = TRUE;
185 }
186 break;
187
188 case 'o':
189 case 'O':
190 if (stricmp(&argv[argi][1], "OS2") == 0)
191 options.fOS2 = argv[argi][4] != '-';
192 else if (stricmp(&argv[argi][1], "Old") == 0)
193 options.fOld = argv[argi][4] != '-';
194 else
195 {
196 fprintf(stderr, "incorrect parameter. (argi=%d, argv[argi]=%s)\n", argi, argv[argi]);
197 fFatal = TRUE;
198 }
199 break;
200
201 case 'p':
202 case 'P':
203 if (argv[argi][2] == ':')
204 pszPasswd = &argv[argi][3];
205 else
206 fprintf(stderr, "warning: option '-p:' requires password.\n");
207 break;
208
209 case 's':
210 case 'S':
211 options.fRecursive = TRUE;
212 fprintf(stderr, "This option (-s) is currently broken\n");
213 return -1;
214
215 case 'u':
216 case 'U':
217 if (argv[argi][2] == ':')
218 pszUser = &argv[argi][3];
219 else
220 fprintf(stderr, "error: option '-u:' requires userid.\n");
221 break;
222
223 default:
224 fprintf(stderr, "incorrect parameter. (argi=%d, argv[argi]=%s)\n", argi, argv[argi]);
225 fFatal = TRUE;
226 break;
227 }
228 }
229 else
230 break; /* files has started */
231 argi++;
232 }
233
234 if (!fFatal)
235 {
236 /* open database */
237 if (!dbConnect(pszHost, pszUser, pszPasswd, pszDatabase))
238 {
239 fprintf(stderr, "Could not connect to database (%s). \n\terror description: %s\n",
240 pszDatabase, dbGetLastErrorDesc());
241 return 0x00010001;
242 }
243
244 /* open the logs */
245 openLogs();
246
247 /* check db integrity */
248 if (options.fIntegrityBefore || options.fIntegrityOnly)
249 {
250 pszErrorDesc = (char*)malloc(1048768); assert(pszErrorDesc != NULL);
251 *pszErrorDesc = '\0';
252 ulRc2 = dbCheckIntegrity(pszErrorDesc);
253 if (ulRc2 != 0)
254 {
255 fprintf(phSignal, "-,-: integrity errors:\n\t%s\n", pszErrorDesc);
256 ulRc += ulRc2 << 16;
257 }
258 free(pszErrorDesc);
259 }
260
261 if (!options.fIntegrityOnly)
262 {
263 /* find dll */
264 options.lDllRefcode = dbGetDll(options.pszDLLName);
265 fprintf(phLog, "DLL: refcode=%d, name=%s\n", options.lDllRefcode, options.pszDLLName);
266
267 /* processing */
268 if (argv[argi] == NULL || *argv[argi] == '\0')
269 ulRc = processDir(".", &options);
270 else
271 while (argv[argi] != NULL)
272 {
273 ulRc += processDir(argv[argi], &options);
274 argi++;
275 }
276
277 /* create new history rows */
278 pszErrorDesc = (char*)malloc(1048768); assert(pszErrorDesc != NULL);
279 *pszErrorDesc = '\0';
280 ulRc2 = dbCreateHistory(pszErrorDesc);
281 if (ulRc2 != 0)
282 {
283 fprintf(phSignal, "-,-: errors which occurred while creating history:\n\t%s\n", pszErrorDesc);
284 ulRc += ulRc2 << 16;
285 }
286 free(pszErrorDesc);
287
288 /* check db integrity */
289 if (options.fIntegrityAfter)
290 {
291 pszErrorDesc = (char*)malloc(1048768); assert(pszErrorDesc != NULL);
292 *pszErrorDesc = '\0';
293 ulRc2 = dbCheckIntegrity(pszErrorDesc);
294 if (ulRc2 != 0)
295 {
296 fprintf(phSignal, "-,-: integrity errors:\n\t%s\n", pszErrorDesc);
297 ulRc += ulRc2 << 16;
298 }
299 free(pszErrorDesc);
300 }
301 }
302
303 /* write status to log */
304 if (!options.fIntegrityOnly)
305 {
306 ul2 = dbGetNumberOfUpdatedFunction(options.lDllRefcode);
307 ul1 = dbCountFunctionInDll(options.lDllRefcode, FALSE);
308 ul0 = dbCountFunctionInDll(options.lDllRefcode, TRUE);
309 if (ul0 > ul2)
310 {
311 fprintf(phSignal, "%d functions where not found (found=%d, total=%d).\n", ul0 - ul2, ul2, ul0);
312 ulRc += 0x00010000;
313 }
314 fprintf(phLog, "-------------------------------------------------\n");
315 fprintf(phLog, "-------- Functions which was not updated --------\n");
316 dbGetNotUpdatedFunction(options.lDllRefcode, dbNotUpdatedCallBack);
317 fprintf(phLog, "-------------------------------------------------\n");
318 fprintf(phLog, "-------------------------------------------------\n\n");
319 fprintf(phLog,"Number of function in this DLL: %4ld (%ld)\n", ul1, ul0);
320 fprintf(phLog,"Number of successfully processed APIs: %4ld (%ld)\n", (long)(0x0000FFFF & ulRc), ul2);
321 }
322 fprintf(phLog,"Number of signals: %4ld\n", (long)(ulRc >> 16));
323
324 /* close the logs */
325 closeLogs();
326
327 /* close database */
328 dbDisconnect();
329
330 /* warn if error during processing. */
331 if (!options.fIntegrityOnly)
332 {
333 fprintf(stdout,"Number of function in this DLL: %4ld (%ld)\n", ul1, ul0);
334 fprintf(stdout,"Number of successfully processed APIs: %4ld (%ld)\n", (long)(0x0000FFFF & ulRc), ul2);
335 }
336 fprintf(stdout,"Number of signals: %4ld\n", (long)(ulRc >> 16));
337 if ((int)(ulRc >> 16) > 0)
338 fprintf(stderr, "Check signal file 'Signals.Log'.\n");
339 }
340
341 return (int)(ulRc >> 16);
342}
343
344
345
346/**
347 * Displays syntax.
348 */
349static void syntax()
350{
351 printf("\n"
352 "StateUpd v%01d.%02d - Odin32 API Database utility\n"
353 "----------------------------------------------\n"
354 "syntax: StateUpd.exe [-h|-?] [options] [FileOrDir1 [FileOrDir2 [...]]]\n"
355 "\n"
356 " -h or -? Syntax help. (this)\n"
357 " -ib<[+]|-> Integrity check at start. default: disabled\n"
358 " -ie<[+]|-> Integrity check at end. default: disabled\n"
359 " -io Integrity check only. default: disabled\n"
360 " -s Scan subdirectories. default: disabled\n"
361 " -Old Use old API style. default: disabled\n"
362 " -OS2 Ignore 'OS2'-prefix on APIs. default: disabled\n"
363 " -Dll:<dllname> Name of the dll. default: dirname\n"
364 " -h:<hostname> Database server hostname. default: localhost\n"
365 " -u:<username> Username on the server. default: root\n"
366 " -p:<password> Password. default: <empty>\n"
367 " -d:<database> Database to use. default: Odin32\n"
368 "\n"
369 "Scans files for API functions. This util will extract data about the API\n"
370 "and insert it into the database.\n"
371 "\n"
372 "If no files are given, then all *.c and *.cpp files will be scanned. (Not correct!)\n"
373 "NOTE: When files are given, only *.c and *.cpp files will be scanned.\n"
374 "Wildchars are allowed in the file spesifications.\n"
375 "\n"
376 "Copyright (c) 1999 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)",
377 MAJOR_VER, MINOR_VER
378 );
379}
380
381
382/**
383 * Open logs, StateUpd.log and Signals.log (error log).
384 */
385static void openLogs(void)
386{
387 if (phLog == NULL)
388 {
389 phLog = fopen("StateUpd.Log", "w");
390 if (phLog == NULL)
391 {
392 fprintf(stderr,"error occured while opening log file - will use stderr instead.\n");
393 phLog = stderr;
394 }
395 }
396
397 if (phSignal == NULL)
398 {
399 phSignal = fopen("Signals.Log", "w");
400 if (phSignal == NULL)
401 {
402 fprintf(stderr,"error occured while opening signal file - will use stdout instead.\n");
403 phSignal = stdout;
404 }
405 }
406}
407
408
409/**
410 * Closes the logs.
411 */
412static void closeLogs(void)
413{
414 if (phLog != stderr && phLog != NULL)
415 fclose(phLog);
416 if (phSignal != stdout && phSignal != NULL)
417 {
418 if (ftell(phSignal) > 0)
419 fclose(phSignal);
420 else
421 {
422 fclose(phSignal);
423 unlink("Signals.log");
424 }
425 }
426}
427
428
429/**
430 * Processes a file or a subdirectory with files.
431 * @returns high word = number of signals
432 * low word = number of APIs processed. (1 or 0).
433 * @param pszDirOrFile Directory or file, see fFile.
434 * @param pOptions Pointer to options.
435 * @sketch -0. Determin dir or file.
436 * 0. Interpret parameters.
437 * 1. Scan current directory for *.cpp and *.c files and process them.
438 * 2. If recusion option is enabled:
439 * Scan current directory for sub-directories, scan them using recursion.
440 */
441static unsigned long processDir(const char *pszDirOrFile, POPTIONS pOptions)
442{
443 unsigned long ulRc = 0; /* high word = #signals, low word = #APIs successfully processed */
444 char szBuf[CCHMAXPATH];
445 char szFileSpec[CCHMAXPATH];
446 APIRET rc;
447 FILEFINDBUF3 ffb;
448 FILESTATUS3 fs;
449 ULONG ul = 1;
450 HDIR hDir = (HDIR)HDIR_CREATE;
451 PSZ pszDir;
452 PSZ pszFile;
453 BOOL fFile;
454
455 /* -0.*/
456 rc = DosQueryPathInfo(pszDirOrFile, FIL_STANDARD, &fs , sizeof(fs));
457 fFile = rc == NO_ERROR && (fs.attrFile & FILE_DIRECTORY) != FILE_DIRECTORY;
458
459 /* 0. */
460 strcpy(szBuf, pszDirOrFile);
461 pszDir = szBuf;
462 if (fFile)
463 {
464 if ((pszFile = strrchr(pszDir, '\\')) != NULL
465 || (pszFile = strrchr(pszDir, '/')) != NULL)
466 *pszFile++ = '\0';
467 else
468 {
469 pszFile = pszDir;
470 pszDir = ".";
471 }
472 }
473 else
474 {
475 pszFile = NULL;
476 ul = strlen(pszDir)-1;
477 if (pszDir[ul] == '\\' || pszDir[ul] == '/')
478 pszDir[ul] = '\0';
479 }
480
481
482 /* 1. */
483 if (fFile)
484 strcat(strcat(strcpy(&szFileSpec[0], pszDir), "\\"), pszFile);
485 else
486 strcat(strcpy(&szFileSpec[0], pszDir), "\\*.c*");
487 ul = 1;
488 rc = DosFindFirst((PCSZ)&szFileSpec[0], &hDir,
489 FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_ARCHIVED,
490 (PVOID)&ffb, sizeof(ffb), &ul, FIL_STANDARD);
491 while (rc == NO_ERROR && ul == 1)
492 {
493 char *psz = strrchr(&ffb.achName[0], '.');
494 if (psz != NULL && (!stricmp(psz, ".cpp") || !stricmp(psz, ".c")))
495 ulRc += processFile(strcat(strcat(strcpy(&szFileSpec[0], pszDir), "\\"), &ffb.achName[0]), pOptions);
496
497 /* next */
498 ul = 1;
499 rc = DosFindNext(hDir, &ffb, sizeof(ffb), &ul);
500 }
501 DosFindClose(hDir);
502
503 /* 2. */
504 if (pOptions->fRecursive)
505 {
506 strcat(strcpy(&szFileSpec[0], pszDir), "\\*");
507
508 hDir = (HDIR)HDIR_CREATE;
509 ul = 1; /* important on TVFS, not on HPFS... */
510 rc = DosFindFirst((PCSZ)&szFileSpec[0], &hDir,
511 MUST_HAVE_DIRECTORY,
512 (PVOID)&ffb, sizeof(ffb), &ul, FIL_STANDARD);
513 while (rc == NO_ERROR && ul == 1)
514 {
515 if (strcmp(&ffb.achName[0], ".") != 0 && strcmp(&ffb.achName[0], "..") != 0)
516 {
517 strcat(strcat(strcpy(&szFileSpec[0], pszDir), "\\"), &ffb.achName[0]);
518 if (fFile)
519 strcat(strcat(&szFileSpec[0], "\\"), pszFile);
520 ulRc += processDir(&szFileSpec[0], pOptions);
521 }
522
523 /* next */
524 ul = 1;
525 rc = DosFindNext(hDir, &ffb, sizeof(ffb), &ul);
526 }
527 DosFindClose(hDir);
528 }
529
530 return ulRc;
531}
532
533
534/**
535 * Processes a file.
536 * @returns high word = number of signals
537 * low word = number of APIs processed. (1 or 0).
538 * @param pszFilename Filename
539 * @param pOptions Pointer to options.
540 * @sketch 1. read file into memory.
541 * 2. create line array.
542 * (3. simple preprocessing - TODO)
543 * 4. scan thru the line array, looking for APIs.
544 * 4b. when API is found, process it.
545 */
546static unsigned long processFile(const char *pszFilename, POPTIONS pOptions)
547{
548 unsigned long cSignals = 0;
549 unsigned long cAPIs = 0;
550 char *pszFile;
551
552 fprintf(phLog, "Processing '%s':\n", pszFilename);
553 /* 1.*/
554 pszFile = readFileIntoMemory(pszFilename);
555 if (pszFile != NULL)
556 {
557 char **papszLines;
558
559 /* 2.*/
560 papszLines = createLineArray(pszFile);
561 if (papszLines != NULL)
562 {
563 int i = 0;
564
565 /* 3. - TODO */
566
567 /* 4.*/
568 while (papszLines[i] != NULL)
569 {
570 if (isFunction(papszLines, i, pOptions))
571 {
572 unsigned long ulRc;
573 ulRc = processAPI(papszLines, i, i, pszFilename, pOptions);
574 cAPIs += 0x0000ffff & ulRc;
575 cSignals += ulRc >> 16;
576 }
577 else
578 i++;
579 }
580
581 free(papszLines);
582 }
583 else
584 {
585 fprintf(phSignal,"%s: error dividing file into lines.\n", pszFilename);
586 cSignals++;
587 }
588 free(pszFile);
589 }
590 else
591 {
592 fprintf(phSignal,"%s: error reading file.\n", pszFilename);
593 cSignals++;
594 }
595 fprintf(phLog, "Processing of '%s' is completed.\n\n", pszFilename);
596
597
598 return (unsigned long)((cSignals << 16) | cAPIs);
599}
600
601
602/**
603 * Processes an API function.
604 * @returns high word = number of signals
605 * low word = number of APIs processed. (1 or 0).
606 * @param papszLines Array of lines in the file.
607 * @param i Index into papszLines.
608 * @param iRet Index into papszLines. Where to resume search.
609 * @param pszFilename Filename used in the signal log.
610 * @param pOptions Pointer to options.
611 */
612static unsigned long processAPI(char **papszLines, int i, int &iRet, const char *pszFilename, POPTIONS pOptions)
613{
614 unsigned long ulRc;
615 int j;
616 FNDESC FnDesc;
617 memset(&FnDesc, 0, sizeof(FnDesc));
618
619 /* default value */
620 FnDesc.lStatus = 99;
621
622 /* precondition: isFunction is true.
623 * brief algorithm:
624 * 1. Analyse function declaration.
625 * 2. Analyse function header.
626 * 3. Log data (for debug purpose).
627 * 4. Update database
628 */
629
630 /* 1.*/
631 ulRc = analyseFnDcl(&FnDesc, papszLines, i, iRet, pszFilename, pOptions);
632 if (0x0000ffff & ulRc) /* if low word is 0 the fatal */
633 {
634 unsigned long ulRcTmp;
635 //char szErrorDesc[2113]; /* due to some limitation in the latest EMX release size is 2112 and not 4096 as initially implemented. */
636 char *pszErrorDesc = (char*)malloc(20480);
637
638 /* 2.*/
639 ulRcTmp = analyseFnHdr(&FnDesc, papszLines, i, pszFilename, pOptions);
640 if (ulRcTmp == ~0UL) /* check for fatal error */
641 return (0xffff0000UL & ulRc) + 0x00010000UL;
642 ulRc += 0xffff0000UL & ulRcTmp;
643
644 /* 3.*/
645 fprintf(phLog, "Name: '%s' (refcodes=", FnDesc.pszName);
646 for (j = 0; j < FnDesc.cRefCodes; j++)
647 fprintf(phLog, j > 0 ? ", %ld" : "%ld", FnDesc.alRefCode[j]);
648 fprintf(phLog, ")\n");
649 fprintf(phLog, " Returns: '%s'\n", FnDesc.pszReturnType != NULL ? FnDesc.pszReturnType : "<missing>");
650 fprintf(phLog, " cParams: %2d\n", FnDesc.cParams);
651 for (j = 0; j < FnDesc.cParams; j++)
652 fprintf(phLog, " Param %2d: type '%s' %*s name '%s' description: %s\n", j, FnDesc.apszParamType[j],
653 max((int)(15 - strlen(FnDesc.apszParamType[j])), 0), "", FnDesc.apszParamName[j],
654 FnDesc.apszParamDesc[j] != NULL ? FnDesc.apszParamDesc[j] : "(null)");
655 fprintf(phLog, " Status: %ld - '%s'\n", FnDesc.lStatus, FnDesc.pszStatus != NULL ? FnDesc.pszStatus : "<missing>");
656 fprintf(phLog, " cAuthors: %2d\n", FnDesc.cAuthors);
657 for (j = 0; j < FnDesc.cAuthors; j++)
658 fprintf(phLog, " Author %d: '%s' (refcode=%ld)\n", j, FnDesc.apszAuthor[j], FnDesc.alAuthorRefCode[j]);
659
660 fprintf(phLog, " Description: %s\n", FnDesc.pszDescription != NULL ? FnDesc.pszDescription : "(null)");
661 fprintf(phLog, " Remark: %s\n", FnDesc.pszRemark != NULL ? FnDesc.pszRemark : "(null)");
662 fprintf(phLog, " Return Desc: %s\n", FnDesc.pszReturnDesc != NULL ? FnDesc.pszReturnDesc : "(null)");
663 fprintf(phLog, " Sketch: %s\n", FnDesc.pszSketch != NULL ? FnDesc.pszSketch : "(null)");
664 fprintf(phLog, " Equiv: %s\n", FnDesc.pszEquiv != NULL ? FnDesc.pszEquiv : "(null)");
665 fprintf(phLog, " Time: %s\n", FnDesc.pszTime != NULL ? FnDesc.pszTime : "(null)");
666 fprintf(phLog, "------------\n");
667
668 /* 4.*/
669 ulRcTmp = dbUpdateFunction(&FnDesc, pOptions->lDllRefcode, pszErrorDesc);
670 if (ulRcTmp != 0)
671 {
672 fprintf(phSignal, "%s,%s: %s\n", pszFilename, FnDesc.pszName, pszErrorDesc);
673 ulRc += ulRcTmp << 16;
674 }
675 free(pszErrorDesc);
676 }
677
678 return ulRc;
679}
680
681
682/**
683 * Analyses the function declaration.
684 * @returns high word = number of signals
685 * low word = number of APIs processed. (1 or 0).
686 * @param papszLines Array of lines in the file.
687 * @param i Index into papszLines.
688 * @param iRet Index into papszLines. Where to start searching again.
689 * @param pszFilename Filename used in the signal log.
690 * @param pOptions Pointer to options.
691 */
692static unsigned long analyseFnDcl(PFNDESC pFnDesc, char **papszLines, int i, int &iRet,
693 const char *pszFilename, POPTIONS pOptions)
694{
695 static long lPrevFnDll = -1L; /* fix for duplicate dlls */
696 unsigned long ulRc;
697 FNFINDBUF FnFindBuf;
698 long lFn = 0;
699
700 /* brief algorithm:
701 * 1. read function declaration using analyseFnDcl2.
702 * 2. apply name rules.
703 * 3. do a database lookup on the name.
704 * 3b. if more that one match, write a signal. (TODO: a simple fix is done, but there are holes.)
705 */
706
707 /* 1. */
708 ulRc = analyseFnDcl2(pFnDesc, papszLines, i, iRet, pszFilename, pOptions);
709 if (ulRc != 1)
710 return ulRc;
711
712 /* 2. */
713 if (pOptions->fOS2 && strncmp(pFnDesc->pszName, "OS2", 3) == 0)
714 pFnDesc->pszName += 3;
715 else if (pOptions->fCOMCTL32 && strncmp(pFnDesc->pszName, "COMCTL32", 8) == 0)
716 pFnDesc->pszName += 8;
717 else if (pOptions->fVERSION && strncmp(pFnDesc->pszName, "VERSION", 7) == 0)
718 pFnDesc->pszName += 7;
719 else if (pOptions->fOld)
720 pFnDesc->pszName += 3;
721
722 /* 3. */
723 if (!dbFindFunction(pFnDesc->pszName, &FnFindBuf, pOptions->lDllRefcode))
724 {
725 fprintf(phSignal, "%s, %s: error occured while reading from database, %s\n",
726 pszFilename, pFnDesc->pszName, dbGetLastErrorDesc());
727 return 0x00010000;
728 }
729
730 pFnDesc->cRefCodes = 0;
731 if (FnFindBuf.cFns != 0)
732 {
733 if (pOptions->lDllRefcode < 0)
734 {
735 if (FnFindBuf.cFns > 1)
736 {
737 fprintf(phSignal, "%s: unknown dll and more than two occurences of this function!\n", pszFilename);
738 return 0x00010000;
739 }
740 pOptions->lDllRefcode = FnFindBuf.alDllRefCode[0];
741 fprintf(phLog, "DllRef = %d\n", pOptions->lDllRefcode);
742 }
743
744 for (lFn = 0; lFn < FnFindBuf.cFns; lFn++)
745 pFnDesc->alRefCode[pFnDesc->cRefCodes++] = FnFindBuf.alRefCode[lFn];
746
747 if (pFnDesc->cRefCodes == 0)
748 fprintf(phLog, "%s was not an API in this dll(%d)!\n", pFnDesc->pszName, pOptions->lDllRefcode);
749 }
750 else
751 fprintf(phLog, "%s was not an API\n", pFnDesc->pszName);
752
753 ulRc = pFnDesc->cRefCodes;
754 return ulRc;
755}
756
757
758
759/**
760 * Analyses the function declaration.
761 * No DB lockup or special function type stuff, only ODINFUNCTION is processed.
762 * @returns high word = number of signals
763 * low word = number of APIs processed. (1 or 0).
764 * @param papszLines Array of lines in the file.
765 * @param i Index into papszLines.
766 * @param iRet Index into papszLines. Where to start searching again.
767 * @param pszFilename Filename used in the signal log.
768 * @param pOptions Pointer to options.
769 */
770static unsigned long analyseFnDcl2(PFNDESC pFnDesc, char **papszLines, int i, int &iRet,
771 const char *pszFilename, POPTIONS pOptions)
772{
773 /** @sketch
774 * 1. find the '('
775 * 2. find the word ahead of the '(', this is the function name.
776 * 2a. class test.
777 * 3. find the closing ')'
778 * 4. copy the parameters, which is between the two '()'
779 * 5. format the parameters
780 */
781
782 int iFn, iP1, iP2, j, c;
783 char * pszFn, *pszFnEnd, *pszP1, *pszP2;
784 char * psz, *pszEnd;
785 int cArgs;
786 char * apszArgs[30];
787 int iClass;
788 char * pszClass, *pszClassEnd;
789
790 /* 1.*/
791 iP1 = i;
792 while (papszLines[iP1] != NULL
793 && (pszP1 = strchr(papszLines[iP1], '(')) == NULL)
794 iP1++;
795 if (papszLines[iP1] == NULL)
796 {
797 fprintf(phSignal, "%d: oops! didn't find end of function!, %d\n", pszFilename, __LINE__);
798 iRet = iP1+1;
799 return 0x00010000;
800 }
801
802 /* 2. */
803 iFn = iP1;
804 if (papszLines[iFn] != pszP1)
805 pszFn = pszP1 - 1;
806 else
807 {
808 pszFn = papszLines[--iFn];
809 pszFn += strlen(pszFn) - (*pszFn != '\0');
810 }
811 while (iFn >= 0 && *pszFn == ' ')
812 {
813 if (pszFn != papszLines[iFn])
814 pszFn--;
815 else
816 {
817 pszFn = papszLines[--iFn];
818 pszFn += strlen(pszFn) - (*pszFn != '\0');
819 }
820 }
821 if (iFn < 0 || *pszFn == ' ' || *pszFn == '\0')
822 {
823 fprintf(phSignal, "%s: internal error!, %d\n", pszFilename, __LINE__);
824 iRet = iP1+1;
825 return 0x00010000;
826 }
827 pszFnEnd = pszFn;
828 pszFn = findStartOfWord(pszFn, papszLines[iFn]);
829
830 /* 2a. */
831 /* operators are not supported (BOOL kTime::operator > (const kTime &time) const) */
832 if (pszFn > papszLines[iFn])
833 {
834 pszClassEnd = pszFn - 1;
835 iClass = iFn;
836 }
837 else
838 {
839 pszClassEnd = pszFn - 1;
840 iClass = iFn - 1;
841 }
842 c = 2;
843 while (iClass >= 0 && c >= 0)
844 {
845 if (*pszClassEnd == ':')
846 c--;
847 else if (*pszClassEnd != ' ')
848 break;
849 pszClassEnd--;
850 }
851 if (*pszClassEnd != ' ' && c == 0)
852 pszClass = findStartOfWord(pszClassEnd, papszLines[iClass]);
853 else
854 pszClass = pszClassEnd = NULL;
855
856 /* 3. */
857 c = 1;
858 iP2 = iP1;
859 pszP2 = pszP1 + 1;
860 while (c > 0)
861 {
862 if (*pszP2 == '(')
863 c++;
864 else if (*pszP2 == ')')
865 if (--c == 0)
866 break;
867 if (*pszP2++ == '\0')
868 if ((pszP2 = papszLines[++iP2]) == NULL)
869 break;
870 }
871
872 iRet = iP2 + 1; //assumes: only one function on a single line!
873
874 /* 4. */
875 psz = pFnDesc->szFnDclBuffer;
876 copy(pFnDesc->szFnDclBuffer, pszP1, iP1, pszP2, iP2, papszLines);
877 pszEnd = psz + strlen(psz) + 1;
878
879 /* 5.*/
880 cArgs = 0;
881 if (stricmp(psz, "(void)") != 0 && strcmp(psz, "()") != 0 && strcmp(psz, "( )"))
882 {
883 char *pszC;
884 pszC = trim(psz+1);
885 c = 1;
886 while (*pszC != '\0')
887 {
888 apszArgs[cArgs] = pszC;
889 while (*pszC != ',' && c > 0 && *pszC != '\0')
890 {
891 if (*pszC == '(')
892 c++;
893 else if (*pszC == ')')
894 if (--c == 0)
895 break;
896 pszC++;
897 }
898 *pszC = '\0';
899 trim(apszArgs[cArgs++]);
900
901 /* next */
902 pszC = trim(pszC + 1);
903 }
904 }
905
906 /* 6. */
907 if (strnicmp(pszFn, "ODINFUNCTION", 12) == 0 || strnicmp(pszFn, "ODINPROCEDURE", 13) == 0)
908 {
909 BOOL fProc = strnicmp(pszFn, "ODINPROCEDURE", 13) == 0;
910 j = 0;
911 if (cArgs < (fProc ? 1 : 2))
912 {
913 fprintf(phSignal, "%s: Invalid ODINFUNCTION function too few parameters!\n", pszFilename);
914 return 0x00010000;
915 }
916
917 /* return type */
918 if (fProc)
919 pFnDesc->pszReturnType = "void";
920 else
921 pFnDesc->pszReturnType = apszArgs[j++];
922
923 /* function name */
924 pFnDesc->pszName = apszArgs[j++];
925
926 /* arguments */
927 pFnDesc->cParams = 0;
928 while (j+1 < cArgs)
929 {
930 pFnDesc->apszParamType[pFnDesc->cParams] = apszArgs[j];
931 pFnDesc->apszParamName[pFnDesc->cParams] = apszArgs[j+1];
932 pFnDesc->cParams++;
933 j += 2;
934 }
935 }
936 else
937 {
938 /* return type */
939 int iReturn = pszClass != NULL ? iClass : iFn;
940 char * pszReturn = pszClass != NULL ? pszClass : pszFn;
941
942 if (pszReturn != papszLines[iReturn])
943 pszReturn--;
944 else
945 {
946 pszReturn = papszLines[--iReturn];
947 pszReturn += strlen(pszReturn) - (*pszReturn != '\0');
948 }
949 pszReturn = skipBackwards("{};-+#:\"\'", pszReturn, iReturn, papszLines);
950 *pszEnd = '\0';
951 copy(pszEnd, pszReturn, iReturn, pszFn-1, iFn, papszLines);
952 if (strlen(pszEnd) > 128)
953 {
954 /* FIXME LATER! Some constructors calling baseclass constructors "breaks" this rule. Win32MDIChildWindow in /src/user32/win32wmdichild.cpp for example. */
955 fprintf(phSignal,"Fatal error? return statement is too larget. len=%d\n", strlen(pszEnd));
956 fprintf(phLog, "Fatal error? return statement is too larget. len=%d\n", strlen(pszEnd));
957 if (strlen(pszEnd) > 512)
958 fprintf(stderr, "Fatal error? return statement is too larget. len=%d\n", strlen(pszEnd));
959 fflush(phLog);
960 fflush(phSignal);
961 fflush(stderr);
962 }
963 pszEnd = trim(pszEnd);
964 pFnDesc->pszReturnType = *pszEnd == '\0' ? NULL : pszEnd;
965 pszEnd = strlen(pszEnd) + pszEnd + 1;
966 *pszEnd = '\0';
967
968 /* !BugFix! some function occur more than once, usually as inline functions */
969 if (pFnDesc->pszReturnType != NULL
970 && strstr(pFnDesc->pszReturnType, "inline ") != NULL)
971 {
972 fprintf(phLog, "Not an API. Inlined functions can't be exported!\n");
973 return 0;
974 }
975
976 /* function name */
977 if (pFnDesc->pszReturnType != NULL
978 && (stristr(pFnDesc->pszReturnType, "cdecl") != NULL
979 || strstr(pFnDesc->pszReturnType, "VFWAPIV") != NULL
980 || strstr(pFnDesc->pszReturnType, "WINAPIV") != NULL
981 )
982 )
983 { /* cdecl function is prefixed with an '_' */
984 strcpy(pszEnd, "_");
985 }
986 if (pszClass != NULL)
987 {
988 strncat(pszEnd,pszClass, pszClassEnd - pszClass + 1);
989 strcat(pszEnd, "::");
990 }
991 strncat(pszEnd, pszFn, pszFnEnd - pszFn + 1);
992 pFnDesc->pszName = pszEnd;
993 pszEnd = strlen(pszEnd) + pszEnd + 1;
994 *pszEnd = '\0';
995
996
997 /* arguments */
998 pFnDesc->cParams = cArgs;
999 for (j = 0; j < cArgs; j++)
1000 {
1001 int cch = strlen(apszArgs[j]);
1002 if ((psz = strchr(apszArgs[j], ')')) == NULL)
1003 { /* Common argument */
1004 if (apszArgs[j][cch-1] != '*' || (apszArgs[j][cch - 1] == ']' && cch < 5))
1005 { /* nearly Normal case, Type [moretype] Name.*/
1006 if (apszArgs[j][cch - 1] != ']')
1007 {
1008 if (strcmp(apszArgs[j], "...") != 0)
1009 { /* Normal case! */
1010 pFnDesc->apszParamName[j] = findStartOfWord(apszArgs[j] + cch - 1,
1011 apszArgs[j]);
1012 pFnDesc->apszParamName[j][-1] = '\0';
1013 pFnDesc->apszParamType[j] = trim(apszArgs[j]);
1014 }
1015 else
1016 { /* eliptic */
1017 pFnDesc->apszParamName[j] = "...";
1018 pFnDesc->apszParamType[j] = "";
1019 }
1020 }
1021 else
1022 { /* arg yet another special case! 'fn(int argc, char *argv[])' */
1023 char *pszP2;
1024 cch = strlen(apszArgs[j]);
1025 psz = &apszArgs[j][cch-2];
1026 while (psz > apszArgs[j] && ((*psz >= '0' && *psz <= '9') || *psz == ' '))
1027 psz--;
1028
1029 if (psz > apszArgs[j] && *psz == '[')
1030 {
1031 pszP2 = psz--;
1032 while (psz >= apszArgs[j] && *psz == ' ')
1033 psz--;
1034 }
1035
1036 if (psz <= apszArgs[j])
1037 { /* funny case - no name? */
1038 sprintf(pszEnd, "arg%i", j);
1039 pFnDesc->apszParamName[j] = pszEnd;
1040 pszEnd = strlen(pszEnd) + pszEnd + 1;
1041 *pszEnd = '\0';
1042 }
1043 else
1044 { /* *pszP2 = '[' and psz = end of name */
1045 psz = findStartOfWord(psz, apszArgs[j]);
1046 strncat(pszEnd, psz, pszP2 - psz);
1047 pFnDesc->apszParamName[j] = pszEnd;
1048 pszEnd = strlen(pszEnd) + pszEnd + 1;
1049 *pszEnd = '\0';
1050 memset(psz, ' ', pszP2 - psz);
1051 }
1052 pFnDesc->apszParamType[j] = trim(apszArgs[j]);
1053 }
1054 }
1055 else
1056 { /* No argument name only type - make a dummy one: 'arg[1..n]' */
1057 sprintf(pszEnd, "arg%i", j);
1058 pFnDesc->apszParamName[j] = pszEnd;
1059 pszEnd = strlen(pszEnd) + pszEnd + 1;
1060 *pszEnd = '\0';
1061 pFnDesc->apszParamType[j] = trim(apszArgs[j]);
1062 }
1063 }
1064 else
1065 { /* Function pointer argument... */
1066 char *pszP2 = psz;
1067 psz = findStartOfWord(psz-1, apszArgs[j]);
1068 strncat(pszEnd, psz, pszP2 - psz);
1069
1070 pFnDesc->apszParamName[j] = pszEnd;
1071 memset(psz, ' ', pszP2 - psz);
1072 pFnDesc->apszParamType[j] = trim(apszArgs[j]);
1073
1074 pszEnd = strlen(pszEnd) + pszEnd + 1;
1075 *pszEnd = '\0';
1076 }
1077 }
1078 }
1079 pOptions = pOptions;
1080 return 0x00000001;
1081}
1082
1083
1084/**
1085 * Analyses the function header.
1086 * @returns high word = number of signals
1087 * low word = number of APIs processed. (1 or 0).
1088 * @param papszLines Array of lines in the file.
1089 * @param i Index into papszLines.
1090 * @param pszFilename Filename used in the signal log.
1091 * @param pOptions Pointer to options.
1092 * @sketch 0. initiate pFnDesc struct
1093 * 1. Search backwards (start at i-1) for a comment or code.
1094 * 2. If comment: (else fail)
1095 * 2a. find start and end of comment.
1096 * 2b. check for function header characteristics
1097 * - lots of '*'s.
1098 * - fields 'Status', 'Author' and 'Name'
1099 * or if SDS, check for:
1100 * - at least two '*'s at the begining.
1101 * - fields '@status' and/or '@author'
1102 * 2c. check that content of the 'Name' field matches (not SDS)
1103 * 2d. read the status and author fields.
1104 * @remark Supports both types of function headers, Odin32-common and SDS.
1105 */
1106static unsigned long analyseFnHdr(PFNDESC pFnDesc, char **papszLines, int i, const char *pszFilename, POPTIONS pOptions)
1107{
1108 int iStatus, iAuthor, iName, iStart, iEnd;
1109 int j, jStart;
1110 int fFound;
1111 int fSDS = 0;
1112 char *psz, *pszB;
1113 char *pszAuthors = NULL;
1114 unsigned long ulRc = 0x00000001;
1115
1116 pOptions = pOptions;
1117
1118 if (i < 0) /* parameter validation */
1119 return 0;
1120
1121 /*
1122 * 0. initiate pFnDesc struct
1123 */
1124 for (j = 0; j < pFnDesc->cParams; j++)
1125 pFnDesc->apszParamDesc[j] = NULL;
1126 pFnDesc->cAuthors = 0;
1127 pFnDesc->pszDescription = pFnDesc->pszRemark = pFnDesc->pszReturnDesc = NULL;
1128 pFnDesc->pszSketch = pFnDesc->pszEquiv = pFnDesc->pszTime = pFnDesc->pszStatus = NULL;
1129 pFnDesc->lStatus = 99; /* unknown */
1130
1131 /*
1132 * 1. + 2a.
1133 */
1134 iEnd = i-1; /* find end */
1135 j = strlen(papszLines[iEnd]);
1136 j -= j > 0 ? 1 : 0;
1137 fFound = 0;
1138 while (iEnd >= 0 && i - iEnd < 7 && papszLines[iEnd][j] != '}' &&
1139 !(fFound = (papszLines[iEnd][j] == '*' && papszLines[iEnd][j+1] == '/')))
1140 if (j-- == 0)
1141 if (iEnd-- > 0)
1142 {
1143 j = strlen(papszLines[iEnd]);
1144 j -= j > 0 ? 1 : 0;
1145 }
1146 if (!fFound) /* fail if not found */
1147 return 0;
1148
1149 iStart = iEnd; /* find start */
1150 if (j < 2)
1151 j -= (j = strlen(papszLines[--iStart])) > 1 ? 2 : j;
1152 else
1153 j -= 2;
1154 fFound = 0;
1155 while (iStart >= 0
1156 && (j < 0
1157 || !(fFound = (papszLines[iStart][j] == '/' && papszLines[iStart][j+1] == '*'))
1158 )
1159 )
1160 if (j-- <= 0)
1161 if (iStart-- > 0)
1162 {
1163 j = strlen(papszLines[iStart]);
1164 j -= j > 1 ? 2 : j;
1165 }
1166
1167 if (!fFound) /* fail if not found */
1168 return 0;
1169 jStart = j;
1170
1171 /*
1172 * 2b.
1173 */
1174 if (strncmp(&papszLines[iStart][jStart], "/**", 3) != 0) /* checks that there are more than one star at start of comment */
1175 return 0;
1176
1177 /* Odin32 common? */
1178 iName = findStrLine("* Name", iStart, iEnd, papszLines);
1179 iStatus = findStrLine("* Status", iStart, iEnd, papszLines);
1180 iAuthor = findStrLine("* Author", iStart, iEnd, papszLines);
1181
1182 if (!(iName <= iEnd || iStatus <= iEnd || iAuthor <= iEnd))
1183 {
1184 /* SDS ? */
1185 iStatus = findStrLine("@status", iStart, iEnd, papszLines);
1186 iAuthor = findStrLine("@author", iStart, iEnd, papszLines);
1187 iName = iEnd + 1;
1188
1189 if (!(iStatus <= iEnd || iAuthor <= iEnd))
1190 return 0;
1191 fSDS = TRUE;
1192 }
1193 else
1194 {
1195 /* 2c.*/
1196 if (iName <= iEnd && strstr(papszLines[iName], pFnDesc->pszName) == NULL)
1197 fprintf(phLog, "Warning: a matching function name is not found in the name Field\n");
1198 }
1199
1200 /* 2d.*/
1201 pszB = &pFnDesc->szFnHdrBuffer[0];
1202 if (!fSDS)
1203 {
1204 /*
1205 * Odin32 common styled header
1206 */
1207
1208 /* Author(s) */
1209 pszAuthors = CommonCopyTextUntilNextTag(pszB, FALSE, iAuthor, iEnd, papszLines);
1210 pszB += strlen(pszB) + 1;
1211
1212 /* Status */
1213 pFnDesc->pszStatus = CommonCopyTextUntilNextTag(pszB, FALSE, iStatus, iEnd, papszLines);
1214 pszB += strlen(pszB) + 1;
1215
1216 /* Remark */
1217 i = findStrLine("* Remark", iStart, iEnd, papszLines);
1218 pFnDesc->pszRemark = CommonCopyTextUntilNextTag(pszB, TRUE, i, iEnd, papszLines);
1219 pszB += strlen(pszB) + 1;
1220
1221 /* Description */
1222 i = findStrLine("* Purpose", iStart, iEnd, papszLines);
1223 pFnDesc->pszDescription = CommonCopyTextUntilNextTag(pszB, TRUE, i, iEnd, papszLines);
1224 pszB += strlen(pszB) + 1;
1225
1226 /* Return(result) description */
1227 i = findStrLine("* Result", iStart, iEnd, papszLines);
1228 pFnDesc->pszReturnDesc = CommonCopyTextUntilNextTag(pszB, TRUE, i, iEnd, papszLines);
1229 pszB += strlen(pszB) + 1;
1230
1231 /* FIXME parameters */
1232
1233 }
1234 else
1235 {
1236 /*
1237 * SDS styled header
1238 */
1239
1240 /* author */
1241 pszAuthors = SDSCopyTextUntilNextTag(pszB, FALSE, iAuthor, iEnd, papszLines);
1242 pszB += strlen(pszB) + 1;
1243
1244 /* status */
1245 pFnDesc->pszReturnDesc = SDSCopyTextUntilNextTag(pszB, FALSE, iStatus, iEnd, papszLines);
1246 pszB += strlen(pszB) + 1;
1247
1248 /* remark */
1249 i = findStrLine("@remark", iStart, iEnd, papszLines);
1250 pFnDesc->pszRemark = SDSCopyTextUntilNextTag(pszB, TRUE, i, iEnd, papszLines);
1251 pszB += strlen(pszB) + 1;
1252
1253 /* description */
1254 i = findStrLine("@desc", iStart, iEnd, papszLines);
1255 pFnDesc->pszDescription = SDSCopyTextUntilNextTag(pszB, TRUE, i > iEnd ? iStart : i, iEnd, papszLines);
1256 pszB += strlen(pszB) + 1;
1257
1258 /* sketch */
1259 i = findStrLine("@sketch", iStart, iEnd, papszLines);
1260 pFnDesc->pszSketch = SDSCopyTextUntilNextTag(pszB, TRUE, i, iEnd, papszLines);
1261 pszB += strlen(pszB) + 1;
1262
1263 /* return description */
1264 i = findStrLine("@return", iStart, iEnd, papszLines);
1265 pFnDesc->pszReturnDesc = SDSCopyTextUntilNextTag(pszB, TRUE, i, iEnd, papszLines);
1266 pszB += strlen(pszB) + 1;
1267
1268 /* time */
1269 i = findStrLine("@time", iStart, iEnd, papszLines);
1270 pFnDesc->pszReturnDesc = SDSCopyTextUntilNextTag(pszB, TRUE, i, iEnd, papszLines);
1271 pszB += strlen(pszB) + 1;
1272
1273 /* equiv */
1274 i = findStrLine("@equiv", iStart, iEnd, papszLines);
1275 pFnDesc->pszReturnDesc = SDSCopyTextUntilNextTag(pszB, TRUE, i, iEnd, papszLines);
1276 pszB += strlen(pszB) + 1;
1277
1278 /* Set parameter descriptions to NULL */
1279 for (i = 0; i < pFnDesc->cParams; i++)
1280 pFnDesc->apszParamDesc[i] = NULL;
1281
1282 /*
1283 * parameters, new @param for each parameter!
1284 */
1285 do
1286 {
1287 char *pszParam;
1288
1289 /* find first */
1290 i = findStrLine("@param", iStart, iEnd, papszLines);
1291 if (i >= iEnd)
1292 break;
1293
1294 /* Get parameter name - first word */
1295 pszParam = SDSCopyTextUntilNextTag(pszB, TRUE, i, iEnd, papszLines);
1296 if (pszParam != NULL)
1297 {
1298 /* first word in psz is the parameter name! */
1299 psz = findEndOfWord(pszParam);
1300 *psz++ = '\0';
1301
1302 /* find parameter */
1303 for (j = 0; j < pFnDesc->cParams; j++)
1304 if (strcmp(pFnDesc->apszParamName[j], pszParam) != 0)
1305 break;
1306 if (j < pFnDesc->cParams)
1307 {
1308 /* find end of parameter name */
1309 psz = findEndOfWord(strstr(papszLines[i], pszParam));
1310 /* copy from end of parameter name */
1311 pFnDesc->apszParamDesc[j] = SDSCopyTextUntilNextTag(pszB, TRUE, i, iEnd, papszLines, psz);
1312 pszB += strlen(pszB) + 1;
1313 }
1314 else
1315 { /* signal that parameter name wasn't found! */
1316 fprintf(phSignal, "%s, %s: '%s' is not a valid parameter.\n",
1317 pszFilename, pFnDesc->pszName, pszParam);
1318 ulRc += 0x00010000;
1319 }
1320 }
1321 } while (i > iEnd);
1322 }
1323
1324 /*
1325 * Status - refcodes are hardcoded here!
1326 */
1327 if (pFnDesc->pszStatus != NULL && *pFnDesc->pszStatus != '\0')
1328 {
1329 if (strstr(pFnDesc->pszStatus, "STUB") != NULL || *pFnDesc->pszStatus == '1')
1330 pFnDesc->lStatus = 1; /* STUB */
1331 else if (stristr(pFnDesc->pszStatus, "Partially") != NULL || *pFnDesc->pszStatus == '2' || *pFnDesc->pszStatus == '3')
1332 {
1333 if (stristr(pFnDesc->pszStatus, "Tested") == NULL || *pFnDesc->pszStatus == '2')
1334 pFnDesc->lStatus = 2; /* STUB */
1335 else
1336 pFnDesc->lStatus = 3; /* STUB */
1337 if (stristr(pFnDesc->pszStatus, "Open32") != NULL
1338 || *pFnDesc->pszStatus == '5' || *pFnDesc->pszStatus == '7')
1339 pFnDesc->lStatus += 4;
1340 }
1341 else if (stristr(pFnDesc->pszStatus, "Completely") != NULL || *pFnDesc->pszStatus == '4' || *pFnDesc->pszStatus == '5')
1342 {
1343 if (stristr(pFnDesc->pszStatus, "Tested") == NULL || *pFnDesc->pszStatus == '4')
1344 pFnDesc->lStatus = 4; /* STUB */
1345 else
1346 pFnDesc->lStatus = 5; /* STUB */
1347 if (stristr(pFnDesc->pszStatus, "Open32") != NULL
1348 || *pFnDesc->pszStatus == '8' || *pFnDesc->pszStatus == '9')
1349 pFnDesc->lStatus += 4;
1350 }
1351 else
1352 {
1353 fprintf(phSignal, "%s, %s: '%s' is not a valid status code.\n",
1354 pszFilename, pFnDesc->pszName, pFnDesc->pszStatus);
1355 ulRc += 0x00010000;
1356 }
1357 }
1358
1359 /*
1360 * Author
1361 */
1362 if (pszAuthors != NULL)
1363 { /* author1, author2, author3 */
1364 j = 0;
1365 psz = trim(pszAuthors);
1366 pFnDesc->cAuthors = 0;
1367 while (*psz != '\0' && pFnDesc->cAuthors < (int)(sizeof(pFnDesc->apszAuthor) / sizeof(pFnDesc->apszAuthor[0])))
1368 {
1369 char *pszBr1 = strchr(psz, '[');
1370 char *pszBr2 = strchr(psz, ']');
1371 char *pszEmail = NULL;
1372 char *pszNext;
1373
1374 /* remove '[text]' text - this is usualy used for time/date */
1375 if (pszBr1 != NULL && pszBr2 != NULL && pszBr1 < pszBr2)
1376 while (pszBr1 <= pszBr2)
1377 *pszBr1++ = ' ';
1378
1379 /* terminate string */
1380 pszNext = strchr(psz, ',');
1381 if (pszNext == NULL)
1382 pszNext = strchr(psz, '\n');
1383 if (pszNext != NULL)
1384 *pszNext = '\0';
1385
1386 /* check for (email) test */
1387 pszBr1 = strchr(psz, '(');
1388 pszBr2 = strchr(psz, ')');
1389 if (pszBr1 != NULL || pszBr2 != NULL)
1390 {
1391 if (pszBr1 != NULL)
1392 *pszBr1++ = '\0';
1393 if (pszBr2 != NULL)
1394 *pszBr2++ = '\0';
1395
1396 if (pszBr1 != NULL && pszBr1 < pszBr2)
1397 pszEmail = trim(pszBr1 + 1);
1398 }
1399
1400 pFnDesc->apszAuthor[pFnDesc->cAuthors] = trim(psz);
1401 pFnDesc->alAuthorRefCode[pFnDesc->cAuthors] =
1402 dbFindAuthor(pFnDesc->apszAuthor[pFnDesc->cAuthors], pszEmail);
1403
1404 if (pFnDesc->alAuthorRefCode[pFnDesc->cAuthors] == -1)
1405 {
1406 fprintf(phSignal, "%s, %s: author '%s' is not recognized.\n", pszFilename, pFnDesc->pszName,
1407 pFnDesc->apszAuthor[pFnDesc->cAuthors]);
1408 ulRc += 0x00010000;
1409 }
1410
1411 /* next */
1412 pFnDesc->cAuthors++;
1413 psz = pszNext ? skip(pszNext + 1) : "";
1414 }
1415 }
1416
1417 return ulRc;
1418}
1419
1420
1421
1422/**
1423 * Copies a piece of tag/keyword text into an buffer. SDS.
1424 * @returns Pointer to buffer. If iStart > iEnd NULL is returned.
1425 * @param pszTarget Pointer to buffer.
1426 * @param fHTML Add HTML tags like <br> or not
1427 * @param iStart Index of start line.
1428 * @param iEnd Index of last line.
1429 * @param apszLines Array lines.
1430 * @param pszStart Pointer to char to start at (into papszLines[iStart] of course!)
1431 * @status completely impelmented.
1432 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1433 * @remark Addes some HTML tags.
1434 */
1435static char *SDSCopyTextUntilNextTag(char *pszTarget, BOOL fHTML, int iStart, int iEnd, char **papszLines, const char *pszStart)
1436{
1437 char *pszRet = pszTarget;
1438
1439 if (iStart <= iEnd)
1440 {
1441 int iStartColumn;
1442 const char *psz = pszStart != NULL ? pszStart : papszLines[iStart];
1443
1444 /*
1445 * skip dummy chars.
1446 */
1447 while (iStart <= iEnd && (*psz == ' ' || *psz == '/' || *psz == '*' || *psz == '\0' ))
1448 {
1449 if (*psz == '\0')
1450 psz = papszLines[++iStart];
1451 else
1452 psz++;
1453 }
1454
1455 /* Anything left of the area to copy? */
1456 if (iStart <= iEnd)
1457 {
1458 /*
1459 * if we stand at a tag, skip over the tag
1460 */
1461 if (*psz == '@')
1462 psz = skip(findEndOfWord(psz+1));
1463
1464 /*
1465 * save start columen
1466 */
1467 iStartColumn = psz - papszLines[iStart];
1468
1469 /*
1470 * Copy loop.
1471 */
1472 do
1473 {
1474 int i;
1475 for (i = psz - papszLines[iStart]; i < iStartColumn; i++)
1476 *pszTarget++ = ' '; /* FIXME HTML and indenting... */
1477
1478 strcpy(pszTarget, psz);
1479 trimR(pszTarget);
1480 pszTarget += strlen(pszTarget);
1481 if (fHTML)
1482 strcpy(pszTarget, "<BR>\n");
1483 else
1484 strcpy(pszTarget, "\n");
1485 pszTarget += strlen(pszTarget);
1486
1487 /* Next */
1488 psz = skip(papszLines[++iStart]);
1489 if (iStart <= iEnd)
1490 {
1491 while (psz != NULL && *psz == '*')
1492 ++psz;
1493 psz = skip(psz);
1494 /* end test comment */
1495 if (psz > papszLines[iStart] && psz[-1] == '*' && *psz == '/')
1496 break;
1497 }
1498 } while (iStart <= iEnd && *psz != '@');
1499
1500 /*
1501 * remove empty lines at end.
1502 */
1503 if (fHTML)
1504 {
1505 pszTarget--;
1506 while (pszTarget >= pszRet && (*pszTarget == '\n' || *pszTarget == ' '))
1507 {
1508 if (*pszTarget == '\n')
1509 pszTarget -= 4;
1510 *pszTarget-- = '\0';
1511 }
1512 }
1513 else
1514 {
1515 pszTarget--;
1516 while (pszTarget >= pszRet && (*pszTarget == '\n' || *pszTarget == ' '))
1517 *pszTarget-- = '\0';
1518 }
1519 }
1520 else
1521 pszTarget = '\0';
1522 }
1523 else
1524 pszRet = NULL;
1525
1526 return pszRet != NULL && *pszRet == '\0' ? NULL : pszRet;
1527}
1528
1529
1530
1531/**
1532 * Copies a piece of tag/keyword text into an buffer. SDS.
1533 * @returns Pointer to buffer. If iStart > iEnd NULL is returned.
1534 * @param pszTarget Pointer to buffer.
1535 * @param fHTML Add HTML tags like <br> or not
1536 * @param iStart Index of start line.
1537 * @param iEnd Index of last line.
1538 * @param apszLines Array lines.
1539 * @param pszStart Pointer to char to start at (into papszLines[iStart] of course!)
1540 * @status completely impelmented.
1541 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
1542 * @remark Addes some HTML tags.
1543 */
1544static char *CommonCopyTextUntilNextTag(char *pszTarget, BOOL fHTML, int iStart, int iEnd, char **papszLines, const char *pszStart)
1545{
1546 char *pszRet = pszTarget;
1547
1548 if (iStart <= iEnd)
1549 {
1550 /* known keywords */
1551 int iStartColumn;
1552 int i;
1553 const char *psz = pszStart != NULL ? pszStart : papszLines[iStart];
1554
1555 /*
1556 * Skip evt. keyword
1557 */
1558 psz = skip(psz);
1559 for (i = 0; pszCommonKeywords[i] != NULL; i++)
1560 if (strnicmp(pszCommonKeywords[i], psz, strlen(pszCommonKeywords[i])) == 0)
1561 {
1562 psz = skip(psz + strlen(pszCommonKeywords[i]));
1563 psz = skip(*psz == ':' ? psz + 1 : psz);
1564 break;
1565 }
1566
1567 /*
1568 * save start columen
1569 */
1570 iStartColumn = psz - papszLines[iStart];
1571
1572 /*
1573 * copy loop
1574 */
1575 do
1576 {
1577 /*
1578 * Skip '*'s at start of the line.
1579 */
1580 while (*psz == '*')
1581 psz++;
1582
1583 /* end comment check */
1584 if (psz > papszLines[iStart] && psz[-1] == '*' && *psz == '/')
1585 break;
1586 psz = skip(psz);
1587
1588 /*
1589 * Indent up to iStartColumn
1590 */
1591 for (i = psz - papszLines[iStart]; i < iStartColumn; i++)
1592 *pszTarget++ = ' '; /* FIXME HTML and indenting... */
1593
1594 /*
1595 * Copy the rest of the line and add HTML break.
1596 */
1597 strcpy(pszTarget, psz);
1598 trimR(pszTarget);
1599 pszTarget += strlen(pszTarget);
1600 if (fHTML)
1601 strcpy(pszTarget, "<BR>\n");
1602 else
1603 strcpy(pszTarget, "\n");
1604 pszTarget += strlen(pszTarget);
1605
1606 /*
1607 * Next
1608 */
1609 psz = skip(papszLines[++iStart]);
1610
1611 /*
1612 * Check for keyword
1613 */
1614 if (iStart <= iEnd)
1615 {
1616 psz = skip(psz);
1617 for (i = 0; pszCommonKeywords[i] != NULL; i++)
1618 if (strnicmp(pszCommonKeywords[i], psz, strlen(pszCommonKeywords[i])) == 0)
1619 break;
1620 if (pszCommonKeywords[i] != NULL)
1621 break;
1622 }
1623 } while (iStart < iEnd);
1624
1625 /*
1626 * remove empty lines at end.
1627 */
1628 if (fHTML)
1629 {
1630 pszTarget--;
1631 while (pszTarget >= pszRet && (*pszTarget == '\n' || *pszTarget == ' '))
1632 {
1633 if (*pszTarget == '\n')
1634 pszTarget -= 4;
1635 *pszTarget-- = '\0';
1636 }
1637 }
1638 else
1639 {
1640 pszTarget--;
1641 while (pszTarget >= pszRet && (*pszTarget == '\n' || *pszTarget == ' '))
1642 *pszTarget-- = '\0';
1643 }
1644 }
1645 else
1646 pszRet = NULL;
1647
1648 return pszRet != NULL && *pszRet == '\0' ? NULL : pszRet;
1649}
1650
1651
1652
1653/**
1654 * Checks if there may be an function starting at the current line.
1655 * @returns TRUE if API found, else FALSE.
1656 * @param papszLines Array of lines in the file.
1657 * @param i Index into papszLines.
1658 * @param pOptions Pointer to options.
1659 */
1660static BOOL isFunction(char **papszLines, int i, POPTIONS pOptions)
1661{
1662 if (!pOptions->fOld)
1663 { /* new API naming style */
1664 /* brief algorithm:
1665 * check that line don't start with '\\', '{' or '}'
1666 * search for '('.
1667 * if found then do
1668 * find c-word previous to '('
1669 * if found then do
1670 * check that the following condition are true:
1671 * 1. word is not 'for', 'while', 'do', 'if', 'else' or 'switch'
1672 * 2. first significant char after '(' should not be a '*'. (Fix for functionnames in function header, "BackupRead(".)
1673 * 3. find the matching ')' and check that the first significant char after it is '{'.
1674 * if 1, 2 and 3 are all true return true
1675 * return false.
1676 *
1677 * Note, for 2: spaces, newlines and comments are ignored, all other chars are significant.
1678 */
1679 char *pszP1 = papszLines[i];
1680
1681 while (*pszP1 != '\0' && *pszP1 == ' ')
1682 pszP1++;
1683 if (*pszP1 != '\0' && *pszP1 != '/' && pszP1[1] != '/'
1684 && *pszP1 != '{' && *pszP1 != '}')
1685 {
1686 pszP1 = strchr(papszLines[i], '(');
1687 if (pszP1 != NULL && pszP1 >= papszLines[i])
1688 {
1689 int cchFnName = 0;
1690 char *pszFnName = pszP1 - 1;
1691
1692 while (pszFnName - cchFnName > papszLines[0] && pszFnName[cchFnName] == ' ')
1693 cchFnName--, pszFnName--;
1694
1695 pszFnName = findStartOfWord(pszFnName, papszLines[0]);
1696 cchFnName += pszP1 - pszFnName;
1697 if (cchFnName >= 0)
1698 {
1699 /* 1. */
1700 if (
1701 strncmp(pszFnName, "for", cchFnName) != 0 &&
1702 strncmp(pszFnName, "while", cchFnName) != 0 &&
1703 strncmp(pszFnName, "do", cchFnName) != 0 &&
1704 strncmp(pszFnName, "if", cchFnName) != 0 &&
1705 strncmp(pszFnName, "else", cchFnName) != 0 &&
1706 strncmp(pszFnName, "switch", cchFnName) != 0
1707 )
1708 {
1709 /* 2. */
1710 int j = i;
1711 char *psz = skipInsignificantChars(papszLines, j, pszP1+1);
1712 if (psz != NULL && *psz != '*')
1713 {
1714 char *pszB = pszP1 + 1; /*'{'*/
1715 int c = 1;
1716
1717 /* 3. */
1718 while (c > 0)
1719 {
1720 if (*pszB == '(')
1721 c++;
1722 else if (*pszB == ')')
1723 if (--c == 0)
1724 break;
1725 if (*pszB++ == '\0')
1726 if ((pszB = papszLines[++i]) == NULL)
1727 break;
1728 }
1729 if (pszB != NULL)
1730 {
1731 pszB = skipInsignificantChars(papszLines, i, pszB+1);
1732 if (pszB != NULL && *pszB == '{')
1733 {
1734 fprintf(phLog, "Function found: %.*s\n", cchFnName, pszFnName);
1735 return TRUE;
1736 }
1737 /* FIXME: constructors with ':' afterwards are not supported !TODO! */
1738 }
1739 }
1740 }
1741 }
1742 }
1743 }
1744 }
1745 else
1746 { /* old API naming style */
1747 char *pszOS2;
1748
1749 /* brief algorithm:
1750 * search for function prefix, 'OS2'.
1751 * if found then do
1752 * check that the following condition are true:
1753 * 1. char before 'OS2' is either start-of-line (no char), space or '*'.
1754 * 2. first significant char after the 'OS2' prefixed word is a '('.
1755 * 3. find the matching ')' and check that the first significant char after it is '{'.
1756 * if 1,2 and 3 all are true return true
1757 * return false.
1758 *
1759 * Note, for 2 and 3 spaces, newlines and comments are ignored, all other chars are significant.
1760 */
1761 pszOS2 = strstr(papszLines[i], "OS2");
1762 if (pszOS2 != NULL)
1763 {
1764 /* 1.*/
1765 if (pszOS2 == papszLines[i] || pszOS2[-1] == ' ' || pszOS2[-1] == '*')
1766 {
1767 char *pszP1; /*'('*/
1768 int cchFnName;
1769
1770 /* 2. */
1771 pszP1 = findEndOfWord(pszOS2);
1772 cchFnName = pszP1 - pszOS2;
1773 pszP1 = skipInsignificantChars(papszLines, i, pszP1);
1774
1775 if (pszP1 != NULL && *pszP1 == '(')
1776 {
1777 char *pszB = pszP1 + 1; /*'{'*/
1778 int c = 1;
1779
1780 /* 3. */
1781 while (c > 0)
1782 {
1783 if (*pszB == '(')
1784 c++;
1785 else if (*pszB == ')')
1786 if (--c == 0)
1787 break;
1788 if (*pszB++ == '\0')
1789 if ((pszB = papszLines[++i]) == NULL)
1790 break;
1791 }
1792 if (pszB != NULL)
1793 {
1794 pszB = skipInsignificantChars(papszLines, i, pszB+1);
1795 if (pszB != NULL && *pszB == '{')
1796 {
1797 fprintf(phLog, "Possible API: %.*s\n", cchFnName, pszOS2);
1798 return TRUE;
1799 }
1800 }
1801 }
1802 }
1803 }
1804 }
1805
1806 return FALSE;
1807}
1808
1809
1810
1811/**
1812 * Callback function for the dbGetNotUpdatedFunction routine.
1813 *
1814 */
1815static long _System dbNotUpdatedCallBack(const char *pszValue, const char *pszFieldName, void *pvUser)
1816{
1817 static i = 0;
1818 switch (i++)
1819 {
1820 case 0:
1821 fprintf(phLog, "%s", pszValue);
1822 break;
1823 case 1:
1824 fprintf(phLog, "(%s)", pszValue);
1825 break;
1826 case 2: /* updated */
1827 fprintf(phLog, " %s=%s", pszFieldName, pszValue);
1828 break;
1829 case 3: /* aliasfn */
1830 fprintf(phLog, " %s=%s", pszFieldName, pszValue);
1831 break;
1832 case 4:
1833 if (pszValue != NULL)
1834 fprintf(phLog, " --> %s.", pszValue);
1835 break;
1836 case 5:
1837 if (pszValue != NULL)
1838 fprintf(phLog, "%s", pszValue);
1839 break;
1840 case 6:
1841 if (pszValue != NULL)
1842 fprintf(phLog, "(%s)", pszValue);
1843 break;
1844
1845 default:
1846 i = 0;
1847 fprintf(phLog, "\n");
1848 }
1849
1850 if (stricmp(pszFieldName, "last") == 0)
1851 {
1852 i = 0;
1853 fprintf(phLog, "\n");
1854 }
1855
1856 pvUser = pvUser;
1857 return 0;
1858}
1859
1860
1861/**
1862 * Skips insignificant chars (spaces, new-lines and comments)
1863 * @returns pointer to new string posision. NULL if end of file.
1864 * @param papszLines Pointer to line table.
1865 * @param i Index into line table. (current line)
1866 * @param psz Pointer where to start (within the current line).
1867 */
1868static char *skipInsignificantChars(char **papszLines, int &i, char *psz)
1869{
1870 BOOL fComment = *psz == '/' && psz[1] == '*';
1871
1872 while (fComment || *psz == ' ' || *psz == '\0' || (*psz == '/' && psz[1] == '/'))
1873 {
1874 if (*psz == '\0' || (*psz == '/' && psz[1] == '/' && !fComment))
1875 {
1876 if ((psz = papszLines[++i]) == NULL)
1877 break;
1878 }
1879 else
1880 psz++;
1881
1882 if (fComment)
1883 {
1884 if (!(fComment = *psz != '*' || psz[1] != '/'))
1885 psz += 2;
1886 else
1887 continue;
1888 }
1889
1890 if ((fComment = *psz == '/' && psz[1] == '*') == TRUE)
1891 psz += 1 + (psz[2] != '*'); // don't add two when there is a possible end comment following.
1892 }
1893
1894 return psz;
1895}
1896
1897
1898/**
1899 * Reads a file into memory.
1900 * @returns Pointer to file. This should be freed using 'free' when processing
1901 * the file is not needed.
1902 * @param pszFilename Name of file to read.
1903 * @remark Current implementation reads the file as a binary file.
1904 */
1905static char *readFileIntoMemory(const char *pszFilename)
1906{
1907 char *pszFile = NULL;
1908 int cbFile = 0; /* don't have to initialized, but it removes gcc warning (release) */
1909 FILE *phFile;
1910
1911 phFile = fopen(pszFilename, "rb");
1912 if (phFile != NULL)
1913 {
1914 if (!fseek(phFile, 0, SEEK_END)
1915 && (cbFile = (int)ftell(phFile)) > 0
1916 && !fseek(phFile, 0, SEEK_SET)
1917 )
1918 {
1919 pszFile = (char*)malloc(cbFile + 1);
1920 if (pszFile != NULL)
1921 {
1922 #if 1
1923 memset((void*)pszFile, 0, cbFile + 1);
1924 if (fread((void*)pszFile, 1, cbFile, phFile) == 1)
1925 {
1926 free(pszFile);
1927 pszFile = NULL;
1928 }
1929 #else
1930 int cLines = 0;
1931 int cch = 0;
1932 char *psz = pszFile;
1933
1934 while (!feof(phFile) && cch < cbFile &&
1935 fgets(psz, cbFile - cch, phFile) != NULL)
1936 {
1937 int cchLine;
1938 cch += cchLine = strlen(psz);
1939 psz += cchLine;
1940 cLines++;
1941 }
1942
1943 /* error check */
1944 if (cch > cbFile || !feof(phFile))
1945 {
1946 free(pszFile);
1947 pszFile = NULL;
1948 }
1949 else
1950 *psz = '\0';
1951 #endif
1952 }
1953 }
1954 fclose(phFile);
1955 }
1956
1957 return pszFile;
1958}
1959
1960
1961/**
1962 * Creates an array of lines from a "memory" file. The last entry in the array contains NULL.
1963 * It also replaces '\t' with ' '.
1964 * @returns Pointer to the array of lines.
1965 * @param pszFile Pointer to "memory" file.
1966 */
1967static char **createLineArray(char *pszFile)
1968{
1969 char *psz = pszFile;
1970 char **papszLines = NULL;
1971 int cLines = 1;
1972
1973 while (*psz != '\0')
1974 {
1975 if (*psz == '\r')
1976 {
1977 if (psz[1] == '\n')
1978 psz++;
1979 cLines++;
1980 } else if (*psz == '\n')
1981 cLines++;
1982 psz++;
1983 }
1984 fprintf(phLog, "%d lines\n", cLines);
1985
1986 papszLines = (char**)calloc(cLines + 1, sizeof(char *));
1987 if (papszLines != NULL)
1988 {
1989 cLines = 1;
1990 papszLines[0] = psz = pszFile;
1991 while (*psz != '\0')
1992 {
1993 if (*psz == '\t')
1994 *psz = ' ';
1995 if (*psz == '\r')
1996 {
1997 if (psz[1] == '\n')
1998 *psz++ = '\0';
1999 papszLines[cLines++] = psz + 1;
2000 *psz = '\0';
2001 } else if (*psz == '\n')
2002 {
2003 *psz = '\0';
2004 papszLines[cLines++] = psz + 1;
2005 }
2006 psz++;
2007 }
2008 papszLines[cLines] = NULL; /* Strictly, this is not needed as we use calloc. */
2009 }
2010
2011
2012 return papszLines;
2013}
2014
2015
2016/** first char after word */
2017static char *findEndOfWord(const char *psz)
2018{
2019
2020 while (*psz != '\0' &&
2021 (
2022 (*psz >= 'A' && *psz <= 'Z') || (*psz >= 'a' && *psz <= 'z')
2023 ||
2024 (*psz >= '0' && *psz <= '9')
2025 ||
2026 *psz == '_'
2027 )
2028 )
2029 ++psz;
2030 return (char *)psz;
2031}
2032
2033
2034/** starting char of word */
2035static char *findStartOfWord(const char *psz, const char *pszStart)
2036{
2037 const char *pszR = psz;
2038 while (psz >= pszStart &&
2039 (
2040 (*psz >= 'A' && *psz <= 'Z')
2041 || (*psz >= 'a' && *psz <= 'z')
2042 || (*psz >= '0' && *psz <= '9')
2043 || *psz == '_'
2044 )
2045 )
2046 pszR = psz--;
2047 return (char*)pszR;
2048}
2049
2050
2051/**
2052 * Trims a string, ie. removing spaces (and tabs) from both ends of the string.
2053 * @returns Pointer to first not space or tab char in the string.
2054 * @param psz Pointer to the string which is to be trimmed.
2055 * @status completely implmented.
2056 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
2057 */
2058inline char *trim(char *psz)
2059{
2060 int i;
2061 if (psz == NULL)
2062 return NULL;
2063 while (*psz == ' ' || *psz == '\t')
2064 psz++;
2065 i = strlen(psz) - 1;
2066 while (i >= 0 && (psz[i] == ' ' || *psz == '\t'))
2067 i--;
2068 psz[i+1] = '\0';
2069 return psz;
2070}
2071
2072
2073/**
2074 * Right trims a string, ie. removing spaces (and tabs) from the end of the string.
2075 * @returns Pointer to the string passed in.
2076 * @param psz Pointer to the string which is to be right trimmed.
2077 * @status completely implmented.
2078 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
2079 */
2080inline char *trimR(char *psz)
2081{
2082 int i;
2083 if (psz == NULL)
2084 return NULL;
2085 i = strlen(psz) - 1;
2086 while (i >= 0 && (psz[i] == ' ' || *psz == '\t'))
2087 i--;
2088 psz[i+1] = '\0';
2089 return psz;
2090}
2091
2092
2093/**
2094 * skips blanks until first non-blank.
2095 * @returns Pointer to first not space or tab char in the string.
2096 * @param psz Pointer to the string.
2097 * @status completely implmented.
2098 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
2099 */
2100inline char *skip(const char *psz)
2101{
2102 if (psz == NULL)
2103 return NULL;
2104
2105 while (*psz == ' ' || *psz == '\t')
2106 psz++;
2107 return (char*)psz;
2108}
2109
2110
2111/* copy: remove remarks, and unneeded spaces, ensuring no space after '(',
2112 * ensuring space after '*', ensuring no space before ',' and ')'.
2113 */
2114static void copy(char *psz, char *pszFrom, int iFrom, char *pszTo, int iTo, char **papszLines)
2115{
2116 copy(psz, pszFrom - papszLines[iFrom], iFrom, pszTo - papszLines[iTo], iTo, papszLines);
2117}
2118
2119#if 0
2120static void copy(char *psz, int jFrom, int iFrom, int jTo, int iTo, char **papszLines)
2121{
2122 char chPrev = '\n';
2123 int i, j;
2124 int fComment = 0;
2125
2126 i = iFrom;
2127 j = jFrom;
2128 while (i < iTo || (i == iTo && j <= jTo))
2129 {
2130 if (papszLines[i][j] != '\0'
2131 && !(papszLines[i][j] == '/' && papszLines[i][j+1] == '/') /* '//' coments */
2132 )
2133 {
2134 /* copy char ? */
2135 if (!fComment)
2136 {
2137 fComment = papszLines[i][j] == '/' && papszLines[i][j+1] == '*';
2138 if (!fComment && !(chPrev == ' ' && papszLines[i][j] == ' ') /* only one space char */
2139 && !(chPrev == '(' && papszLines[i][j] == ' ') /* no space after '(' */
2140 )
2141 {
2142 if (chPrev == ' ' && (papszLines[i][j] == ',' || papszLines[i][j] == ')'))
2143 psz[-1] = papszLines[i][j]; /* no space before ',' and ')' */
2144 else
2145 {
2146 chPrev = *psz++ = papszLines[i][j];
2147 if (chPrev == '*') /* ensure ' ' after '*' */
2148 chPrev = *psz++ = ' ';
2149 }
2150 }
2151 }
2152 else
2153 if ((fComment = papszLines[i][j] != '*' || papszLines[i][j+1] != '/') == 0)
2154 j++;
2155 j++;
2156 }
2157 else
2158 {
2159 /* next */
2160 j = 0;
2161 i++;
2162 if (chPrev != ' ' && chPrev != '(')
2163 chPrev = *psz++ = ' ';
2164 }
2165 }
2166 *psz = '\0';
2167}
2168
2169#else
2170/**
2171 * Copies a set of lines to a buffer (psz) removing precompiler lines and all comments.
2172 * @param psz
2173 * @param jFrom Starting position, index into line iFrom.
2174 * @param iFrom Starting position, index into papszLines.
2175 * @param jTo Ending position, index into line iFrom.
2176 * @param iTo Ending position, index into papszLines.
2177 * @param papszLines Array of lines.
2178 * @status completely implemented.
2179 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
2180 */
2181static void copy(char *psz, int jFrom, int iFrom, int jTo, int iTo, char **papszLines)
2182{
2183 char chPrev = '\n';
2184 int i, j;
2185 int fComment = FALSE;
2186 int fFirst = TRUE;
2187
2188 i = iFrom;
2189 j = jFrom;
2190 while (i < iTo || (i == iTo && j <= jTo))
2191 {
2192 if (papszLines[i][j] != '\0'
2193 && !(papszLines[i][j] == '/' && papszLines[i][j+1] == '/') /* '//' coments */
2194 && !(!fComment && fFirst && papszLines[i][j] == '#')
2195 )
2196 {
2197 fFirst = papszLines[i][j] == ' ';
2198
2199 /* copy char ? */
2200 if (!fComment)
2201 {
2202 fComment = papszLines[i][j] == '/' && papszLines[i][j+1] == '*';
2203
2204 if (!fComment && !(chPrev == ' ' && papszLines[i][j] == ' ') /* only one space char */
2205 && !(chPrev == '(' && papszLines[i][j] == ' ') /* no space after '(' */
2206 )
2207 {
2208 if (chPrev == ' ' && (papszLines[i][j] == ',' || papszLines[i][j] == ')'))
2209 psz[-1] = papszLines[i][j]; /* no space before ',' and ')' */
2210 else
2211 {
2212 chPrev = *psz++ = papszLines[i][j];
2213 if (chPrev == '*') /* ensure ' ' after '*' */
2214 chPrev = *psz++ = ' ';
2215 }
2216 }
2217
2218 }
2219 else
2220 if ((fComment = papszLines[i][j] != '*' || papszLines[i][j+1] != '/') == FALSE)
2221 j++;
2222 j++;
2223 }
2224 else
2225 {
2226 /* next */
2227 j = 0;
2228 fFirst = TRUE;
2229 i++;
2230 if (chPrev != ' ' && chPrev != '(')
2231 chPrev = *psz++ = ' ';
2232 }
2233 }
2234 *psz = '\0';
2235}
2236#endif
2237
2238
2239/**
2240 * Upcases a char.
2241 * @returns Upper case of the char given in ch.
2242 * @param ch Char to capitalize.
2243 */
2244#if 0
2245inline char upcase(char ch)
2246{
2247 return ch >= 'a' && ch <= 'z' ? (char)(ch - ('a' - 'A')) : ch;
2248}
2249#else
2250#define upcase(ch) ((ch) >= 'a' && (ch) <= 'z' ? (char)((ch) - ('a' - 'A')) : (ch))
2251#endif
2252
2253
2254/**
2255 * Searches for a substring in a string.
2256 * @returns Pointer to start of substring when found, NULL when not found.
2257 * @param pszStr String to be searched.
2258 * @param pszSubStr String to be searched.
2259 * @remark Depends on the upcase function.
2260 */
2261static char *stristr(const char *pszStr, const char *pszSubStr)
2262{
2263 int cchSubStr = strlen(pszSubStr);
2264 int i = 0;
2265
2266 while (*pszStr != '\0' && i < cchSubStr)
2267 {
2268 i = 0;
2269 while (i < cchSubStr && pszStr[i] != '\0' &&
2270 (upcase(pszStr[i]) == upcase(pszSubStr[i])))
2271 i++;
2272 pszStr++;
2273 }
2274
2275 return (char*)(*pszStr != '\0' ? pszStr - 1 : NULL);
2276}
2277
2278
2279
2280/**
2281 * Skips backwards until one of the chars in pszStopAt or star of file is reached.
2282 * @returns Pointer to end.
2283 * @param pszStopAt Array of chars which we should stop at.
2284 * @param pszFrom Start pointer.
2285 * @param iLine Reference to index to array of lines. input: start line, output: result line.
2286 * @param papszLines Array lines.
2287 * @sketch
2288 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
2289 * @remark Comments are skipped.
2290 * No tests for strings ("...asdf").
2291 */
2292static char *skipBackwards(const char *pszStopAt, const char *pszFrom, int &iLine, char **papszLines)
2293{
2294 BOOL fComment = FALSE;
2295 int i = iLine;
2296 const char *psz = pszFrom;
2297
2298 while (i >= 0)
2299 {
2300 /* check for stop char */
2301 const char *psz1 = pszStopAt;
2302 while (*psz1 != '\0')
2303 if (*psz1++ == *psz)
2304 break;
2305 if (*psz1 != '\0')
2306 break;
2307
2308 /* comment check */
2309 if (!fComment && psz > papszLines[i] && *psz == '/' && psz[-1] == '*')
2310 fComment = TRUE;
2311 else if (fComment && *psz == '/' && psz[1] == '*')
2312 fComment = FALSE;
2313
2314 /* ok position to return? */
2315 if (!fComment)
2316 {
2317 iLine = i;
2318 pszFrom = psz;
2319 }
2320
2321 /* prev */
2322 if (psz > papszLines[i])
2323 psz--;
2324 else
2325 { /* try find line comment */
2326 do
2327 {
2328 char *pszStart = papszLines[--i];
2329 while (*pszStart == ' ')
2330 pszStart++;
2331 if (*pszStart != '\0' && *pszStart != '#'
2332 && !(*pszStart == '/' && pszStart[1] == '/'))
2333 { /* find '//' */
2334 pszStart = strstr(pszStart, "//");
2335 if (pszStart != NULL)
2336 psz = pszStart-1;
2337 else
2338 psz = papszLines[i] + strlen(papszLines[i]) - 1;
2339 break;
2340 }
2341 } while (i > 0);
2342 }
2343 }
2344
2345 return (char*)pszFrom;
2346}
2347
2348
2349/**
2350 * Finds a string in a range of pages.
2351 * @returns Index of the line (into ppaszLines).
2352 * @param psz String to search for.
2353 * @param iStart Start line.
2354 * @param iEnd Line to stop at
2355 * @param papszLines Array of lines to search within.
2356 * @status completely implemented.
2357 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
2358 */
2359static int findStrLine(const char *psz, int iStart, int iEnd, char **papszLines)
2360{
2361 while (iStart <= iEnd &&
2362 stristr(papszLines[iStart], psz) == NULL)
2363 iStart++;
2364 return iStart;
2365}
2366
2367
2368
2369
Note: See TracBrowser for help on using the repository browser.