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

Last change on this file since 69 was 53, checked in by umoeller, 24 years ago

Dialog mgr.

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