Ignore:
Timestamp:
Mar 26, 2002, 8:02:50 PM (23 years ago)
Author:
umoeller
Message:

Misc fixes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/helpers/tmsgfile.c

    r147 r151  
    3737 *      has been completely rewritten with V0.9.16 to use my
    3838 *      fast string functions now. Also, tmfGetMessage now
    39  *      requires tmfOpenMessageFile to be called beforehand.
     39 *      requires tmfOpenMessageFile to be called beforehand
     40 *      and keeps all messages in memory for speed.
    4041 *
    4142 *      Usage: All OS/2 programs.
     
    8182#include "setup.h"                      // code generation and debugging options
    8283
     84#include "helpers\datetime.h"
    8385#include "helpers\dosh.h"
    8486#include "helpers\eah.h"
     
    126128
    127129/*
    128  *@@ tmfOpenMessageFile:
    129  *      opens a .TMF message file for future use
    130  *      with tmfGetMessage.
    131  *
    132  *      Use tmfCloseMessageFile to close the file
    133  *      again and free all resources. This thing
    134  *      can allocate quite a bit of memory.
    135  *
    136  *      Returns:
    137  *
    138  *      --  NO_ERROR: *ppMsgFile has received the
    139  *          new TMFMSGFILE structure.
    140  *
    141  *      --  ERROR_NOT_ENOUGH_MEMORY
    142  *
    143  *      plus any of the errors of doshLoadTextFile,
    144  *      such as ERROR_FILE_NOT_FOUND.
    145  *
    146  *@@added V0.9.16 (2001-10-08) [umoeller]
    147  */
    148 
    149 APIRET tmfOpenMessageFile(const char *pcszMessageFile, // in: fully q'fied .TMF file name
    150                           PTMFMSGFILE *ppMsgFile)     // out: TMFMSGFILE struct
     130 *@@ LoadAndCompile:
     131 *      loads and compiles the message file into the
     132 *      given TMFMSGFILE struct.
     133 *
     134 *      This has been extracted from tmfOpenMessageFile
     135 *      to allow for recompiling on the fly if the
     136 *      message file's last-write date/time changed.
     137 *
     138 *      Preconditions:
     139 *
     140 *      --  pFile->pszFilename must have been set.
     141 *
     142 *      All other fields get initialized here.
     143 *
     144 *@@added V0.9.18 (2002-03-24) [umoeller]
     145 */
     146
     147APIRET LoadAndCompile(PTMFMSGFILE pFile)
    151148{
    152149    APIRET arc;
     150
    153151    PSZ pszContent = NULL;
    154 
    155     if (!(arc = doshLoadTextFile(pcszMessageFile,
     152    if (!(arc = doshLoadTextFile(pFile->pszFilename,
    156153                                 &pszContent,
    157154                                 NULL)))
    158155    {
    159156        // file loaded:
     157
     158        PCSZ    pStartOfFile,
     159                pStartOfMarker;
     160
     161        ULONG   ulStartMarkerLength = strlen(G_pcszStartMarker),
     162                ulEndMarkerLength = strlen(G_pcszEndMarker);
     163
     164        // initialize TMFMSGFILE struct
     165        treeInit(&pFile->IDsTreeRoot, NULL);
     166
     167        xstrInitSet(&pFile->strContent, pszContent);
     168
     169        // convert to plain C format
     170        xstrConvertLineFormat(&pFile->strContent,
     171                              CRLF2LF);
     172
     173        // kick out all the comments
     174        while (pStartOfMarker = strstr(pFile->strContent.psz, "\n;"))
     175        {
     176            // copy the next line over this
     177            PCSZ pEOL = strhFindEOL(pStartOfMarker + 2, NULL);
     178            xstrrpl(&pFile->strContent,
     179                    // ofs of first char to replace: "\n;"
     180                    pStartOfMarker - pFile->strContent.psz,
     181                    // no. of chars to replace:
     182                    pEOL - pStartOfMarker,
     183                    // string to replace chars with:
     184                    NULL,
     185                    // length of replacement string:
     186                    0);
     187        }
     188
     189        // free excessive memory
     190        xstrShrink(&pFile->strContent);
     191
     192        pStartOfFile = pFile->strContent.psz;
     193
     194        // go build a tree of all message IDs...
     195
     196        // find first start message marker
     197        pStartOfMarker = strstr(pStartOfFile,
     198                                G_pcszStartMarker);     // start-of-line marker
     199        while (    (pStartOfMarker)
     200                && (!arc)
     201              )
     202        {
     203            // start marker found:
     204            PCSZ pStartOfMsgID = pStartOfMarker + ulStartMarkerLength;
     205            // search next start marker
     206            PCSZ pStartOfNextMarker = strstr(pStartOfMsgID + 1,
     207                                             G_pcszStartMarker);
     208            // and the end-marker
     209            PCSZ pEndOfMarker = strstr(pStartOfMsgID + 1,
     210                                       G_pcszEndMarker);
     211
     212            PMSGENTRY pNew;
     213
     214            // sanity checks...
     215
     216            if (    (pStartOfNextMarker)
     217                 && (pStartOfNextMarker < pEndOfMarker)
     218               )
     219            {
     220                // next start marker before end marker:
     221                // that doesn't look correct, skip this entry
     222                pStartOfMarker = pStartOfNextMarker;
     223                continue;
     224            }
     225
     226            if (!pEndOfMarker)
     227                // no end marker found:
     228                // that's invalid too, and there can't be any
     229                // message left in the file then...
     230                break;
     231
     232            // alright, this ID looks correct now
     233            if (!(pNew = NEW(MSGENTRY)))
     234                arc = ERROR_NOT_ENOUGH_MEMORY;
     235            else
     236            {
     237                // length of the ID
     238                ULONG ulIDLength = pEndOfMarker - pStartOfMsgID;
     239                PCSZ pStartOfText = pEndOfMarker + ulEndMarkerLength;
     240
     241                ZERO(pNew);
     242
     243                // copy the string ID (between start and end markers)
     244                xstrInit(&pNew->strID, 0);
     245                xstrcpy(&pNew->strID,
     246                        pStartOfMsgID,
     247                        ulIDLength);
     248                // make ulKey point to the string ID for tree sorting
     249                pNew->Tree.ulKey = (ULONG)pNew->strID.psz;
     250
     251                // skip leading spaces
     252                while (*pStartOfText == ' ')
     253                    pStartOfText++;
     254
     255                // store start of text
     256                pNew->ulOfsText = pStartOfText - pStartOfFile;
     257
     258                // check if there's a comment before the
     259                // next item
     260                /* if (pNextComment = strstr(pStartOfText, "\n;"))
     261                {
     262                    if (    (!pStartOfNextMarker)
     263                         || (pNextComment < pStartOfNextMarker)
     264                       )
     265                        pEndOfText = pNextComment;
     266                } */
     267
     268                if (pStartOfNextMarker)
     269                    // other markers left:
     270                    pNew->cbText =    // offset of next marker
     271                                     (pStartOfNextMarker - pStartOfFile)
     272                                   - pNew->ulOfsText;
     273                else
     274                    // this was the last message:
     275                    pNew->cbText = strlen(pStartOfText);
     276
     277                // remove trailing newlines
     278                while (    (pNew->cbText)
     279                        && (pStartOfText[pNew->cbText-1] == '\n')
     280                      )
     281                    (pNew->cbText)--;
     282
     283                // store this thing
     284                if (!treeInsert(&pFile->IDsTreeRoot,
     285                                NULL,
     286                                (TREE*)pNew,
     287                                treeCompareStrings))
     288                    // successfully inserted:
     289                    (pFile->cIDs)++;
     290            }
     291
     292            // go on with next start marker (can be NULL)
     293            pStartOfMarker = pStartOfNextMarker;
     294        } // end while (    (pStartOfMarker) ...
     295    } // end else if (!(pFile = NEW(TMFMSGFILE)))
     296
     297    return (arc);
     298}
     299
     300/*
     301 *@@ tmfOpenMessageFile:
     302 *      opens a .TMF message file for future use
     303 *      with tmfGetMessage.
     304 *
     305 *      Use tmfCloseMessageFile to close the file
     306 *      again and free all resources. This thing
     307 *      can allocate quite a bit of memory.
     308 *
     309 *      Returns:
     310 *
     311 *      --  NO_ERROR: *ppMsgFile has received the
     312 *          new TMFMSGFILE structure.
     313 *
     314 *      --  ERROR_NOT_ENOUGH_MEMORY
     315 *
     316 *      plus any of the errors of doshLoadTextFile,
     317 *      such as ERROR_FILE_NOT_FOUND.
     318 *
     319 *@@added V0.9.16 (2001-10-08) [umoeller]
     320 */
     321
     322APIRET tmfOpenMessageFile(const char *pcszMessageFile, // in: fully q'fied .TMF file name
     323                          PTMFMSGFILE *ppMsgFile)     // out: TMFMSGFILE struct
     324{
     325    APIRET arc;
     326
     327    FILESTATUS3 fs3;
     328    if (!(arc = DosQueryPathInfo((PSZ)pcszMessageFile,
     329                                 FIL_STANDARD,
     330                                 &fs3,
     331                                 sizeof(fs3))))
     332    {
    160333        // create a TMFMSGFILE entry
    161334        PTMFMSGFILE pFile;
    162335        if (!(pFile = NEW(TMFMSGFILE)))
    163         {
    164336            arc = ERROR_NOT_ENOUGH_MEMORY;
    165             free(pszContent);
    166         }
    167337        else
    168338        {
    169             // TMFMSGFILE created:
    170 
    171             PCSZ    pStartOfFile,
    172                     pStartOfMarker;
    173 
    174             ULONG   ulStartMarkerLength = strlen(G_pcszStartMarker),
    175                     ulEndMarkerLength = strlen(G_pcszEndMarker);
    176 
    177             // initialize TMFMSGFILE struct
    178339            ZERO(pFile);
    179340            pFile->pszFilename = strdup(pcszMessageFile);
    180             treeInit(&pFile->IDsTreeRoot, NULL);
    181 
    182             xstrInitSet(&pFile->strContent, pszContent);
    183 
    184             // convert to plain C format
    185             xstrConvertLineFormat(&pFile->strContent,
    186                                   CRLF2LF);
    187 
    188             // kick out all the comments
    189             while (pStartOfMarker = strstr(pFile->strContent.psz, "\n;"))
    190             {
    191                 // copy the next line over this
    192                 PCSZ pEOL = strhFindEOL(pStartOfMarker + 2, NULL);
    193                 /* printf("pStartOfMarker = %lX, pEOL = %lX\n",
    194                         pStartOfMarker,
    195                         pEOL); */
    196                 xstrrpl(&pFile->strContent,
    197                         // ofs of first char to replace: "\n;"
    198                         pStartOfMarker - pFile->strContent.psz,
    199                         // no. of chars to replace:
    200                         pEOL - pStartOfMarker,
    201                         // string to replace chars with:
    202                         NULL,
    203                         // length of replacement string:
    204                         0);
    205             }
    206 
    207             // free excessive memory
    208             xstrShrink(&pFile->strContent);
    209 
    210             pStartOfFile = pFile->strContent.psz;
    211 
    212             // go build a tree of all message IDs...
    213 
    214             // find first start message marker
    215             pStartOfMarker = strstr(pStartOfFile,
    216                                     G_pcszStartMarker);     // start-of-line marker
    217             while (    (pStartOfMarker)
    218                     && (!arc)
    219                   )
    220             {
    221                 // start marker found:
    222                 PCSZ pStartOfMsgID = pStartOfMarker + ulStartMarkerLength;
    223                 // search next start marker
    224                 PCSZ pStartOfNextMarker = strstr(pStartOfMsgID + 1,
    225                                                  G_pcszStartMarker);
    226                 // and the end-marker
    227                 PCSZ pEndOfMarker = strstr(pStartOfMsgID + 1,
    228                                            G_pcszEndMarker);
    229 
    230                 PMSGENTRY pNew;
    231 
    232                 // sanity checks...
    233 
    234                 if (    (pStartOfNextMarker)
    235                      && (pStartOfNextMarker < pEndOfMarker)
    236                    )
    237                 {
    238                     // next start marker before end marker:
    239                     // that doesn't look correct, skip this entry
    240                     pStartOfMarker = pStartOfNextMarker;
    241                     continue;
    242                 }
    243 
    244                 if (!pEndOfMarker)
    245                     // no end marker found:
    246                     // that's invalid too, and there can't be any
    247                     // message left in the file then...
    248                     break;
    249 
    250                 // alright, this ID looks correct now
    251                 if (!(pNew = NEW(MSGENTRY)))
    252                     arc = ERROR_NOT_ENOUGH_MEMORY;
    253                 else
    254                 {
    255                     // length of the ID
    256                     ULONG ulIDLength = pEndOfMarker - pStartOfMsgID;
    257                     PCSZ pStartOfText = pEndOfMarker + ulEndMarkerLength;
    258 
    259                     ZERO(pNew);
    260 
    261                     // copy the string ID (between start and end markers)
    262                     xstrInit(&pNew->strID, 0);
    263                     xstrcpy(&pNew->strID,
    264                             pStartOfMsgID,
    265                             ulIDLength);
    266                     // make ulKey point to the string ID for tree sorting
    267                     pNew->Tree.ulKey = (ULONG)pNew->strID.psz;
    268 
    269                     // skip leading spaces
    270                     while (*pStartOfText == ' ')
    271                         pStartOfText++;
    272 
    273                     // store start of text
    274                     pNew->ulOfsText = pStartOfText - pStartOfFile;
    275 
    276                     // check if there's a comment before the
    277                     // next item
    278                     /* if (pNextComment = strstr(pStartOfText, "\n;"))
    279                     {
    280                         if (    (!pStartOfNextMarker)
    281                              || (pNextComment < pStartOfNextMarker)
    282                            )
    283                             pEndOfText = pNextComment;
    284                     } */
    285 
    286                     if (pStartOfNextMarker)
    287                         // other markers left:
    288                         pNew->cbText =    // offset of next marker
    289                                          (pStartOfNextMarker - pStartOfFile)
    290                                        - pNew->ulOfsText;
    291                     else
    292                         // this was the last message:
    293                         pNew->cbText = strlen(pStartOfText);
    294 
    295                     // remove trailing newlines
    296                     while (    (pNew->cbText)
    297                             && (pStartOfText[pNew->cbText-1] == '\n')
    298                           )
    299                         (pNew->cbText)--;
    300 
    301                     // store this thing
    302                     if (!treeInsert(&pFile->IDsTreeRoot,
    303                                     NULL,
    304                                     (TREE*)pNew,
    305                                     treeCompareStrings))
    306                         // successfully inserted:
    307                         (pFile->cIDs)++;
    308                 }
    309 
    310                 // go on with next start marker (can be NULL)
    311                 pStartOfMarker = pStartOfNextMarker;
    312             } // end while (    (pStartOfMarker) ...
    313 
    314             // done with IDs, or error occured:
    315             if (!arc)
     341
     342            // TMFMSGFILE created:
     343            if (!(arc = LoadAndCompile(pFile)))
     344            {
     345                // set timestamp to that of the file
     346                dtCreateFileTimeStamp(pFile->szTimestamp,
     347                                      &fs3.fdateLastWrite,
     348                                      &fs3.ftimeLastWrite);
     349
    316350                // output
    317351                *ppMsgFile = pFile;
     352            }
    318353            else
    319354                // error:
    320355                tmfCloseMessageFile(&pFile);
    321 
    322         } // end else if (!(pFile = NEW(TMFMSGFILE)))
    323     } // end if (!(arc = doshLoadTextFile(pcszMessageFile,
     356        }
     357    }
    324358
    325359    return (arc);
     360}
     361
     362/*
     363 *@@ FreeInternalMem:
     364 *      cleans out the internal message file compilation
     365 *      and the content string. Used by both tmfCloseMessageFile
     366 *      and tmfGetMessage to allow for recompiles when the
     367 *      last-write date/time changed.
     368 *
     369 *@@added V0.9.18 (2002-03-24) [umoeller]
     370 */
     371
     372static VOID FreeInternalMem(PTMFMSGFILE pFile)
     373{
     374    LONG   cItems;
     375    TREE**  papNodes;
     376
     377    xstrClear(&pFile->strContent);
     378
     379    if (cItems = pFile->cIDs)
     380    {
     381        if (papNodes = treeBuildArray(pFile->IDsTreeRoot,
     382                                      &cItems))
     383        {
     384            ULONG ul;
     385            for (ul = 0; ul < cItems; ul++)
     386            {
     387                PMSGENTRY pNodeThis = (PMSGENTRY)(papNodes[ul]);
     388
     389                xstrClear(&pNodeThis->strID);
     390
     391                free(pNodeThis);
     392            }
     393
     394            free(papNodes);
     395        }
     396    }
    326397}
    327398
     
    340411    {
    341412        PTMFMSGFILE pFile = *ppMsgFile;
    342         LONG   cItems;
    343         TREE**  papNodes;
    344413
    345414        if (pFile->pszFilename)
    346415            free(pFile->pszFilename);
    347         xstrClear(&pFile->strContent);
    348 
    349         if (cItems = pFile->cIDs)
    350         {
    351             if (papNodes = treeBuildArray(pFile->IDsTreeRoot,
    352                                           &cItems))
    353             {
    354                 ULONG ul;
    355                 for (ul = 0; ul < cItems; ul++)
    356                 {
    357                     PMSGENTRY pNodeThis = (PMSGENTRY)(papNodes[ul]);
    358 
    359                     xstrClear(&pNodeThis->strID);
    360 
    361                     free(pNodeThis);
    362                 }
    363 
    364                 free(papNodes);
    365             }
    366         }
     416
     417        FreeInternalMem(pFile);
    367418
    368419        free(pFile);
     
    387438 *      (see xstrInit), but will be replaced.
    388439 *
    389  *      This does perform the same simple string replacements
     440 *      This does perform the same brain-dead string replacements
    390441 *      as DosGetMessage, that is, the string "%1" will be
    391442 *      replaced with pTable[0], "%2" will be replaced with
     
    401452 *
    402453 *@@added V0.9.16 (2001-10-08) [umoeller]
     454 *@@changed V0.9.18 (2002-03-24) [umoeller]: now recompiling if last write date changed
    403455 */
    404456
     
    415467    else
    416468    {
    417         // go find the message in the tree
    418         PMSGENTRY pEntry;
    419         if (pEntry = (PMSGENTRY)treeFind(pMsgFile->IDsTreeRoot,
    420                                          (ULONG)pcszMessageName,
    421                                          treeCompareStrings))
    422         {
    423             // copy the raw string to the output buffer
    424             xstrcpy(pstr,
    425                     pMsgFile->strContent.psz + pEntry->ulOfsText,
    426                     pEntry->cbText);
    427 
    428             // now replace strings from the table
    429             if (cTableEntries && pTable)
    430             {
    431                 CHAR szFind[10] = "%0";
    432                 ULONG ul;
    433                 for (ul = 0;
    434                      ul < cTableEntries;
    435                      ul++)
     469        // check if last-write date/time changed compared
     470        // to the last time we opened the thing...
     471        // V0.9.18 (2002-03-24) [umoeller]
     472        FILESTATUS3 fs3;
     473        if (!(arc = DosQueryPathInfo(pMsgFile->pszFilename,
     474                                     FIL_STANDARD,
     475                                     &fs3,
     476                                     sizeof(fs3))))
     477        {
     478            CHAR szTemp[30];
     479            dtCreateFileTimeStamp(szTemp,
     480                                  &fs3.fdateLastWrite,
     481                                  &fs3.ftimeLastWrite);
     482            if (strcmp(szTemp, pMsgFile->szTimestamp))
     483            {
     484                // last write date changed:
     485                _Pmpf((__FUNCTION__ ": timestamp changed, recompiling"));
     486                FreeInternalMem(pMsgFile);
     487                if (!(arc = LoadAndCompile(pMsgFile)))
     488                    strcpy(pMsgFile->szTimestamp, szTemp);
     489            }
     490        }
     491
     492        if (!arc)
     493        {
     494            // go find the message in the tree
     495            PMSGENTRY pEntry;
     496            if (pEntry = (PMSGENTRY)treeFind(pMsgFile->IDsTreeRoot,
     497                                             (ULONG)pcszMessageName,
     498                                             treeCompareStrings))
     499            {
     500                // copy the raw string to the output buffer
     501                xstrcpy(pstr,
     502                        pMsgFile->strContent.psz + pEntry->ulOfsText,
     503                        pEntry->cbText);
     504
     505                // now replace strings from the table
     506                if (cTableEntries && pTable)
    436507                {
    437                     ULONG ulOfs = 0;
    438 
    439                     _ultoa(ul + 1, szFind + 1, 10);
    440                     while (xstrFindReplaceC(pstr,
    441                                             &ulOfs,
    442                                             szFind,
    443                                             pTable[ul]))
    444                         ;
     508                    CHAR szFind[10] = "%0";
     509                    ULONG ul;
     510                    for (ul = 0;
     511                         ul < cTableEntries;
     512                         ul++)
     513                    {
     514                        ULONG ulOfs = 0;
     515
     516                        _ultoa(ul + 1, szFind + 1, 10);
     517                        while (xstrFindReplaceC(pstr,
     518                                                &ulOfs,
     519                                                szFind,
     520                                                pTable[ul]))
     521                            ;
     522                    }
    445523                }
    446524            }
     525            else
     526                arc = ERROR_MR_MID_NOT_FOUND;
    447527        }
    448         else
    449             arc = ERROR_MR_MID_NOT_FOUND;
    450528    }
    451529
Note: See TracChangeset for help on using the changeset viewer.