Changeset 1394 for trunk/dll/strutil.c
- Timestamp:
- Feb 5, 2009, 5:17:25 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/dll/strutil.c
r1213 r1394 4 4 $Id$ 5 5 6 External strings file support6 External strings support - stored in STRINGTABLE 7 7 8 8 Copyright (c) 1993-98 M. Kimes 9 Copyright (c) 2006, 200 8Steven H. Levine9 Copyright (c) 2006, 2009 Steven H. Levine 10 10 11 11 22 Jul 06 SHL Comments 12 12 20 Aug 07 GKY Move #pragma alloc_text to end for OpenWatcom compat 13 13 05 Jan 08 SHL Rename from string.c to avoid string.h conflict 14 03 Feb 09 SHL Switch to STRINGTABLE and const return 14 15 15 16 ***********************************************************************/ … … 17 18 #include <stdio.h> 18 19 #include <share.h> 20 #include <string.h> 21 22 #define INCL_DOSPROCESS // DosSleep 19 23 20 24 #include "fm3dll.h" 21 25 #include "fm3str.h" 22 26 #include "init.h" // Data declaration(s) 27 #include "mainwnd.h" // FM3ModHandle 28 #include "wrappers.h" 29 #include "errutil.h" 23 30 #include "strutil.h" 24 31 #include "version.h" 25 32 26 extern PSZ NullStr; // 05 Jan 08 SHL fixme to be in some .h 27 28 static char **strs, *str; 29 static ULONG numStr; 30 31 //== LoadStrings() load strings from file == 32 33 BOOL LoadStrings(char *filename) 33 static PSZ pszSrcFile = __FILE__; 34 35 //== GetPString() return a readonly pointer to the requested string in memory == 36 37 PCSZ GetPString(ULONG id) 34 38 { 35 BOOL ok = FALSE; 36 ULONG size, len, totalsize; 37 USHORT vermajor = 0, verminor = 0; 38 register char *p; 39 register ULONG x; 40 FILE *fp; 41 APIRET rc; 42 43 /* Load strings from requested file or FM3RES.STR 44 * with some quiet error-checking. 45 * Return TRUE on success, FALSE on error. 46 */ 47 48 if (!filename) 49 filename = "FM3RES.STR"; 50 numStr = 0; 51 if (str) 52 DosFreeMem(str); 53 strs = NULL; 54 str = NULL; 55 56 fp = _fsopen(filename, "rb", SH_DENYWR); 57 if (fp) { 58 if (fread(&numStr, 59 sizeof(numStr), 60 1, 61 fp) && 62 numStr == IDS_NUMSTRS && 63 fread(&len, sizeof(len), 1, fp) && 64 fread(&vermajor, sizeof(vermajor), 1, fp) && 65 fread(&verminor, sizeof(verminor), 1, fp) && 66 (vermajor >= VERMAJORBREAK && 67 (vermajor > VERMAJORBREAK || verminor >= VERMINORBREAK))) { 68 fseek(fp, 0, SEEK_END); 69 size = ftell(fp) - ((sizeof(ULONG) * 2) + (sizeof(USHORT) * 2)); 70 if (size && size == len) { 71 fseek(fp, (sizeof(ULONG) * 2) + (sizeof(USHORT) * 2), SEEK_SET); 72 /* NOTE: Make one memory object for both str and strs 73 * for efficiency. 74 */ 75 totalsize = size + sizeof(ULONG); 76 totalsize += (totalsize % sizeof(ULONG)); 77 len = totalsize; 78 totalsize += (numStr * sizeof(char *)); 79 totalsize += 4; 80 rc = DosAllocMem((PPVOID) & str, totalsize, 81 PAG_COMMIT | PAG_READ | PAG_WRITE); 82 if (!rc && str) { 83 strs = (char **)(str + len); 84 if (fread(str, 1, size, fp) == size) { 85 p = str; 86 for (x = 0; x < numStr; x++) { 87 if (p - str >= size) 88 break; 89 strs[x] = p; 90 while (*p) 91 p++; 92 p++; 93 } 94 if (x == numStr) 95 ok = TRUE; 39 PSZ psz; 40 LONG l; 41 CHAR sz[257]; 42 ULONG ulNewFirstId; 43 ULONG ulNewLastId; 44 45 static PSZ *pLoadedStrings; 46 static ULONG ulFirstId; 47 static ULONG ulLastId; 48 49 // Strings that must be combined because stringtable items limited to 256 50 static struct LongString { 51 ULONG id; 52 ULONG sub_id; 53 } LongStrings[] = { 54 {IDS_SUGGEST1TEXT, IDS_SUGGEST1TEXT1}, 55 {IDS_SUGGEST1TEXT, IDS_SUGGEST1TEXT2}, 56 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT1}, 57 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT2}, 58 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT3}, 59 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT4}, 60 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT5}, 61 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT6}, 62 {IDS_ARCHIVERBB2TEXT, IDS_ARCHIVERBB2TEXT7}, 63 {IDS_INIBINARYDATASKIPTEXT, IDS_INIBINARYDATASKIPTEXT1}, 64 {IDS_INIBINARYDATASKIPTEXT, IDS_INIBINARYDATASKIPTEXT2}, 65 {IDS_INSTANTHELPTEXT, IDS_INSTANTHELPTEXT1}, 66 {IDS_INSTANTHELPTEXT, IDS_INSTANTHELPTEXT2}, 67 {IDS_FSDERRORTEXT, IDS_FSDERRORTEXT1}, 68 {IDS_FSDERRORTEXT, IDS_FSDERRORTEXT2}, 69 {IDS_LANERRORTEXT, IDS_LANERRORTEXT1}, 70 {IDS_LANERRORTEXT, IDS_LANERRORTEXT2}, 71 {IDS_MAKESHADOWHELPTEXT, IDS_MAKESHADOWHELPTEXT1}, 72 {IDS_MAKESHADOWHELPTEXT, IDS_MAKESHADOWHELPTEXT2}, 73 {IDS_UNDELETEHELPTEXT, IDS_UNDELETEHELPTEXT1}, 74 {IDS_UNDELETEHELPTEXT, IDS_UNDELETEHELPTEXT2}, 75 {IDS_KILLPROCHELPTEXT, IDS_KILLPROCHELPTEXT1}, 76 {IDS_KILLPROCHELPTEXT, IDS_KILLPROCHELPTEXT2}, 77 {IDS_ARCNOTTHERETEXT, IDS_ARCNOTTHERETEXT1}, 78 {IDS_ARCNOTTHERETEXT, IDS_ARCNOTTHERETEXT2}, 79 {IDS_FM2CMDHELPTEXT, IDS_FM2CMDHELPTEXT1}, 80 {IDS_FM2CMDHELPTEXT, IDS_FM2CMDHELPTEXT2}, 81 {IDS_FM2CMDHELPTEXT, IDS_FM2CMDHELPTEXT3} 82 }; 83 84 static UINT cLongStrings = sizeof(LongStrings) / sizeof(struct LongString); 85 86 static volatile INT cBusy; // Need to be MT-safe 87 static ULONG ulDbgId; // 13 Jan 09 SHL fixme to be gone? 88 static UINT uDbgState; // 03 Feb 09 SHL fixme to be gone? 89 static ULONG ulDbgTid; // 13 Jan 09 SHL fixme to be gone? 90 91 UINT c; 92 // 23 Jan 09 SHL fixme to use SMP safe inc/dec? 93 extern void SMPSafeInc(void); 94 extern void SMPSafeDec(void); 95 #pragma aux SMPSafeInc = "lock inc cBusy" modify exact []; 96 #pragma aux SMPSafeDec = "lock dec cBusy" modify exact []; 97 // SMPSafeInc(); 98 for (c = 0; ; c++) { 99 if (++cBusy == 1) 100 break; 101 cBusy--; 102 // Hold off 1 cycle before reporting since some contention expected 103 if (c == 1) 104 DbgMsg(pszSrcFile, __LINE__, "GetPString(%lu) waiting for tid %lu GetPString(%lu), state=%u", id, ulDbgTid, ulDbgId, uDbgState); 105 DosSleep(1); // Let current owner finish 106 } 107 if (c > 1) 108 DbgMsg(pszSrcFile, __LINE__, "continuing with GetPString(%lu) after tid %lu GetPString(%lu), state=%u", id, ulDbgTid, ulDbgId, uDbgState); 109 110 // Remember id and thread ordinal for diagnosing MT hangs 111 // Use fast DosGetInfoBlocks to ensure debug logic does not change timing 112 { 113 extern PTIB2 GetPTIB2(void); 114 #pragma aux GetPTIB2 = "mov eax,fs:[12]" value [eax]; 115 // PIB *ppib; 116 // TIB *ptib; 117 TIB2 *ptib2 = GetPTIB2(); 118 // APIRET apiret = DosGetInfoBlocks(&ptib, &ppib); 119 ulDbgId = id; 120 // ulDbgTid = apiret == 0 ? ptib->tib_ptib2->tib2_ultid : 0; 121 ulDbgTid = ptib2->tib2_ultid; 122 } 123 124 // DbgMsg(pszSrcFile, __LINE__, "Fetching %lu", id); 125 126 // If string already loaded, return it now 127 if (id >= ulFirstId && 128 id <= ulLastId && 129 pLoadedStrings && 130 (psz = pLoadedStrings[id - ulFirstId]) != NULL) { 131 cBusy--; 132 if (((ULONG)psz & 0xffff0000) == 0) 133 DbgMsg(pszSrcFile, __LINE__, "id %lu corrupted %p", id, psz); 134 // DbgMsg(pszSrcFile, __LINE__, "id %lu \"%s\"", id, psz ? psz : "(null)"); 135 return psz; 136 } 137 138 // Try to load 139 // 11 Jan 09 SHL fixme to use global HAB? 140 uDbgState = 1; 141 l = WinLoadString((HAB)NULL, FM3ModHandle, id, sizeof(sz), sz); 142 uDbgState = 2; 143 144 if (l != 0) { 145 psz = xstrdup(sz, pszSrcFile, __LINE__); 146 if (!psz) { 147 cBusy--; 148 return NullStr; 149 } 150 } 151 else { 152 // Assume string must be built from multiple strings - find first 153 UINT i; 154 psz = NULL; 155 for (i = 0; i < cLongStrings && LongStrings[i].id != id; i++); // Scan 156 157 if (i < cLongStrings) { 158 // Combine stringtable items to build long string 159 // DbgMsg(pszSrcFile, __LINE__, "Building long string %lu", id); 160 for (; LongStrings[i].id == id; i++) { 161 uDbgState = 3; 162 l = WinLoadString((HAB)NULL, FM3ModHandle, LongStrings[i].sub_id, sizeof(sz), sz); 163 uDbgState = 4; 164 if (l == 0) { 165 cBusy--; 166 Runtime_Error(pszSrcFile, __LINE__, "string %lu missing", LongStrings[i].sub_id); 167 xfree(psz, pszSrcFile, __LINE__); 168 return NullStr; 169 } 170 if (!psz) { 171 // Remember 1st string 172 psz = strdup(sz); 173 if (!psz) { 174 cBusy--; 175 return NullStr; 96 176 } 97 if (ok)98 /* set pages to readonly */99 DosSetMem(str, totalsize, PAG_COMMIT | PAG_READ);100 177 } 101 } 102 } 103 fclose(fp); 104 } 105 106 if (!ok) { 107 numStr = 0; 108 if (str) 109 DosFreeMem(str); 110 str = NULL; 111 strs = NULL; 112 } 113 114 return ok; 178 else { 179 // Append string 180 UINT curLen = strlen(psz); 181 PSZ psz2 = xrealloc(psz, curLen + l + 1, pszSrcFile, __LINE__); 182 if (!psz2) { 183 xfree(psz, pszSrcFile, __LINE__); 184 cBusy--; 185 return NullStr; 186 } 187 memcpy(psz2 + curLen, sz, l); // Append 188 *(psz2 + curLen + l) = 0; // Terminate 189 psz = psz2; // Remember 190 l += curLen; 191 } 192 } // while 193 } // if long 194 } // if loaded 195 196 if (l == 0) { 197 DbgMsg(pszSrcFile, __LINE__, "Error loading %lu", id); 198 sprintf(sz, "** Error loading id %lu **", id); 199 psz = xstrdup(sz, pszSrcFile, __LINE__); 200 if (psz) 201 l = strlen(sz); 202 else 203 psz = NullStr; // Oh heck 204 } 205 206 uDbgState = 5; 207 // Add to cache 208 // DbgMsg(pszSrcFile, __LINE__, "Caching %lu", id); 209 210 // Calculate new array limits 211 if (!pLoadedStrings) { 212 ulNewFirstId = id; 213 ulNewLastId = id; 214 ulFirstId = id; 215 ulLastId = id; 216 } 217 else { 218 ulNewFirstId = id < ulFirstId ? id : ulFirstId; 219 ulNewLastId = id > ulLastId ? id : ulLastId; 220 } 221 222 if (ulNewFirstId != ulFirstId || 223 ulNewLastId != ulLastId || 224 !pLoadedStrings) { 225 PSZ *pNewLoadedStrings; 226 // DbgMsg(pszSrcFile, __LINE__, "Reallocating for %lu", id); 227 pNewLoadedStrings = xrealloc(pLoadedStrings, 228 (ulNewLastId - ulNewFirstId + 1) * sizeof(PSZ), 229 pszSrcFile, __LINE__); 230 if (!pNewLoadedStrings) { 231 cBusy--; 232 Runtime_Error(pszSrcFile, __LINE__, "realloc failed"); 233 xfree(psz, pszSrcFile, __LINE__); 234 return NullStr; 235 } 236 // Align existing entries and zero fill unused entries as needed 237 if (ulNewFirstId < ulFirstId) { 238 // Move room for new entries at head of array 239 memmove(pNewLoadedStrings + (ulFirstId - ulNewFirstId), 240 pNewLoadedStrings, 241 (ulLastId - ulFirstId + 1) * sizeof(PSZ)); 242 // Null unused placeholder entries 243 if (ulFirstId - ulNewFirstId > 1) 244 memset(pNewLoadedStrings + 1, 0, (ulFirstId - ulNewFirstId - 1) * sizeof(PSZ)); 245 } 246 if (ulNewLastId - ulLastId > 1) { 247 // Null unused placeholder entries 248 memset(pNewLoadedStrings + (ulLastId - ulNewFirstId + 1), 249 0, 250 (ulNewLastId - ulLastId - 1) * sizeof(PSZ)); 251 } 252 pLoadedStrings = pNewLoadedStrings; 253 ulFirstId = ulNewFirstId; 254 ulLastId = ulNewLastId; 255 } 256 257 uDbgState = 6; 258 pLoadedStrings[id - ulFirstId] = psz; 259 cBusy--; 260 // DbgMsg(pszSrcFile, __LINE__, "id %lu \"%s\"", id, psz ? psz : "(null)"); 261 return psz; 115 262 } 116 263 117 //== GetPString() return a readonly pointer to the requested string in memory ==118 119 char *GetPString(ULONG id)120 {121 return id < numStr && str && strs && strs[id] ? strs[id] : NullStr;122 }123 124 //== StringsLoaded() return TRUE is strings loaded125 126 BOOL StringsLoaded(void)127 {128 return numStr && str && strs;129 }130 131 264 #pragma alloc_text(STRINGS,LoadStrings,GetPString)
Note:
See TracChangeset
for help on using the changeset viewer.