source: trunk/dll/wrappers.c@ 1570

Last change on this file since 1570 was 1544, checked in by Gregg Young, 15 years ago

Changes to fopen and _fsopen to allow FM2 to be loaded in high memory

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.4 KB
RevLine 
[395]1
2/***********************************************************************
3
4 $Id: wrappers.c 1544 2010-09-30 13:00:59Z gyoung $
5
6 Wrappers with error checking
7
[1008]8 Copyright (c) 2006, 2008 Steven H.Levine
[395]9
10 22 Jul 06 SHL Baseline
[400]11 29 Jul 06 SHL Add xgets_stripped
[438]12 18 Aug 06 SHL Correct Runtime_Error line number report
[794]13 20 Aug 07 GKY Move #pragma alloc_text to end for OpenWatcom compat
[826]14 01 Sep 07 GKY Add xDosSetPathInfo to fix case where FS3 buffer crosses 64k boundry
[850]15 06 Oct 07 SHL Add xDos...() wrappers to support systems wo/large file support (Gregg, Steven)
[1008]16 05 May 08 SHL Add FORTIFY support
[1358]17 25 Dec 08 GKY Add code to allow write verify to be turned off on a per drive basis
[1432]18 17 Jun 09 SHL Correct missing rc set
[1476]19 12 Jul 09 GKY Add xDosQueryAppType and xDosAlloc... to allow FM/2 to load in high memory
20 15 Nov 09 GKY Rework xDosQueryAppType to remove HIMEM ifdefs
[395]21
22***********************************************************************/
23
[907]24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
[1354]27#include <ctype.h>
[907]28
[395]29#define INCL_WIN
[826]30#define INCL_DOS
31#define INCL_DOSERRORS
[841]32#define INCL_LONGLONG
[395]33#include <os2.h>
34
35#include "fm3dll.h"
[1215]36#include "init.h" // Data declaration(s)
[1182]37#include "wrappers.h"
[395]38#include "fm3str.h"
[907]39#include "errutil.h" // Dos_Error...
40#include "strutil.h" // GetPString
[1032]41#include "command.h"
42#include "tools.h"
43#include "avl.h"
[1182]44#include "strips.h" // bstrip
[395]45
[1005]46#include "fortify.h" // GetPString
[1354]47#include "info.h" // driveflags
48#include "notebook.h" // fVerify
[1439]49#include "pathutil.h" // MaxComLineStrg
[1005]50
[1215]51// Data definitions
[827]52static PSZ pszSrcFile = __FILE__;
53
[1215]54#pragma data_seg(GLOBAL1)
55BOOL fNoLargeFileSupport;
56
[1439]57APIRET xDosQueryAppType(PCSZ pszName, PULONG pFlags)
58{
59 APIRET rc;
[1476]60 CHAR szPgm[CCHMAXPATH];
[1439]61
[1476]62 strcpy(szPgm, pszName);
63 rc = DosQueryAppType(szPgm, pFlags);
[1439]64 return rc;
65}
66
[1438]67APIRET xDosAllocSharedMem(PPVOID ppb,
68 PSZ pszName,
69 ULONG cb,
70 ULONG flag)
71{
72 APIRET rc; ;
73
74 rc = DosAllocSharedMem(ppb, pszName, cb, flag | OBJ_ANY);
[1439]75 //DbgMsg(pszSrcFile, __LINE__, "ppb %p", *ppb);
[1438]76 if (rc)
77 rc = DosAllocSharedMem(ppb, pszName, cb, flag);
78 return rc;
79}
80
81APIRET xDosAllocMem(PPVOID ppb,
82 ULONG cb,
[1439]83 ULONG flag,
84 PCSZ pszSrcFile,
85 UINT uiLineNumber)
[1438]86{
87 APIRET rc;
88
89 rc = DosAllocMem(ppb, cb, flag | OBJ_ANY);
[1439]90 //DbgMsg(pszSrcFile, uiLineNumber, "ppb %p %x", *ppb, rc);
[1438]91 if (rc)
92 rc = DosAllocMem(ppb, cb, flag);
[1439]93 //DbgMsg(pszSrcFile, uiLineNumber, "ppb %p", *ppb);
[1438]94 return rc;
95}
96
[850]97APIRET xDosFindFirst(PSZ pszFileSpec,
98 PHDIR phdir,
99 ULONG flAttribute,
100 PVOID pfindbuf,
101 ULONG cbBuf,
102 PULONG pcFileNames,
103 ULONG ulInfoLevel)
[838]104{
[850]105 APIRET rc;
106 if (fNoLargeFileSupport) {
107 switch (ulInfoLevel) {
108 case FIL_STANDARDL:
109 {
110 FILEFINDBUF3 ffb3;
111 ulInfoLevel = FIL_STANDARD;
112 *pcFileNames = 1; // fixme to support larger counts
113 rc = DosFindFirst(pszFileSpec, phdir, flAttribute, &ffb3, sizeof(ffb3),
114 pcFileNames, ulInfoLevel);
115 if (!rc) {
116 *(PFILEFINDBUF3)pfindbuf = ffb3; // Copy aligned data
117 ((PFILEFINDBUF3L)pfindbuf)->cbFile = ffb3.cbFile; // Copy unaligned data
118 ((PFILEFINDBUF3L)pfindbuf)->cbFileAlloc = ffb3.cbFileAlloc;
119 ((PFILEFINDBUF3L)pfindbuf)->attrFile = ffb3.attrFile;
120 ((PFILEFINDBUF3L)pfindbuf)->cchName = ffb3.cchName;
121 memcpy(((PFILEFINDBUF3L)pfindbuf)->achName, ffb3.achName, ffb3.cchName + 1);
122 }
123 }
[849]124 break;
[850]125 case FIL_QUERYEASIZEL:
126 {
127 FILEFINDBUF4 ffb4;
128 *pcFileNames = 1; // fixme to support larger counts
129 ulInfoLevel = FIL_QUERYEASIZE;
130 rc = DosFindFirst(pszFileSpec, phdir, flAttribute, &ffb4, sizeof(ffb4),
131 pcFileNames, ulInfoLevel);
132 if (!rc) {
133 *(PFILEFINDBUF4)pfindbuf = ffb4; // Copy aligned data
134 ((PFILEFINDBUF4L)pfindbuf)->cbFile = ffb4.cbFile; // Copy unaligned data
135 ((PFILEFINDBUF4L)pfindbuf)->cbFileAlloc = ffb4.cbFileAlloc;
136 ((PFILEFINDBUF4L)pfindbuf)->attrFile = ffb4.attrFile;
137 ((PFILEFINDBUF4L)pfindbuf)->cbList = ffb4.cbList;
138 ((PFILEFINDBUF4L)pfindbuf)->cchName = ffb4.cchName;
139 memcpy(((PFILEFINDBUF4L)pfindbuf)->achName, ffb4.achName, ffb4.cchName + 1);
140 }
141 }
[849]142 break;
143 default:
[850]144 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
145 rc = ERROR_INVALID_PARAMETER;
146 } // switch
147 }
148 else
[838]149 rc = DosFindFirst(pszFileSpec, phdir, flAttribute, pfindbuf, cbBuf,
[850]150 pcFileNames, ulInfoLevel);
151 return rc;
[838]152}
153
[850]154APIRET xDosFindNext(HDIR hDir,
155 PVOID pfindbuf,
156 ULONG cbfindbuf,
157 PULONG pcFileNames,
158 ULONG ulInfoLevel)
[838]159{
160 APIRET rc;
[849]161 if (fNoLargeFileSupport) {
[850]162 switch (ulInfoLevel) {
163 case FIL_STANDARDL:
164 {
165 FILEFINDBUF3 ffb3;
166 *pcFileNames = 1; // fixme to support larger counts
167 rc = DosFindNext(hDir, &ffb3, sizeof(ffb3), pcFileNames);
168 if (!rc) {
169 *(PFILEFINDBUF3)pfindbuf = ffb3; // Copy aligned data
170 ((PFILEFINDBUF3L)pfindbuf)->cbFile = ffb3.cbFile; // Copy unaligned data
171 ((PFILEFINDBUF3L)pfindbuf)->cbFileAlloc = ffb3.cbFileAlloc;
172 ((PFILEFINDBUF3L)pfindbuf)->attrFile = ffb3.attrFile;
173 ((PFILEFINDBUF3L)pfindbuf)->cchName = ffb3.cchName;
174 memcpy(((PFILEFINDBUF3L)pfindbuf)->achName, ffb3.achName, ffb3.cchName + 1);
175 }
176 }
177 break;
178 case FIL_QUERYEASIZEL:
179 {
180 FILEFINDBUF4 ffb4;
181 *pcFileNames = 1; // fixme to support larger counts
182 rc = DosFindNext(hDir, &ffb4, sizeof(ffb4), pcFileNames);
183 if (!rc) {
184 *(PFILEFINDBUF4)pfindbuf = ffb4; // Copy aligned data
185 ((PFILEFINDBUF4L)pfindbuf)->cbFile = ffb4.cbFile; // Copy unaligned data
186 ((PFILEFINDBUF4L)pfindbuf)->cbFileAlloc = ffb4.cbFileAlloc;
187 ((PFILEFINDBUF4L)pfindbuf)->attrFile = ffb4.attrFile;
188 ((PFILEFINDBUF4L)pfindbuf)->cbList = ffb4.cbList;
189 ((PFILEFINDBUF4L)pfindbuf)->cchName = ffb4.cchName;
190 memcpy(((PFILEFINDBUF4L)pfindbuf)->achName, ffb4.achName, ffb4.cchName + 1);
191 }
192 }
193 break;
194 default:
195 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
196 rc = ERROR_INVALID_PARAMETER;
197 } // switch
[849]198 }
199 else
[850]200 rc = DosFindNext(hDir, pfindbuf, cbfindbuf, pcFileNames);
[838]201
202 return rc;
203}
204
[827]205/**
[850]206 * DosQueryPathInfo wrapper
207 * Translate request for systems without large file support
208 */
209
210APIRET xDosQueryPathInfo (PSZ pszPathName, ULONG ulInfoLevel, PVOID pInfoBuf, ULONG cbInfoBuf)
211{
212 FILESTATUS3 fs3;
213 FILESTATUS4 fs4;
214 APIRET rc;
215
216 if (fNoLargeFileSupport) {
217 switch (ulInfoLevel) {
218 case FIL_STANDARDL:
219 rc = DosQueryPathInfo(pszPathName, ulInfoLevel, &fs3, sizeof(fs3));
220 if (!rc) {
221 *(PFILESTATUS3)pInfoBuf = fs3; // Copy aligned data
222 ((PFILESTATUS3L)pInfoBuf)->cbFile = fs3.cbFile; // Copy unaligned data
223 ((PFILESTATUS3L)pInfoBuf)->cbFileAlloc = fs3.cbFileAlloc;
224 ((PFILESTATUS3L)pInfoBuf)->attrFile = fs3.attrFile;
225 }
226 break;
227 case FIL_QUERYEASIZEL:
228 rc = DosQueryPathInfo(pszPathName, ulInfoLevel, &fs4, sizeof(fs4));
229 if (!rc) {
230 *(PFILESTATUS4)pInfoBuf = fs4; // Copy aligned data
231 ((PFILESTATUS4L)pInfoBuf)->cbFile = fs4.cbFile; // Copy unaligned data
232 ((PFILESTATUS4L)pInfoBuf)->cbFileAlloc = fs4.cbFileAlloc;
233 ((PFILESTATUS4L)pInfoBuf)->attrFile = fs4.attrFile;
234 ((PFILESTATUS4L)pInfoBuf)->cbList = fs4.cbList;
235 }
236 break;
237 default:
238 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
239 rc = ERROR_INVALID_PARAMETER;
240 } // switch
241 }
242 else
[1432]243 rc = DosQueryPathInfo (pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf);
[850]244
245 return rc;
246}
247
248/**
249 * Wrap DosSetPathInfo to avoid spurious ERROR_INVALID_NAME returns and
250 * support systems without large file support
251 *
[827]252 * Some kernels to do not correctly handle FILESTATUS3 and PEAOP2 buffers
253 * that cross a 64K boundary.
254 * When this occurs, they return ERROR_INVALID_NAME.
255 * This code works around the problem because if the passed buffer crosses
256 * the boundary the alternate buffer will not because both are on the stack
257 * and we don't put enough additional data on the stack for this to occur.
258 * It is caller's responsitibility to report errors
[847]259 * @param pInfoBuf pointer to FILESTATUS3(L) or EAOP2 buffer
260 * @param ulInfoLevel FIL_STANDARD(L) or FIL_QUERYEASIZE
[827]261 * @returns Same as DosSetPathInfo
262 */
263
[841]264APIRET xDosSetPathInfo(PSZ pszPathName,
[850]265 ULONG ulInfoLevel,
[841]266 PVOID pInfoBuf,
267 ULONG cbInfoBuf,
[850]268 ULONG flOptions)
[826]269{
[850]270 FILESTATUS3 fs3;
271 FILESTATUS3 fs3_a;
272 FILESTATUS3L fs3l;
273 EAOP2 eaop2;
[849]274 APIRET rc;
[968]275 BOOL crosses = ((ULONG)pInfoBuf ^
[1354]276 ((ULONG)pInfoBuf + cbInfoBuf - 1)) & ~0xffff;
277 BOOL fResetVerify = FALSE;
[850]278
[1354]279 if (fVerify && driveflags[toupper(*pszPathName) - 'A'] & DRIVE_WRITEVERIFYOFF) {
280 DosSetVerify(FALSE);
281 fResetVerify = TRUE;
282 }
[850]283 switch (ulInfoLevel) {
284 case FIL_STANDARD:
[975]285 if (crosses) {
[968]286 fs3 = *(PFILESTATUS3)pInfoBuf; // Copy to buffer that does not cross 64K boundary
287 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3, cbInfoBuf, flOptions);
288 }
289 else
290 rc = DosSetPathInfo(pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf, flOptions);
[850]291 break;
292
293 case FIL_STANDARDL:
294 if (fNoLargeFileSupport) {
295 ulInfoLevel = FIL_STANDARD;
296 fs3 = *(PFILESTATUS3)pInfoBuf; // Copy aligned data
297 // Check size too big to handle
298 if (((PFILESTATUS3L)pInfoBuf)->cbFile >= 1LL << 32 ||
299 ((PFILESTATUS3L)pInfoBuf)->cbFileAlloc >= 2LL << 32)
300 {
301 rc = ERROR_INVALID_PARAMETER;
302 }
303 else {
304 fs3.cbFile = ((PFILESTATUS3L)pInfoBuf)->cbFile; // Copy unaligned data
305 fs3.cbFileAlloc = ((PFILESTATUS3L)pInfoBuf)->cbFileAlloc;
306 fs3.attrFile = ((PFILESTATUS3L)pInfoBuf)->attrFile;
307 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3, sizeof(fs3), flOptions);
308 }
309 if (rc == ERROR_INVALID_NAME) {
310 // fixme to validate counts?
311 fs3_a = fs3; // Copy to buffer that does not cross
312 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3_a, sizeof(fs3_a), flOptions);
313 }
314 }
315 else {
316 rc = DosSetPathInfo(pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf, flOptions);
317 if (rc == ERROR_INVALID_NAME) {
318 fs3l = *(PFILESTATUS3L)pInfoBuf; // Copy to buffer that does not cross
319 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3l, sizeof(fs3l), flOptions);
320 }
321 }
322 break;
323 case FIL_QUERYEASIZE:
324 rc = DosSetPathInfo(pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf, flOptions);
325 if (rc == ERROR_INVALID_NAME) {
326 // fixme to validate counts?
327 eaop2 = *(PEAOP2)pInfoBuf; // Copy to buffer that does not cross
328 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &eaop2, sizeof(eaop2), flOptions);
[932]329 }
330 break;
[827]331 default:
332 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
333 rc = ERROR_INVALID_PARAMETER;
[850]334 } // switch
[1354]335 if (fResetVerify) {
336 DosSetVerify(fVerify);
337 fResetVerify = FALSE;
338 }
[826]339 return rc;
340}
341
[551]342PSZ xfgets(PSZ pszBuf, size_t cMaxBytes, FILE * fp, PCSZ pszSrcFile,
343 UINT uiLineNumber)
[400]344{
[551]345 PSZ psz = fgets(pszBuf, cMaxBytes, fp);
346
[400]347 if (!psz) {
348 if (ferror(fp))
349 Runtime_Error(pszSrcFile, uiLineNumber, "fgets");
350 }
351 else {
352 size_t c = strlen(psz);
[551]353
[400]354 if (c + 1 > cMaxBytes)
355 Runtime_Error(pszSrcFile, uiLineNumber, "buffer overflow");
[551]356 else if (!c || (psz[c - 1] != '\n' && psz[c - 1] != '\r'))
[400]357 Runtime_Error(pszSrcFile, uiLineNumber, "missing EOL");
358 }
359 return psz;
360}
361
[551]362PSZ xfgets_bstripcr(PSZ pszBuf, size_t cMaxBytes, FILE * fp, PCSZ pszSrcFile,
363 UINT uiLineNumber)
[400]364{
[551]365 PSZ psz = xfgets(pszBuf, cMaxBytes, fp, pszSrcFile, uiLineNumber);
366
[400]367 if (psz)
368 bstripcr(psz);
369 return psz;
370}
371
[1544]372/**
373 * Wrapper for fopen it works around DosOpenL's failure to
374 * thunk properly so that fm2 can be loaded in high memory
375 * It also gives the option of reporting file open errors
376 * If fSilent is TRUE it fails silently; if FALSE it produces a
377 * runtime error dialog. Note pszMode must be passed on the stack
378 * to xfopen to avoid the thunking problem.
379 */
380
[551]381FILE *xfopen(PCSZ pszFileName, PCSZ pszMode, PCSZ pszSrcFile,
[1544]382 UINT uiLineNumber, BOOL fSilent)
[395]383{
[1544]384 CHAR FileName[CCHMAXPATH];
385 FILE *fp;
[551]386
[1544]387 strcpy(FileName, pszFileName);
388 fp = fopen(FileName, pszMode);
389
390 if (!fp && !fSilent)
[395]391 Runtime_Error(pszSrcFile, uiLineNumber, "fopen");
392 return fp;
393}
394
[1544]395/**
396 * Wrapper for _fsopen it works around DosOpenL's failure to
397 * thunk properly so that fm2 can be loaded in high memory
398 * It also gives the option of reporting file open errors
399 * If fSilent is TRUE it fails silently; if FALSE it produces a
400 * runtime error dialog. Note pszMode must be passed on the stack
401 * to xfopen to avoid the thunking problem
402 */
403
[551]404FILE *xfsopen(PCSZ pszFileName, PCSZ pszMode, INT fSharemode, PCSZ pszSrcFile,
[1544]405 UINT uiLineNumber, BOOL fSilent)
[395]406{
[1544]407 CHAR FileName[CCHMAXPATH];
408 FILE *fp;
[551]409
[1544]410 strcpy(FileName, pszFileName);
411 fp = _fsopen(FileName, pszMode, fSharemode);
412
413 if (!fp && !fSilent)
[395]414 Runtime_Error(pszSrcFile, uiLineNumber, "_fsopen");
415 return fp;
416}
417
418//== xfree - safe free ==
419
[1009]420VOID xfree(PVOID pv, PCSZ pszSrcFile, UINT uiLineNumber)
[395]421{
[1009]422 if (pv && pv != NullStr) {
[1063]423# ifdef FORTIFY
[1009]424 Fortify_free(pv, pszSrcFile, uiLineNumber);
[1063]425# else
[395]426 free(pv);
[1063]427# endif
[1009]428
429 }
[395]430}
431
432//== xmalloc() malloc with error checking ==
433
434PVOID xmalloc(size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
435{
[1006]436# ifdef FORTIFY
437 PVOID pv = Fortify_malloc(cBytes, pszSrcFile, uiLineNumber);
[1011]438# else
[395]439 PVOID pv = malloc(cBytes);
[1063]440# endif
[395]441
442 if (!pv)
[551]443 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
[395]444
445 return pv;
446}
447
448//== xmallocz() malloc and zero with error checking ==
449
450PVOID xmallocz(size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
451{
[1011]452 PVOID pv = xmalloc(cBytes, pszSrcFile, uiLineNumber);
[395]453
[1011]454 if (pv)
[395]455 memset(pv, 0, cBytes);
456
457 return pv;
458}
459
460//== xrealloc() realloc with error checking ==
461
462PVOID xrealloc(PVOID pvIn, size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
463{
[963]464 if (pvIn != NullStr) {
[1063]465# ifdef FORTIFY
466 PVOID pv = Fortify_realloc(pvIn, cBytes, pszSrcFile, uiLineNumber);
467# else
468 PVOID pv = realloc(pvIn, cBytes);
469# endif
[395]470
[963]471 if (!pv && cBytes)
472 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
[395]473
[963]474 return pv;
475 }
476 else
477 return xmalloc(cBytes, pszSrcFile, uiLineNumber);
[395]478}
479
480//== xstrdup() strdup with error checking ==
481
482PVOID xstrdup(PCSZ pszIn, PCSZ pszSrcFile, UINT uiLineNumber)
483{
[1009]484# ifdef FORTIFY
485 PSZ psz = Fortify_strdup(pszIn, pszSrcFile, uiLineNumber);
[1011]486# else
[395]487 PSZ psz = strdup(pszIn);
[1063]488# endif
[395]489
490 if (!psz)
[551]491 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
[395]492
493 return psz;
494}
[794]495
[1032]496
497#pragma alloc_text(WRAPPERS1,xfree,xfopen,xfsopen,xmalloc,xrealloc,xstrdup)
[1037]498#pragma alloc_text(WRAPPERS2,xDosSetPathInfo,xDosFindFirst,xDosFindNext)
Note: See TracBrowser for help on using the repository browser.