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

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

Added line numbers for function and designnote.
Corrected reading of SDS function headers.

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