Changeset 151 for trunk/src/helpers/tmsgfile.c
- Timestamp:
- Mar 26, 2002, 8:02:50 PM (23 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/helpers/tmsgfile.c
r147 r151 37 37 * has been completely rewritten with V0.9.16 to use my 38 38 * 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. 40 41 * 41 42 * Usage: All OS/2 programs. … … 81 82 #include "setup.h" // code generation and debugging options 82 83 84 #include "helpers\datetime.h" 83 85 #include "helpers\dosh.h" 84 86 #include "helpers\eah.h" … … 126 128 127 129 /* 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 147 APIRET LoadAndCompile(PTMFMSGFILE pFile) 151 148 { 152 149 APIRET arc; 150 153 151 PSZ pszContent = NULL; 154 155 if (!(arc = doshLoadTextFile(pcszMessageFile, 152 if (!(arc = doshLoadTextFile(pFile->pszFilename, 156 153 &pszContent, 157 154 NULL))) 158 155 { 159 156 // 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 322 APIRET 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 { 160 333 // create a TMFMSGFILE entry 161 334 PTMFMSGFILE pFile; 162 335 if (!(pFile = NEW(TMFMSGFILE))) 163 {164 336 arc = ERROR_NOT_ENOUGH_MEMORY; 165 free(pszContent);166 }167 337 else 168 338 { 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 struct178 339 ZERO(pFile); 179 340 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 316 350 // output 317 351 *ppMsgFile = pFile; 352 } 318 353 else 319 354 // error: 320 355 tmfCloseMessageFile(&pFile); 321 322 } // end else if (!(pFile = NEW(TMFMSGFILE))) 323 } // end if (!(arc = doshLoadTextFile(pcszMessageFile, 356 } 357 } 324 358 325 359 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 372 static 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 } 326 397 } 327 398 … … 340 411 { 341 412 PTMFMSGFILE pFile = *ppMsgFile; 342 LONG cItems;343 TREE** papNodes;344 413 345 414 if (pFile->pszFilename) 346 415 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); 367 418 368 419 free(pFile); … … 387 438 * (see xstrInit), but will be replaced. 388 439 * 389 * This does perform the same simplestring replacements440 * This does perform the same brain-dead string replacements 390 441 * as DosGetMessage, that is, the string "%1" will be 391 442 * replaced with pTable[0], "%2" will be replaced with … … 401 452 * 402 453 *@@added V0.9.16 (2001-10-08) [umoeller] 454 *@@changed V0.9.18 (2002-03-24) [umoeller]: now recompiling if last write date changed 403 455 */ 404 456 … … 415 467 else 416 468 { 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) 436 507 { 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 } 445 523 } 446 524 } 525 else 526 arc = ERROR_MR_MID_NOT_FOUND; 447 527 } 448 else449 arc = ERROR_MR_MID_NOT_FOUND;450 528 } 451 529
Note:
See TracChangeset
for help on using the changeset viewer.