source: trunk/src/helpers/tmsgfile.c@ 20

Last change on this file since 20 was 14, checked in by umoeller, 25 years ago

Major updates; timers, LVM, miscellaneous.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 29.3 KB
Line 
1
2/*
3 *@@sourcefile tmsgfile.c:
4 * contains a "text message file" helper function,
5 * which works similar to DosGetMessage. See
6 * tmfGetMessage for details.
7 *
8 * tmfGetMessage operates on plain-text ".TMF" files.
9 * The file is "compiled" into the file's extended
10 * attributes for faster access after the first access.
11 * When the file's contents change, the EAs are recompiled
12 * automatically.
13 *
14 * This has the following advantages over DosGetMessage:
15 *
16 * 1) No external utility is necessary to change message
17 * files. Simply edit the text, and on the next call,
18 * the file is recompiled at run-time.
19 *
20 * 2) To identify messages, any string can be used, not
21 * only numerical IDs.
22 *
23 * This file is entirely new with V0.9.0.
24 *
25 * Usage: All OS/2 programs.
26 *
27 * Function prefixes:
28 * -- tmf* text message file functions
29 *
30 * This code uses only C standard library functions
31 * which are also part of the subsystem libraries.
32 * It does _not_ use the fopen etc. functions, but
33 * DosOpen etc. instead.
34 * You can therefore use this code with your software
35 * which uses the subsystem libraries only.
36 *
37 * This code was kindly provided by Christian Langanke.
38 * Modifications April 1999 by Ulrich M”ller. Any
39 * substantial changes (other than comments and
40 * formatting) are marked with (*UM).
41 *
42 * Note: Version numbering in this file relates to XWorkplace version
43 * numbering.
44 *
45 *@@header "helpers\tmsgfile.h"
46 *@@added V0.9.0 [umoeller]
47 */
48
49/*
50 * Copyright (C) 1999 Christian Langanke.
51 * Copyright (C) 1999-2000 Ulrich M”ller.
52 * This file is part of the "XWorkplace helpers" source package.
53 * This is free software; you can redistribute it and/or modify
54 * it under the terms of the GNU General Public License as published
55 * by the Free Software Foundation, in version 2 as it comes in the
56 * "COPYING" file of the XWorkplace main distribution.
57 * This program is distributed in the hope that it will be useful,
58 * but WITHOUT ANY WARRANTY; without even the implied warranty of
59 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60 * GNU General Public License for more details.
61 */
62
63#define OS2EMX_PLAIN_CHAR
64 // this is needed for "os2emx.h"; if this is defined,
65 // emx will define PSZ as _signed_ char, otherwise
66 // as unsigned char
67
68#define INCL_DOSFILEMGR
69#define INCL_DOSMISC
70#define INCL_DOSNLS
71#define INCL_DOSERRORS
72#include <os2.h>
73
74#include <stdio.h>
75#include <stdlib.h>
76#include <string.h>
77#include <stdarg.h>
78
79#include "setup.h" // code generation and debugging options
80
81#include "helpers\eah.h"
82#include "helpers\tmsgfile.h"
83
84/*
85 *@@category: Helpers\Control program helpers\Text message files (TMF)
86 */
87
88/* ******************************************************************
89 *
90 * Declarations
91 *
92 ********************************************************************/
93
94// extended attribute used for timestamp; written to .TMF file
95#define EA_TIMESTAMP "TMF.FILEINFO"
96// extended attribute used for compiled text file; written to .TMF file
97#define EA_MSGTABLE "TMF.MSGTABLE"
98
99#define NEWLINE "\n"
100
101// start-of-msgid marker
102#define MSG_NAME_START "\r\n<--"
103// end-of-msgid marker
104#define MSG_NAME_END "-->:" // fixed: the space had to be removed, because
105 // if a newline was the first character after ":",
106 // we got complete garbage (crashes) (99-10-23) [umoeller]
107// comment marker
108#define MSG_COMMENT_LINE "\r\n;"
109
110// internal prototypes
111APIRET CompileMsgTable(PSZ pszMessageFile, PBYTE * ppbTableData);
112APIRET GetTimeStamp(PFILESTATUS3 pfs3, PSZ pszBuffer, ULONG ulBufferlen);
113
114/* ******************************************************************
115 *
116 * Text Message File Code
117 *
118 ********************************************************************/
119
120/*
121 *@@ tmfGetMessage:
122 * just like DosGetMessage, except that this does not
123 * take a simple message number for the message in the
124 * given message file, but a PSZ message identifier
125 * (pszMessageName).
126 *
127 * This function automatically compiles the given .TMF
128 * file into the file's extended attributes, if we find
129 * that this is necessary, by calling CompileMsgTable.
130 *
131 * Note that for compatibily, this function performs the
132 * same brain-dead string processing as DosGetMessage, that
133 * is, the return string is _not_ null-terminated, and
134 * trailing newline characters are _not_ cut off.
135 *
136 * If you don't like this, call tmfGetMessageExt, which
137 * calls this function in turn.
138 *
139 * <B>Returns:</B>
140 * -- ERROR_INVALID_PARAMETER
141 * -- ERROR_BUFFER_OVERFLOW
142 * -- ERROR_MR_MID_NOT_FOUND
143 * -- ERROR_MR_INV_MSGF_FORMAT
144 * -- ERROR_BUFFER_OVERFLOW
145 *
146 * plus the error codes of DosOpen, DosRead, DosClose.
147 */
148
149APIRET tmfGetMessage(PCHAR* pTable, // in: pointer table for string insertion
150 ULONG cTable, // in: number of pointers in *pTable
151 PBYTE pbBuffer, // out: returned string
152 ULONG cbBuffer, // out: sizeof(*pbBuffer)
153 PSZ pszMessageName, // in: message identifier
154 PSZ pszFile, // in: message file (.TMF extension proposed)
155 PULONG pcbMsg) // out: bytes written to *pbBuffer
156{
157 // fixed UM 99-10-22: now initializing all vars to 0,
158 // because ulBytesRead might be returned from this func
159 APIRET rc = NO_ERROR;
160 CHAR szMessageFile[_MAX_PATH];
161 PBYTE pbTableData = NULL;
162 PSZ pszEntry = 0;
163 PSZ pszEndOfEntry = 0;
164 ULONG ulMessagePos = 0;
165 ULONG ulMessageLen = 0;
166
167 HFILE hfile = NULLHANDLE;
168 ULONG ulFilePtr = 0;
169 ULONG ulAction = 0;
170 ULONG ulBytesToRead = 0;
171 ULONG ulBytesRead = 0;
172
173 do
174 {
175 // check parms
176 if ((!pbBuffer) ||
177 (!cbBuffer) ||
178 (!pszMessageName) ||
179 (!*pszMessageName) ||
180 (!*pszFile))
181 {
182 rc = ERROR_INVALID_PARAMETER;
183 break;
184 }
185
186 if (cbBuffer < 2)
187 {
188 rc = ERROR_BUFFER_OVERFLOW;
189 break;
190 }
191
192 // search file
193 if ((strchr(pszFile, ':')) ||
194 (strchr(pszFile, '\\')) ||
195 (strchr(pszFile, '/')))
196 // drive and/or path given: no search in path
197 strcpy(szMessageFile, pszFile);
198 else
199 {
200 // only filename, search in current dir and DPATH
201 rc = DosSearchPath(SEARCH_IGNORENETERRS
202 | SEARCH_ENVIRONMENT
203 | SEARCH_CUR_DIRECTORY,
204 "DPATH",
205 pszFile,
206 szMessageFile,
207 sizeof(szMessageFile));
208 if (rc != NO_ERROR)
209 break;
210 }
211
212 // _Pmpf(("tmfGetMessage: Found %s", szMessageFile));
213
214 // compile table if neccessary
215 rc = CompileMsgTable(szMessageFile, &pbTableData);
216 if (rc != NO_ERROR)
217 break;
218
219 // _Pmpf(("tmfGetMessage: Now searching compiled file"));
220
221 // search the name
222 pszEntry = strstr(pbTableData, pszMessageName);
223 if (!pszEntry)
224 {
225 rc = ERROR_MR_MID_NOT_FOUND;
226 break;
227 }
228 else
229 pszEntry += strlen(pszMessageName) + 1;
230
231 // isolate entry
232 pszEndOfEntry = strchr(pszEntry, '\n');
233 if (pszEndOfEntry)
234 *pszEndOfEntry = 0;
235
236 // get numbers
237 ulMessagePos = atol(pszEntry);
238 if (ulMessagePos == 0)
239 if (!pszEntry)
240 {
241 rc = ERROR_MR_INV_MSGF_FORMAT;
242 break;
243 }
244
245 pszEntry = strchr(pszEntry, ' ');
246 if (!pszEntry)
247 {
248 rc = ERROR_MR_INV_MSGF_FORMAT;
249 break;
250 }
251 ulMessageLen = atol(pszEntry);
252
253 // determine maximum read len
254 ulBytesToRead = _min(ulMessageLen, cbBuffer);
255
256 // open file and read message
257 rc = DosOpen(pszFile,
258 &hfile,
259 &ulAction,
260 0, 0,
261 OPEN_ACTION_FAIL_IF_NEW
262 | OPEN_ACTION_OPEN_IF_EXISTS,
263 OPEN_FLAGS_FAIL_ON_ERROR
264 | OPEN_SHARE_DENYWRITE
265 | OPEN_ACCESS_READONLY,
266 NULL);
267 if (rc != NO_ERROR)
268 break;
269
270 rc = DosSetFilePtr(hfile, ulMessagePos, FILE_BEGIN, &ulFilePtr);
271 if ((rc != NO_ERROR) || (ulFilePtr != ulMessagePos))
272 break;
273
274 rc = DosRead(hfile,
275 pbBuffer,
276 ulBytesToRead,
277 &ulBytesRead);
278 if (rc != NO_ERROR)
279 break;
280
281 // report "buffer too small" here
282 if (ulBytesToRead < ulMessageLen)
283 rc = ERROR_BUFFER_OVERFLOW;
284
285 }
286 while (FALSE);
287
288 // replace string placeholders ("%1" etc.) (*UM)
289 if (rc == NO_ERROR) // added (99-10-24) [umoeller]
290 if (cTable)
291 {
292 // create a temporary buffer for replacements
293 PSZ pszTemp = (PSZ)malloc(cbBuffer); // ### memory leak here!
294
295 if (!pszTemp)
296 rc = ERROR_NOT_ENOUGH_MEMORY;
297 else
298 {
299 // two pointers for copying
300 PSZ pSource = pbBuffer,
301 pTarget = pszTemp;
302
303 CHAR szMsgNum[5] = "0";
304 ULONG ulTableIndex = 0;
305
306 ULONG ulCount = 0, ulTargetWritten = 0;
307
308 // 1) copy the stuff we've read to the
309 // new temporary buffer
310 for (ulCount = 0;
311 ulCount < ulBytesRead;
312 ulCount++)
313 *pTarget++ = *pSource++;
314
315 // 2) now go thru the source string
316 // (which we've read above) and
317 // look for "%" characters; we do
318 // this while copying the stuff
319 // back to pbBuffer
320
321 pSource = pszTemp;
322 pTarget = pbBuffer;
323
324 for (ulCount = 0;
325 ulCount < ulBytesRead;
326 ulCount++)
327 {
328 if (*pSource == '%')
329 {
330 // copy the index (should be > 0)
331 szMsgNum[0] = *(pSource + 1);
332 // szMsgNum[1] is still 0
333
334 // Pmpf((" Found %s", szMsgNum));
335
336 ulTableIndex = atoi(szMsgNum);
337 // _Pmpf((" --> %d", ulTableIndex));
338 if ((ulTableIndex != 0)
339 && (ulTableIndex <= cTable)
340 )
341 {
342 // valid index:
343 // insert stuff from table
344 PSZ *ppTableThis = (PSZ*)(pTable + (ulTableIndex - 1));
345
346 // (pTable) if 1, (pTable+1) if 2, ...
347 PSZ pTableSource = *ppTableThis;
348
349 // copy string from table
350 // and increase the target pointer
351 while ((*pTarget++ = *pTableSource++))
352 ulTargetWritten++;
353
354 // increase source pointer to point
355 // behind the "%x"
356 pSource += 2;
357 // decrease target again, because
358 // we've copied a null-byte
359 pTarget--;
360
361 ulCount++;
362 // next for
363 continue;
364 }
365 // else invalid index: just copy
366 }
367
368 // regular character: copy
369 *pTarget++ = *pSource++;
370 ulTargetWritten++;
371 } // end for (ulCount = 0) ...
372
373 ulBytesRead = ulTargetWritten;
374 }
375 } // end if (cTable)
376
377 // report bytes written (*UM)
378 if (pcbMsg)
379 *pcbMsg = ulBytesRead;
380
381 // cleanup
382 if (hfile)
383 DosClose(hfile);
384 if (pbTableData)
385 free(pbTableData);
386
387 return (rc);
388}
389
390/*
391 *@@ tmfGetMessageExt:
392 * just like tmfGetMessage, but this func is smart
393 * enough to return a zero-terminated string and
394 * strip trailing newlines.
395 *
396 * See tmfGetMessage for details.
397 */
398
399APIRET tmfGetMessageExt(PCHAR* pTable, // in: pointer table for string insertion
400 ULONG cTable, // in: number of pointers in *pTable
401 PBYTE pbBuffer, // out: returned string
402 ULONG cbBuffer, // out: sizeof(*pbBuffer)
403 PSZ pszMessageName, // in: message identifier
404 PSZ pszFile, // in: message file (.TMF extension proposed)
405 PULONG pcbMsg) // out: bytes written to *pbBuffer
406{
407 APIRET arc = NO_ERROR;
408 ULONG cbReturned = 0;
409 arc = tmfGetMessage(pTable, cTable, pbBuffer, cbBuffer, pszMessageName, pszFile,
410 &cbReturned);
411
412 if (arc == NO_ERROR)
413 {
414 PSZ p = pbBuffer;
415
416 // terminate string
417 if (cbReturned < cbBuffer)
418 *(pbBuffer+cbReturned) = 0;
419 else
420 *(pbBuffer+cbBuffer-1) = 0;
421
422 // remove leading spaces (99-10-24) [umoeller]
423 while (*p == ' ')
424 p++;
425 if (p != pbBuffer)
426 {
427 // we have leading spaces:
428 strcpy(pbBuffer, p);
429 // decrease byte count
430 cbReturned -= (p - pbBuffer);
431 }
432
433 // remove trailing newlines
434 while (TRUE)
435 {
436 p = pbBuffer + strlen(pbBuffer) - 1;
437 if ( (*p == '\n')
438 || (*p == '\r')
439 )
440 {
441 *p = '\0';
442 } else
443 break; // while (TRUE)
444 }
445 }
446
447 if (pcbMsg)
448 *pcbMsg = cbReturned;
449
450 return (arc);
451}
452
453/*
454 *@@ CompileMsgTable:
455 * this gets called from tmfGetMessage.
456 * Here we check for whether the given
457 * message file has been compiled to the
458 * EAs yet or if the compilation is
459 * outdated.
460 *
461 * If we need recompilation, we do this here.
462 * Memory for the compiled message table is
463 * allocated here using malloc(), and the
464 * buffer is stored in ppbTableData. You
465 * must free() this buffer after using this
466 * function.
467 *
468 * <B>Returns:</B>
469 * -- ERROR_INVALID_PARAMETER
470 * -- ERROR_BUFFER_OVERFLOW
471 * -- ERROR_NOT_ENOUGH_MEMORY
472 * -- ERROR_READ_FAULT
473 * -- ERROR_INVALID_DATA
474 *
475 *@@changed V0.9.1 (99-12-12) [umoeller]: fixed heap overwrites which caused irregular crashes
476 *@@changed V0.9.1 (99-12-12) [umoeller]: fixed realloc failure
477 *@@changed V0.9.1 (99-12-12) [umoeller]: file last-write date is now reset when EAs are written
478 *@@changed V0.9.1 (2000-02-01) [umoeller]: now skipping leading spaces in msg
479 */
480
481APIRET CompileMsgTable(PSZ pszMessageFile, // in: file to compile
482 PBYTE *ppbTableDataReturn) // out: compiled message table
483{
484 APIRET rc = NO_ERROR;
485 // CHAR szMessageFile[_MAX_PATH];
486
487 FILESTATUS3 fs3MessageFile;
488
489 // fixed UM 99-10-22: initializing all vars to 0
490 ULONG ulStampLength = 0;
491 PBYTE pbFileData = NULL;
492 ULONG ulFileDataLength = 0;
493
494 CHAR szFileStampOld[18] = ""; // yyyymmddhhmmssms.
495
496 CHAR szFileStampCurrent[18] = "";
497
498 PBYTE pbTableData = NULL;
499 ULONG cbTableDataAllocated = 0;
500 ULONG cbTableDataUsed = 0;
501
502 HFILE hfileMessageFile = NULLHANDLE;
503 ULONG ulAction = 0;
504 ULONG ulBytesRead = 0;
505
506 COUNTRYCODE cc = {0, 0};
507
508 ULONG cbOpenTag = strlen(MSG_NAME_START);
509 ULONG cbClosingTag = strlen(MSG_NAME_END);
510
511 do
512 {
513 PSZ pCurrentNameStart = 0;
514 PSZ pCurrentNameEnd = 0;
515 ULONG ulCurrentMessagePos = 0;
516 ULONG ulCurrentMessageLen = 0;
517 // BOOL fError = FALSE;
518
519 // check parms
520 if ((!pszMessageFile) ||
521 (!ppbTableDataReturn))
522 {
523 rc = ERROR_INVALID_PARAMETER;
524 break;
525 }
526
527 // get length and timestamp of file
528 rc = DosQueryPathInfo(pszMessageFile,
529 FIL_STANDARD,
530 &fs3MessageFile,
531 sizeof(fs3MessageFile));
532 if (rc != NO_ERROR)
533 break;
534 ulFileDataLength = fs3MessageFile.cbFile;
535
536 // determine current timestamp
537 GetTimeStamp(&fs3MessageFile, szFileStampCurrent, sizeof(szFileStampCurrent));
538
539 _Pmpf((" Timestamp for %s: '%s'", pszMessageFile, szFileStampCurrent));
540
541 // determine saved timestamp
542 ulStampLength = sizeof(szFileStampOld);
543 rc = eahReadStringEA(pszMessageFile,
544 EA_TIMESTAMP,
545 szFileStampOld,
546 &ulStampLength);
547
548 _Pmpf((" Saved timestamp for %s: '%s'", pszMessageFile, szFileStampOld));
549
550 // compare timestamps
551 if ((rc == NO_ERROR)
552 && (ulStampLength == (strlen(szFileStampCurrent) + 1))
553 && (!strcmp(szFileStampCurrent, szFileStampOld))
554 )
555 {
556
557 // read table out of EAs
558 do
559 {
560 // get ea length of table
561 rc = eahReadStringEA(pszMessageFile,
562 EA_MSGTABLE,
563 NULL, &cbTableDataAllocated);
564 if (rc != ERROR_BUFFER_OVERFLOW)
565 break;
566
567 // get memory
568 if ((pbTableData = (PBYTE)malloc(cbTableDataAllocated)) == NULL)
569 {
570 rc = ERROR_NOT_ENOUGH_MEMORY;
571 break;
572 }
573
574 // read table
575 rc = eahReadStringEA(pszMessageFile,
576 EA_MSGTABLE,
577 pbTableData, &cbTableDataAllocated);
578
579 }
580 while (FALSE);
581
582 // if no error occurred, we are finished
583 if (rc == NO_ERROR)
584 {
585 _Pmpf((" --> using precompiled table"));
586 break;
587 }
588 } // end if
589
590 _Pmpf((" --> recompiling table"));
591
592 // recompilation needed:
593 // get memory for file data
594 if ((pbFileData = (PBYTE)malloc(ulFileDataLength + 1)) == NULL)
595 {
596 rc = ERROR_NOT_ENOUGH_MEMORY;
597 break;
598 }
599 *(pbFileData + ulFileDataLength) = 0;
600
601 // get memory for table data
602 cbTableDataAllocated = ulFileDataLength / 2;
603 if ((pbTableData = (PBYTE)malloc(cbTableDataAllocated)) == NULL)
604 {
605 rc = ERROR_NOT_ENOUGH_MEMORY;
606 break;
607 }
608
609 *pbTableData = 0;
610 // fixed V0.9.1 (99-12-12);
611 // this was
612 // *(pbTableData + cbTableDataAllocated) = 0;
613 // since we're using "strcat" below to write into
614 // the table data, this wasn't such a good idea
615
616 // open file and read it
617 rc = DosOpen(pszMessageFile,
618 &hfileMessageFile,
619 &ulAction,
620 0, 0,
621 OPEN_ACTION_FAIL_IF_NEW
622 | OPEN_ACTION_OPEN_IF_EXISTS,
623 OPEN_FLAGS_FAIL_ON_ERROR
624 | OPEN_SHARE_DENYWRITE
625 | OPEN_ACCESS_READWRITE, // needed for EA attachement
626 NULL);
627 if (rc != NO_ERROR)
628 break;
629
630 rc = DosRead(hfileMessageFile,
631 pbFileData,
632 ulFileDataLength,
633 &ulBytesRead);
634 if (rc != NO_ERROR)
635 break;
636 if (ulBytesRead != ulFileDataLength)
637 {
638 rc = ERROR_READ_FAULT;
639 break;
640 }
641
642 // search first message name
643 // this will automatically skip comments
644 // at the beginning
645 pCurrentNameStart = strstr(pbFileData, MSG_NAME_START);
646
647 if (!pCurrentNameStart)
648 {
649 rc = ERROR_INVALID_DATA;
650 break;
651 }
652 else
653 pCurrentNameStart += cbOpenTag;
654 // this points to message ID string after "<--" now
655
656 // is first name complete ?
657 pCurrentNameEnd = strstr(pCurrentNameStart, MSG_NAME_END);
658 if (!pCurrentNameEnd)
659 {
660 rc = ERROR_INVALID_DATA;
661 break;
662 }
663
664 // scan through all names
665 while ( (pCurrentNameStart)
666 && (*pCurrentNameStart)
667 )
668 {
669 PSZ pNextNameStart = 0,
670 pNextCommentStart = 0,
671 pEndOfMsg = 0;
672 CHAR szEntry[500] = "";
673
674 // search end of name, if not exist, skip end of file
675 pCurrentNameEnd = strstr(pCurrentNameStart, MSG_NAME_END);
676 // this points to the closing "-->" now
677 if (!pCurrentNameEnd)
678 break;
679
680 // search next name (ID), if none, use end of string
681 pNextNameStart = strstr(pCurrentNameEnd, MSG_NAME_START);
682 // points to next "<--" now
683 if (!pNextNameStart)
684 // not found:
685 // use terminating null byte
686 pNextNameStart = pCurrentNameStart + strlen(pCurrentNameStart);
687 else
688 // found:
689 // point to next message ID string
690 pNextNameStart += cbOpenTag;
691
692 pEndOfMsg = pNextNameStart - cbOpenTag;
693
694 // search next comment (99-11-28) [umoeller]
695 pNextCommentStart = strstr(pCurrentNameEnd, MSG_COMMENT_LINE);
696 if (pNextCommentStart)
697 // another comment found:
698 if (pNextCommentStart < pNextNameStart)
699 // if it's even before the next key, use that
700 // for the end of the current string; otherwise
701 // the comment would appear in the message too
702 pEndOfMsg = pNextCommentStart;
703
704 // now we have:
705 // -- pCurrentNameStart: points to message ID after "<--"
706 // -- pCurrentNameEnd: points to "-->"
707 // -- pNextNameStart: points to _next_ message ID after "<--"
708 // -- pNextCommentStart: points to _next_ comment
709 // -- pEndOfMsg: either pNextNameStart-cbOpenTag
710 // or pNextCommentStart,
711 // whichever comes first
712
713 // calculate table entry data
714 *pCurrentNameEnd = 0;
715 ulCurrentMessagePos = (pCurrentNameEnd - pbFileData) + cbClosingTag;
716 // this points to the first character after the <-- --> tag now;
717 // if this points to a space character, take next char
718 // (V0.9.1 (2000-02-13) [umoeller])
719 while ( (*(pbFileData + ulCurrentMessagePos))
720 && (*(pbFileData + ulCurrentMessagePos) == ' ')
721 )
722 ulCurrentMessagePos++;
723
724 ulCurrentMessageLen = (pEndOfMsg - pbFileData) - ulCurrentMessagePos;
725 // pszNextNameStart - pbFileData - ulCurrentMessagePos - 1;
726
727 // determine entry
728 sprintf(szEntry, "%s %lu %lu" NEWLINE,
729 pCurrentNameStart,
730 ulCurrentMessagePos,
731 ulCurrentMessageLen);
732
733 _Pmpf(("Found %s at %d, length %d",
734 pCurrentNameStart,
735 ulCurrentMessagePos,
736 ulCurrentMessageLen));
737
738 // need more space ?
739 if ((cbTableDataUsed + strlen(szEntry) + 1) > cbTableDataAllocated)
740 {
741 PBYTE pbTmp;
742 _Pmpf((" Re-allocating!!"));
743
744 cbTableDataAllocated += ulFileDataLength / 2;
745 pbTmp = (PBYTE)realloc(pbTableData, cbTableDataAllocated);
746 if (!pbTmp)
747 {
748 rc = ERROR_NOT_ENOUGH_MEMORY;
749 break;
750 }
751 else
752 pbTableData = pbTmp;
753 }
754
755 // add entry
756 strcat(pbTableData, szEntry);
757 cbTableDataUsed += strlen(szEntry);
758 // added V0.9.1 (99-12-12);
759 // this was 0 all the time and never raised
760
761 // adress next entry
762 pCurrentNameStart = pNextNameStart;
763
764 } // while (pszCurrentNameStart)
765
766 // write new timestamp and table
767 // ### handle 64 kb limit here !!!
768 if (rc == NO_ERROR)
769 {
770 FILESTATUS3 fs3Tmp;
771
772 rc = eahWriteStringEA(hfileMessageFile, EA_TIMESTAMP, szFileStampCurrent);
773 rc = eahWriteStringEA(hfileMessageFile, EA_MSGTABLE, pbTableData);
774
775 if (rc == NO_ERROR)
776 {
777 // fixed V0.9.1 (99-12-12): we need to reset the file date to
778 // the old date,
779 // because writing EAs updates the "last write date" also;
780 // without this, we'd recompile every single time
781 rc = DosQueryFileInfo(hfileMessageFile,
782 FIL_STANDARD,
783 &fs3Tmp,
784 sizeof(fs3Tmp));
785 if (rc == NO_ERROR)
786 {
787 // restore original "last write" date
788 _Pmpf(("Resetting file date"));
789 fs3Tmp.fdateLastWrite = fs3MessageFile.fdateLastWrite;
790 fs3Tmp.ftimeLastWrite = fs3MessageFile.ftimeLastWrite;
791 DosSetFileInfo(hfileMessageFile,
792 FIL_STANDARD,
793 &fs3Tmp,
794 sizeof(fs3Tmp));
795 }
796 }
797 }
798 } while (FALSE);
799
800
801 if (rc == NO_ERROR)
802 {
803 // hand over result
804 *ppbTableDataReturn = pbTableData;
805
806 // make text uppercase
807 rc = DosMapCase(cbTableDataAllocated, &cc, pbTableData);
808 }
809 else
810 {
811 // error occured:
812 if (pbTableData)
813 free(pbTableData);
814 }
815
816 // cleanup
817 if (pbFileData)
818 free(pbFileData);
819 if (hfileMessageFile)
820 DosClose(hfileMessageFile);
821
822 return rc;
823}
824
825/*
826 * GetTimeStamp:
827 * this returns the "last write date" timestamp
828 * of the file specified in pfs3.
829 *
830 * <B>Usage:</B> called from CompileMsgTable
831 * to check whether the compilation is
832 * outdated.
833 *
834 * Returns:
835 * -- NO_ERROR
836 * -- ERROR_INVALID_PARAMETER
837 * -- ERROR_BUFFER_OVERFLOW: pszBuffer too small for timestamp
838 */
839
840APIRET GetTimeStamp(PFILESTATUS3 pfs3, // in: file to check
841 PSZ pszBuffer, // out: timestamp
842 ULONG ulBufferlen) // in: sizeof(*pszBuffer)
843{
844
845 APIRET rc = NO_ERROR;
846 CHAR szTimeStamp[15];
847 static PSZ pszFormatTimestamp = "%4u%02u%02u%02u%02u%02u%";
848
849 do
850 {
851 // check parms
852 if ((!pfs3) ||
853 (!pszBuffer))
854 {
855 rc = ERROR_INVALID_PARAMETER;
856 break;
857 }
858
859 // create stamp
860 sprintf(szTimeStamp,
861 pszFormatTimestamp,
862 pfs3->fdateLastWrite.year + 1980,
863 pfs3->fdateLastWrite.month,
864 pfs3->fdateLastWrite.day,
865 pfs3->ftimeLastWrite.hours,
866 pfs3->ftimeLastWrite.minutes,
867 pfs3->ftimeLastWrite.twosecs * 2);
868
869 // check bufferlen
870 if (strlen(szTimeStamp) + 1 > ulBufferlen)
871 {
872 rc = ERROR_BUFFER_OVERFLOW;
873 break;
874 }
875
876 // hand over result
877 strcpy(pszBuffer, szTimeStamp);
878 }
879 while (FALSE);
880
881 return rc;
882}
883
Note: See TracBrowser for help on using the repository browser.