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

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

Read more of the function header into the database.
Stateupd is changed to do this and the database is expanded with new fields.
The sample is partly updated.

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