home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: WPS_PM
/
WPS_PM.zip
/
xfld085s.zip
/
helpers
/
dosh.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-02-23
|
35KB
|
1,102 lines
/*
*@@sourcefile dosh.c:
* dosh.c contains helper functions that are independent
* of a single application, i.e. you can use them in any
* program. All of the following work with OS/2 only.
*
* Function prefixes (new with V0.81):
* -- dosh* Dos (Control Program) helper functions
*
* These funcs are forward-declared in dosh.h, which
* must be #include'd first.
*
* Save dosh.h to enforce a complete recompile of XFolder.
* That header is checked for in the main makefile.
*
*@@include #define INCL_DOSPROCESS
*@@include #include <os2.h>
*@@include #include "dosh.h"
*/
/*
* Copyright (C) 1997-99 Ulrich Möller.
* This file is part of the XFolder source package.
* XFolder is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, in version 2 as it comes in the
* "COPYING" file of the XFolder main distribution.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define INCL_DOSDEVIOCTL
#define INCL_DOS
#define INCL_DOSERRORS
#define INCL_WIN
#define INCL_GPI
#include <os2.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "dosh.h"
// #define _PMPRINTF_
#include "pmprintf.h"
const CHAR acDriveLetters[28] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/*
*@@ doshGetULongTime:
* this returns the current time as a ULONG value (in milliseconds).
* Useful for stopping how much time the machine has spent in
* a certain function. To do this, simply call this function twice,
* and subtract the two values, which will give you the execution
* time in milliseconds.
*/
ULONG doshGetULongTime(VOID) {
DATETIME dt;
DosGetDateTime(&dt);
return (10*(dt.hundredths + 100*(dt.seconds + 60*(dt.minutes + 60*(dt.hours)))));
}
/*
*@@ doshQueryShiftState:
* returns TRUE if any of the SHIFT keys are
* currently pressed.
*/
BOOL doshQueryShiftState(VOID)
{
// BYTE abBuf[512];
HFILE hfKbd;
ULONG ulAction; //, cbRead, cbWritten;
SHIFTSTATE ShiftState;
ULONG cbDataLen = sizeof(ShiftState);
DosOpen("KBD$", &hfKbd, &ulAction, 0,
FILE_NORMAL, FILE_OPEN,
OPEN_ACCESS_READONLY | OPEN_SHARE_DENYWRITE,
(PEAOP2)NULL);
DosDevIOCtl(hfKbd, IOCTL_KEYBOARD, KBD_GETSHIFTSTATE,
NULL, 0, NULL, // no parameters
&ShiftState, cbDataLen, &cbDataLen);
DosClose(hfKbd);
return ((ShiftState.fsState & 3) != 0);
}
/*
*@@ doshIsWarp4:
* returns TRUE only if at least OS/2 Warp 4 is running.
*/
BOOL doshIsWarp4(VOID)
{
ULONG aulBuf[3];
DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_MINOR,
&aulBuf, sizeof(aulBuf));
return ((aulBuf[0] != 20) || (aulBuf[1] > 30));
}
/*
*@@ doshEnumDrives:
* this copies the drive letters of the drives on the
* system to pszBuffer which match the given pszFileSystem
* string (for example, "HPFS"). If pszFileSystem
* is NULL, all drives are enumerated.
* pszBuffer should be 27 characters in size to hold
* information for all drives.
*/
VOID doshEnumDrives(PSZ pszBuffer, // out: drive letters
PSZ pszFileSystem) // in: FS's to match or NULL
{
CHAR szName[5] = "";
ULONG ulLogicalDrive = 3, // start with drive C:
ulFound = 0; // found drives count
APIRET arc = NO_ERROR; // return code
// go thru the drives, start with C: (== 3)
do {
UCHAR nonRemovable=0;
ULONG parmSize=2;
ULONG dataLen=1;
#pragma pack(1)
struct
{
UCHAR dummy,drive;
} parms;
#pragma pack()
parms.drive=(UCHAR)(ulLogicalDrive-1);
arc = DosDevIOCtl((HFILE)-1,
IOCTL_DISK,
DSK_BLOCKREMOVABLE,
&parms,
parmSize,
&parmSize,
&nonRemovable,
1,
&dataLen);
if (arc == NO_ERROR)
{
if (nonRemovable) {
ULONG ulOrdinal = 0; // ordinal of entry in name list
BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
szName[0] = acDriveLetters[ulLogicalDrive];
szName[1] = ':';
szName[2] = '\0';
arc = DosQueryFSAttach(
szName, // logical drive of attached FS
ulOrdinal, // ignored for FSAIL_QUERYNAME
FSAIL_QUERYNAME, // return data for a Drive or Device
pfsqBuffer, // returned data
&cbBuffer); // returned data length
if (arc == NO_ERROR)
{
// The data for the last three fields in the FSQBUFFER2
// structure are stored at the offset of fsqBuffer.szName.
// Each data field following fsqBuffer.szName begins
// immediately after the previous item.
CHAR* pszFSDName = (PSZ)&(pfsqBuffer->szName) + (pfsqBuffer->cbName) + 1;
if (pszFileSystem == NULL) {
// enum-all mode: always copy
pszBuffer[ulFound] = szName[0]; // drive letter
ulFound++;
} else if (strcmp(pszFSDName, pszFileSystem) == 0) {
pszBuffer[ulFound] = szName[0]; // drive letter
ulFound++;
}
}
}
ulLogicalDrive++;
}
} while ( arc == NO_ERROR );
pszBuffer[ulFound] = '\0';
}
/*
*@@ doshQueryBootDrive:
* returns the letter of the boot drive
*/
CHAR doshQueryBootDrive(VOID)
{
ULONG ulBootDrive;
DosQuerySysInfo(5, 5, &ulBootDrive, sizeof(ulBootDrive));
return (acDriveLetters[ulBootDrive]);
}
/*
*@@ doshIsFixedDisk:
* checks whether a disk is fixed or removeable.
* ulLogicalDrive must be 1 for drive A:, 2 for B:, ...
* The result is stored in *pfFixed.
* Returns DOS error code.
* Warning: This uses DosDevIOCtl, which has proved
* to cause problems with some device drivers for
* removeable disks.
*/
APIRET doshIsFixedDisk(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
PBOOL pfFixed) // out: TRUE for fixed disks
{
APIRET arc = ERROR_INVALID_DRIVE;
if (ulLogicalDrive) {
// parameter packet
struct {
UCHAR command, drive;
} parms;
// data packet
UCHAR ucNonRemoveable;
ULONG ulParmSize = sizeof(parms);
ULONG ulDataSize = sizeof(ucNonRemoveable);
parms.drive = (UCHAR)(ulLogicalDrive-1);
arc = DosDevIOCtl((HFILE)-1,
IOCTL_DISK,
DSK_BLOCKREMOVABLE,
&parms,
ulParmSize,
&ulParmSize,
&ucNonRemoveable,
ulDataSize,
&ulDataSize);
if (arc == NO_ERROR)
*pfFixed = (BOOL)ucNonRemoveable;
}
return (arc);
}
/*
*@@ doshAssertDrive:
* this checks for whether the given drive
* is currently available. If fSuppress == TRUE,
* DosError is used in a critical section to
* avoid "Drive not ready" popups.
*/
APIRET doshAssertDrive(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
BOOL fSuppress) // in: suppress-popups flag
{
FSALLOCATE fsa;
APIRET arc = NO_ERROR;
if (fSuppress) {
DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
DosEnterCritSec();
}
arc = DosQueryFSInfo(ulLogicalDrive, FSIL_ALLOC, &fsa, sizeof(fsa));
if (fSuppress) {
DosError(FERR_ENABLEHARDERR | FERR_ENABLEEXCEPTION);
DosExitCritSec();
}
return (arc);
}
/*
*@@ doshQueryDiskFree:
* returns the number of bytes remaining on the disk
* specified by the given logical drive, or -1 upon errors.
* Note: This returns a "double" value, because a ULONG
* can only hold values of some 4 billion, which would
* lead to funny results for drives > 4 GB.
*/
double doshQueryDiskFree(ULONG ulLogicalDrive) // in: 1 for A:, 2 for B:, 3 for C:, ...
{
FSALLOCATE fsa;
double dbl = -1;
if (ulLogicalDrive)
if (DosQueryFSInfo(ulLogicalDrive, FSIL_ALLOC, &fsa, sizeof(fsa))
== NO_ERROR)
dbl = (fsa.cSectorUnit * fsa.cbSector * fsa.cUnitAvail);
return (dbl);
}
/*
*@@ doshQueryDiskFSType:
* copies the file-system type of the given disk object
* (HPFS, FAT, CDFS etc.) to pszBuf.
* Returns the DOS error code.
*/
APIRET doshQueryDiskFSType(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
PSZ pszBuf) // out: buffer for FS type
{
APIRET arc = NO_ERROR;
CHAR szName[5];
szName[0] = acDriveLetters[ulLogicalDrive];
szName[1] = ':';
szName[2] = '\0';
{
ULONG ulOrdinal = 0; // ordinal of entry in name list
// PBYTE pszFSDName = NULL; // pointer to FS name
// PBYTE prgFSAData = NULL; // pointer to FS data
BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
arc = DosQueryFSAttach(
szName, // logical drive of attached FS
ulOrdinal, // ignored for FSAIL_QUERYNAME
FSAIL_QUERYNAME, // return data for a Drive or Device
pfsqBuffer, // returned data
&cbBuffer); // returned data length
if (arc == NO_ERROR)
{
// The data for the last three fields in the FSQBUFFER2
// structure are stored at the offset of fsqBuffer.szName.
// Each data field following fsqBuffer.szName begins
// immediately after the previous item.
PSZ pszFSDName = (CHAR*)(&pfsqBuffer->szName) + pfsqBuffer->cbName + 1;
strcpy(pszBuf, pszFSDName);
}
}
return (arc);
}
/*
*@@ doshQueryDiskType:
* this retrieves more information about a given drive,
* which is stored in *pulDeviceType. According to the
* IBM Control Program Reference, this value can be:
* <BR> 0 48 TPI low-density diskette drive
* <BR> 1 96 TPI high-density diskette drive
* <BR> 2 3.5-inch 720KB diskette drive
* <BR> 3 8-Inch single-density diskette drive
* <BR> 4 8-Inch double-density diskette drive
* <BR> 5 Fixed disk
* <BR> 6 Tape drive
* <BR> 7 Other (includes 1.44MB 3.5-inch diskette drive)
* <BR> 8 R/W optical disk
* <BR> 9 3.5-inch 4.0MB diskette drive (2.88MB formatted)
* <BR> Returns DOS error code.
* Warning: This uses DosDevIOCtl, which has proved
* to cause problems with some device drivers for
* removeable disks.
*/
APIRET doshQueryDiskType(ULONG ulLogicalDrive, // in: 1 = A:, 2 = B:, ...
PULONG pulDeviceType) // out: device type
{
APIRET arc = ERROR_INVALID_DRIVE;
if (ulLogicalDrive) {
#pragma pack(1)
// parameter packet
struct {
UCHAR command, drive;
} parms;
// data packet
struct {
UCHAR aucBPB[31]; // BIOS parameter block
USHORT usCylinders;
UCHAR ucDeviceType;
USHORT usDeviceAttrs;
} data;
#pragma pack()
ULONG ulParmSize = sizeof(parms);
ULONG ulDataSize = sizeof(data);
parms.command = 1; // read currently inserted media
parms.drive=(UCHAR)(ulLogicalDrive-1);
arc = DosDevIOCtl((HFILE)-1,
IOCTL_DISK,
DSK_GETDEVICEPARAMS,
&parms, ulParmSize, &ulParmSize,
&data, ulDataSize, &ulDataSize);
if (arc == NO_ERROR)
*pulDeviceType = (ULONG)(data.ucDeviceType);
}
return (arc);
}
/*
*@@ doshIsFileOnFAT:
* returns TRUE if pszFileName resides on
* a FAT drive.
*/
BOOL doshIsFileOnFAT(PSZ pszFileName)
{
BOOL brc = FALSE;
CHAR szName[5];
szName[0] = pszFileName[0];
szName[1] = ':';
szName[2] = '\0';
#ifdef DEBUG_TITLECLASH
_Pmpf(("cmnIsFAT for %s -> %s", pszFileName, szName));
#endif
{
ULONG ulOrdinal = 0; // ordinal of entry in name list
// PBYTE pszFSDName = NULL; // pointer to FS name
// PBYTE prgFSAData = NULL; // pointer to FS data
APIRET rc = NO_ERROR; // return code
BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
rc = DosQueryFSAttach(
szName, // logical drive of attached FS
ulOrdinal, // ignored for FSAIL_QUERYNAME
FSAIL_QUERYNAME, // return data for a Drive or Device
pfsqBuffer, // returned data
&cbBuffer); // returned data length
if (rc == NO_ERROR)
{
// The data for the last three fields in the FSQBUFFER2
// structure are stored at the offset of fsqBuffer.szName.
// Each data field following fsqBuffer.szName begins
// immediately after the previous item.
PSZ pszFSDName = (PSZ)&(pfsqBuffer->szName) + pfsqBuffer->cbName + 1;
#ifdef DEBUG_TITLECLASH
_Pmpf((" cmnIsFAT -> File system: %s", pszFSDName));
#endif
if (strncmp(pszFSDName, "FAT", 3) == 0)
brc = TRUE;
}
}
return (brc);
}
/*
*@@ doshIsValidFileName:
* this returns NO_ERROR only if pszFile is a valid file name.
* This may include a full path.
* If a drive letter is specified, this checks for whether
* that drive is a FAT drive and adjust the checks accordingly,
* i.e. 8+3 syntax and more invalid characters.
* If no drive letter is specified, this check is performed
* for the current drive.
* Note: this performs syntactic checks only. This does not
* check for whether the specified path components exist.
* However, it _is_ checked for whether the given drive
* exists.
* If an error is found, the corresponding DOS error code
* is returned:
* <BR> ERROR_INVALID_DRIVE
* <BR> ERROR_FILENAME_EXCED_RANGE (on FAT: no 8+3 filename)
* <BR> ERROR_INVALID_NAME (invalid character)
*/
APIRET doshIsValidFileName(PSZ pszFile)
{
CHAR szPath[CCHMAXPATH+4] = " :";
CHAR szComponent[CCHMAXPATH];
PSZ p1, p2;
BOOL fIsFAT = FALSE;
PSZ pszInvalid;
// check drive first
if (*(pszFile + 1) == ':')
{
CHAR cDrive = toupper(*pszFile);
// drive specified:
strcpy(szPath, pszFile);
szPath[0] = toupper(*pszFile);
if (doshQueryDiskFree(cDrive - 'A' + 1) == -1)
return (ERROR_INVALID_DRIVE);
}
else
{
// no drive specified: take current
ULONG ulDriveNum = 0,
ulDriveMap = 0;
DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap);
szPath[0] = ((UCHAR)ulDriveNum) + 'A' - 1;
szPath[1] = ':';
strcpy(&szPath[2], pszFile);
}
fIsFAT = doshIsFileOnFAT(szPath);
pszInvalid = (fIsFAT)
? "<>|+=:;,\"/[] " // invalid characters in FAT
: "<>|:\"/"; // invalid characters in IFS's
// now separate path components
p1 = &szPath[2]; // advance past ':'
do {
if (*p1 == '\\')
p1++;
p2 = strchr(p1, '\\');
if (p2 == NULL)
p2 = p1 + strlen(p1);
if (p1 != p2)
{
LONG lDotOfs = -1,
lAfterDot = -1;
ULONG cbFile,
ul;
PSZ pSource = szComponent;
strncpy(szComponent, p1, p2-p1);
szComponent[p2-p1] = 0;
cbFile = strlen(szComponent);
// now check each path component
for (ul = 0; ul < cbFile; ul++)
{
if (fIsFAT)
{
// on FAT: only 8 characters allowed before dot
if (*pSource == '.')
{
lDotOfs = ul;
lAfterDot = 0;
if (ul > 7)
return (ERROR_FILENAME_EXCED_RANGE);
}
}
// and check for invalid characters
if (strchr(pszInvalid, *pSource) != NULL)
return (ERROR_INVALID_NAME);
pSource++;
// on FAT, allow only three chars after dot
if (fIsFAT)
if (lAfterDot != -1)
{
lAfterDot++;
if (lAfterDot > 3)
return(ERROR_FILENAME_EXCED_RANGE);
}
}
// we are still missing the case of a FAT file
// name without extension; if so, check whether
// the file stem is <= 8 chars
if (fIsFAT)
if (lDotOfs == -1) // dot not found:
if (cbFile > 8)
return (ERROR_FILENAME_EXCED_RANGE);
}
// go for next component
p1 = p2+1;
} while (*p2);
return (NO_ERROR);
}
/*
*@@ doshMakeRealName:
* this copies pszSource to pszTarget, replacing
* all characters which are not supported by file
* systems with cReplace.
* pszTarget must be at least the same size as pszSource.
* If (fIsFAT), the file name will be made FAT-compliant (8+3).
* Returns TRUE if characters were replaced.
*/
BOOL doshMakeRealName(PSZ pszTarget, // out: new real name
PSZ pszSource, // in: filename to translate
CHAR cReplace, // in: replacement char for invalid
// characters (e.g. '!')
BOOL fIsFAT) // in: make-FAT-compatible flag
{
ULONG ul,
cbSource = strlen(pszSource);
LONG lDotOfs = -1,
lAfterDot = -1;
BOOL brc = FALSE;
PSZ pSource = pszSource,
pTarget = pszTarget,
pszInvalid = (fIsFAT)
? "<>|+=:;,\"/\\[] " // invalid characters in FAT
: "<>|:\"/\\"; // invalid characters in IFS's
for (ul = 0; ul < cbSource; ul++)
{
if (fIsFAT) {
// on FAT: truncate filename if neccessary
if (*pSource == '.')
{
lDotOfs = ul;
lAfterDot = 0;
if (ul > 7) {
// only 8 characters allowed before dot,
// so set target ptr to dot pos
pTarget = pszTarget+8;
}
}
}
// and replace invalid characters
if (strchr(pszInvalid, *pSource) == NULL)
*pTarget = *pSource;
else {
*pTarget = cReplace;
brc = TRUE;
}
pTarget++;
pSource++;
// on FAT, allow only three chars after dot
if (fIsFAT)
if (lAfterDot != -1) {
lAfterDot++;
if (lAfterDot > 3)
break;
}
}
*pTarget = '\0';
#ifdef DEBUG_TITLECLASH
_Pmpf((" strMakeRealName: returning %s", pszTarget));
#endif
if (fIsFAT)
{
// we are still missing the case of a FAT file
// name without extension; if so, check whether
// the file stem is <= 8 chars
if (lDotOfs == -1) // dot not found:
if (cbSource > 8)
*(pszTarget+8) = 0; // truncate
// convert to upper case
strupr(pszTarget);
}
return (brc);
}
/*
*@@ doshQueryFileSize:
* returns the size of an already opened file.
*/
ULONG doshQueryFileSize(HFILE hFile)
{
FILESTATUS3 fs3;
if (DosQueryFileInfo(hFile, FIL_STANDARD, &fs3, sizeof(fs3)))
return (0);
else
return (fs3.cbFile);
}
/*
*@@ doshQueryPathSize:
* returns the size of any file,
* or 0 if the file could not be
* found.
*/
ULONG doshQueryPathSize(PSZ pszFile)
{
FILESTATUS3 fs3;
if (DosQueryPathInfo(pszFile, FIL_STANDARD, &fs3, sizeof(fs3)))
return (0);
else
return (fs3.cbFile);
}
/*
*@@ doshQueryDirExist:
* returns TRUE if the given directory
* exists.
*/
BOOL doshQueryDirExist(PSZ pszDir)
{
FILESTATUS3 fs3;
APIRET arc = DosQueryPathInfo(pszDir, FIL_STANDARD, &fs3, sizeof(fs3));
if (arc == NO_ERROR)
// file found:
return ((fs3.attrFile & FILE_DIRECTORY) != 0);
else
return FALSE;
}
/*
*@@ doshCreatePath:
* this creates the specified directory.
* As opposed to DosCreateDir, this
* function can create several directories
* at the same time, if the parent
* directories do not exist yet.
*/
APIRET doshCreatePath(PSZ pszPath)
{
APIRET arc0 = NO_ERROR;
CHAR path[CCHMAXPATH];
CHAR *cp, c;
ULONG cbPath;
strcpy(path, pszPath);
cbPath = strlen(path);
if (path[cbPath] != '\\')
{
path[cbPath] = '\\';
path[cbPath+1] = 0;
}
cp = path;
// advance past the drive letter only if we have one
if (*(cp+1) == ':')
cp += 3;
// Now, make the directories
while (*cp != 0)
{
if (*cp == '\\')
{
c = *cp;
*cp = 0;
if (!doshQueryDirExist(path))
{
APIRET arc = DosCreateDir(path, 0);
if (arc != NO_ERROR)
{
arc0 = arc;
break;
}
}
*cp = c;
}
cp++;
}
return (arc0);
}
/*
*@@ doshSetCurrentDir:
* sets the current working directory
* to the given path.
* As opposed to DosSetCurrentDir, this
* one will change the current drive
* also, if one is specified.
*/
APIRET doshSetCurrentDir(PSZ pszDir)
{
if (pszDir)
{
if (*pszDir != 0)
if (*(pszDir+1) == ':')
{
// drive given:
CHAR cDrive = toupper(*(pszDir));
APIRET arc;
// change drive
arc = DosSetDefaultDisk( (ULONG)(cDrive - 'A' + 1) );
// 1 = A:, 2 = B:, ...
if (arc != NO_ERROR)
return (arc);
}
return (DosSetCurrentDir(pszDir));
}
return (ERROR_INVALID_PARAMETER);
}
/*
*@@ doshReadTextFile:
* reads a text file from disk, allocates memory
* via malloc() and returns a pointer to this
* buffer (or NULL upon errors). Specify in
* ulExtraMemory how much extra memory (in addition
* to the file's size) should be allocated to
* allow for text manipulation.
* Returns NULL if an error occured.
*/
PSZ doshReadTextFile(PSZ pszFile, ULONG ulExtraMemory)
{
ULONG ulSize,
ulBytesRead = 0,
ulAction, ulLocal;
HFILE hFile;
PSZ pszContent = NULL;
APIRET rc = DosOpen(pszFile,
&hFile,
&ulAction, // action taken
5000L, // primary allocation size
FILE_ARCHIVED | FILE_NORMAL, // file attribute
/* OPEN_ACTION_CREATE_IF_NEW | */
OPEN_ACTION_OPEN_IF_EXISTS, // open flags
OPEN_FLAGS_NOINHERIT |
OPEN_SHARE_DENYNONE |
OPEN_ACCESS_READONLY, // read-write mode
NULL); // no EAs
if (rc == NO_ERROR) {
ulSize = doshQueryFileSize(hFile);
pszContent = (PSZ)malloc(ulSize+10+ulExtraMemory);
rc = DosSetFilePtr(hFile,
0L,
FILE_BEGIN,
&ulLocal);
rc = DosRead(hFile,
pszContent,
ulSize,
&ulBytesRead);
DosClose(hFile);
*(pszContent+ulBytesRead) = '\0';
}
return (pszContent);
}
/*
*@@ doshCreateBackupFileName:
* creates a valid backup filename of pszExisting
* with a numerical file name extension which does
* not exist in the directory where pszExisting
* resides.
* Returns a PSZ to a new buffer which was allocated
* using malloc().
* <P><B>Example:</B> returns "C:\CONFIG.002" for input
* "C:\CONFIG.SYS" if "C:\CONFIG.001" already exists.
*/
PSZ doshCreateBackupFileName(PSZ pszExisting)
{
// CHAR szTemp[CCHMAXPATH];
PSZ pszNew = strdup(pszExisting),
pszLastDot = strrchr(pszNew, '.');
ULONG ulCount = 1;
CHAR szCount[5];
do {
sprintf(szCount, ".%03d", ulCount);
strcpy(pszLastDot, szCount);
ulCount++;
} while (doshQueryPathSize(pszNew) != 0);
return (pszNew);
}
/*
*@@ doshWriteTextFile:
* writes a text file to disk; pszFile must contain the
* whole path and filename.
* An existing file will be backed up if (fBackup == TRUE),
* using doshCreateBackupFileName; otherwise the file
* will be overwritten.
* Returns the number of bytes written or 0 upon errors.
*/
ULONG doshWriteTextFile(PSZ pszFile, // in: file name
PSZ pszContent, // in: text to write
BOOL fBackup) // in: create-backup flag
{
ULONG ulWritten = 0,
ulAction, ulLocal;
HFILE hFile;
APIRET rc;
if (fBackup) {
PSZ pszBackup = doshCreateBackupFileName(pszFile);
DosCopy(pszFile, pszBackup, DCPY_EXISTING);
free(pszBackup);
}
rc = DosOpen(pszFile,
&hFile,
&ulAction, // action taken
5000L, // primary allocation size
FILE_ARCHIVED | FILE_NORMAL, // file attribute
OPEN_ACTION_CREATE_IF_NEW
| OPEN_ACTION_REPLACE_IF_EXISTS, // open flags
OPEN_FLAGS_NOINHERIT
| OPEN_FLAGS_WRITE_THROUGH // write immediately w/out cache
| OPEN_FLAGS_NO_CACHE // do not store in cache
| OPEN_FLAGS_SEQUENTIAL // sequential, not random access
| OPEN_SHARE_DENYNONE
| OPEN_ACCESS_WRITEONLY, // read-write mode
NULL); // no EAs
if (rc == NO_ERROR)
{
ULONG ulSize = strlen(pszContent); // exclude 0 byte
rc = DosSetFilePtr(hFile,
0L,
FILE_BEGIN,
&ulLocal);
if (rc == NO_ERROR) {
rc = DosWrite(hFile,
pszContent,
ulSize,
&ulWritten);
if (rc == NO_ERROR)
rc = DosSetFileSize(hFile, ulSize);
}
DosClose(hFile);
if (rc != NO_ERROR)
ulWritten = 0;
}
return (ulWritten);
}
/*
*@@ doshOpenLogFile:
* this opens a log file in the root directory of
* the boot drive; it is titled pszFilename, and
* the file handle is returned.
*/
HFILE doshOpenLogFile(PSZ pszFileName)
{
APIRET rc;
CHAR szFileName[CCHMAXPATH];
HFILE hfLog;
ULONG ulAction;
ULONG ibActual;
sprintf(szFileName, "%c:\\%s", doshQueryBootDrive(), pszFileName);
rc = DosOpen(szFileName, &hfLog, &ulAction, 0,
FILE_NORMAL,
OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE,
(PEAOP2)NULL);
if (rc == NO_ERROR) {
DosSetFilePtr(hfLog, 0, FILE_END, &ibActual);
return (hfLog);
} else
return (0);
}
/*
* doshWriteToLogFile
* writes a string to a log file, adding a
* leading timestamp.
*/
APIRET doshWriteToLogFile(HFILE hfLog, PSZ psz)
{
if (hfLog) {
DATETIME dt;
CHAR szTemp[2000];
ULONG cbWritten;
DosGetDateTime(&dt);
sprintf(szTemp, "Time: %02d:%02d:%02d %s",
dt.hours, dt.minutes, dt.seconds,
psz);
return (DosWrite(hfLog, psz, strlen(psz), &cbWritten));
}
else return (ERROR_INVALID_HANDLE);
}
/*
*@@ doshQuickStartSession:
* shortcut to DosStartSession w/out having to deal
* with all the parameters. This one starts a session
* as a child session and can optionally wait for the
* session to end (using a termination queue), if
* Wait == TRUE; otherwise, this function returns
* immediately.
* Returns the error code of DosStartSession.
*/
APIRET doshQuickStartSession(PSZ pszPath, // in: program to start
PSZ pszParams, // in: parameters for program
BOOL Visible, // in: show program?
BOOL Wait, // in: wait for termination?
PULONG pulSID, // out: session ID
PPID ppid) // out: process ID
{
APIRET rc;
REQUESTDATA rqdata;
ULONG DataLength; PULONG DataAddress; BYTE elpri;
int er;
// Queue Stuff
HQUEUE hq;
PID qpid=0;
STARTDATA SData;
CHAR szObjBuf[CCHMAXPATH];
if (Wait) {
if ( (er=DosCreateQueue(&hq, QUE_FIFO|QUE_CONVERT_ADDRESS, "\\queues\\kfgstart.que"))
!= NO_ERROR)
{
char str[80];
sprintf(str, "Create %ld\n", er);
}
if ((er=DosOpenQueue(&qpid, &hq, "\\queues\\kfgstart.que")) != NO_ERROR)
{
char str[80];
sprintf(str, "Open %ld\n", er);
}
}
SData.Length = sizeof(STARTDATA);
SData.Related = SSF_RELATED_CHILD; //INDEPENDENT;
SData.FgBg = SSF_FGBG_FORE;
SData.TraceOpt = SSF_TRACEOPT_NONE;
SData.PgmTitle = pszPath; // title for window
SData.PgmName = pszPath;
SData.PgmInputs = pszParams;
SData.TermQ = (Wait) ? "\\queues\\kfgstart.que" : NULL;
SData.Environment = 0;
SData.InheritOpt = SSF_INHERTOPT_SHELL;
SData.SessionType = SSF_TYPE_DEFAULT;
SData.IconFile = 0;
SData.PgmHandle = 0;
SData.PgmControl = ((Visible) ? SSF_CONTROL_VISIBLE : SSF_CONTROL_INVISIBLE);
SData.InitXPos = 30;
SData.InitYPos = 40;
SData.InitXSize = 200;
SData.InitYSize = 140;
SData.Reserved = 0;
SData.ObjectBuffer = (CHAR*)&szObjBuf;
SData.ObjectBuffLen = (ULONG)sizeof(szObjBuf);
rc = DosStartSession(&SData, pulSID, ppid);
if (rc == NO_ERROR) {
if (Wait) {
rqdata.pid=qpid;
DosReadQueue(hq, &rqdata, &DataLength, (PVOID*)&DataAddress, 0, 0, &elpri, 0);
DosCloseQueue(hq);
}
}
return (rc);
}
/*
*@@ doshSetPathAttr:
* sets the file attributes of pszFile,
* which can be fully qualified.
* fAttr can be:
* <BR> FILE_ARCHIVED
* <BR> FILE_READONLY
* <BR> FILE_SYSTEM
* <BR> FILE_HIDDEN
* <BR> Note that this sets all the given
* attributes; the existing attributes
* are lost.
*/
APIRET doshSetPathAttr(PSZ pszFile, ULONG fAttr)
{
FILESTATUS3 fs3;
APIRET rc = DosQueryPathInfo(pszFile,
FIL_STANDARD,
&fs3,
sizeof(fs3));
if (rc == NO_ERROR) {
fs3.attrFile = fAttr;
rc = DosSetPathInfo(pszFile,
FIL_STANDARD,
&fs3,
sizeof(fs3),
DSPI_WRTTHRU);
}
return (rc);
}