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

Last change on this file since 8006 was 8006, checked in by bird, 24 years ago

New kFile* classes; now in sync with os2tools.

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