home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
cset21v5.zip
/
TOOLKT21
/
REXX
/
SAMPLES
/
REXXUTIL
/
REXXUTIL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-12
|
118KB
|
2,508 lines
/**********************************************************************
* REXXUTIL.C *
* *
* This program extends the REXX language by providing many *
* REXX external functions. *
* This sample program contains a subset of the functions *
* provided in the version of REXXUTIL.DLL that is included in *
* the base OS/2 product. *
* These functions are: *
* SysCls -- Clear the screen in an OS/2 fullscreen *
* or windowed command prompt session. *
* SysCurPos -- Set and/or Query the cursor position *
* in an OS/2 fullscreen or windowed *
* command prompt session. *
* SysCurState -- Make the cursor visible or invisible *
* in an OS/2 fullscreen or windowed *
* command prompt session. *
* SysDriveInfo -- Returns information about a specific *
* drive. *
* SysDriveMap -- Returns a list of the drives on the *
* machine *
* SysDropFuncs -- Makes all functions in this package *
* unknown to REXX. *
* SysFileDelete -- Deletes a file *
* SysFileSearch -- Searches for a file matching a given *
* filespec. *
* SysFileTree -- Searches for files matching a given *
* filespec, including files in *
* subdirectories. *
* SysGetMessage -- Retrieves a message text from an OS/2 *
* message file, substituting values *
* provided. *
* SysIni -- Reads and/or updates entries in .INI *
* files. *
* SysLoadFuncs -- Makes all functions in this package *
* known to REXX so REXX programs may *
* call them. *
* SysMkDir -- Creates a directory *
* SysOS2Ver -- Returns the OS/2 Version number *
* SysRmDir -- Removes a directory *
* SysSearchPath -- Searches throught a specified path *
* for a file. *
* SysSleep -- Suspends execution for a number of *
* seconds. *
* SysTempFileName -- Creates a unique filename *
* SysTextScreenRead -- Reads characters from the screen, *
* in an OS/2 fullscreen or windowed *
* command prompt session. *
* SysTextScreenSize -- Returns the size of the window in *
* rows and columns, *
* in an OS/2 fullscreen or windowed *
* command prompt session. *
* SysGetEA -- Reads an extended attribute *
* for a file. *
* SysPutEA -- Writes an extended attribute *
* for a file. *
* SysWaitNamedPipe -- Wait on a named pipe. *
* SysMakeNamedPipe -- Create a named pipe. *
* SysConnectNamedPipe -- Prepare a named pipe for connection. *
* SysDisConnectNamedPipe -- Release a pipe connection. *
* *
* To compile: MAKE REXXUTIL *
* *
**********************************************************************/
/* Include files */
#define INCL_WINSHELLDATA
#define INCL_VIO
#define INCL_DOS
#define INCL_DOSFILEMGR
#define INCL_DOSMEMMGR
#define INCL_DOSMISC
#define INCL_DONMPIPES
#define INCL_ERRORS
#define INCL_REXXSAA
#define _DLL
#define _MT
#include <os2.h>
#include <rexxsaa.h>
#include <memory.h>
#include <malloc.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#define DosSetFileMode Dos16SetFileMode
APIRET APIENTRY DosSetFileMode(PSZ pszFName, USHORT usAttr, ULONG ulReserved);
/*********************************************************************/
/* Declare all exported functions as REXX functions. */
/*********************************************************************/
RexxFunctionHandler SysCls;
RexxFunctionHandler SysCurPos;
RexxFunctionHandler SysCurState;
RexxFunctionHandler SysDriveInfo;
RexxFunctionHandler SysDriveMap;
RexxFunctionHandler SysDropFuncs;
RexxFunctionHandler SysFileDelete;
RexxFunctionHandler SysFileSearch;
RexxFunctionHandler SysFileTree;
RexxFunctionHandler SysGetMessage;
RexxFunctionHandler SysIni;
RexxFunctionHandler SysLoadFuncs;
RexxFunctionHandler SysMkDir;
RexxFunctionHandler SysOS2Ver;
RexxFunctionHandler SysRmDir;
RexxFunctionHandler SysSearchPath;
RexxFunctionHandler SysSleep;
RexxFunctionHandler SysTempFileName;
RexxFunctionHandler SysTextScreenRead;
RexxFunctionHandler SysTextScreenSize;
RexxFunctionHandler SysGetEA;
RexxFunctionHandler SysPutEA;
RexxFunctionHandler SysWaitNamedPipe;
/*********************************************************************/
/* Various definitions used by various functions. */
/*********************************************************************/
#define MAX_DIGITS 9 /* maximum digits in numeric arg */
#define MAX 256 /* temporary buffer length */
#define IBUF_LEN 4096 /* Input buffer length */
#define AllocFlag PAG_COMMIT | PAG_WRITE /* for DosAllocMem */
/*********************************************************************/
/* Defines used by SysDriveMap */
/*********************************************************************/
#define USED 0
#define FREE 1
#define DETACHED 2
#define REMOTE 3
#define LOCAL 4
/*********************************************************************/
/* Defines uses by SysTree */
/*********************************************************************/
#define FIRST_TIME 0x0001
#define RECURSE 0x0002
#define DO_DIRS 0x0004
#define DO_FILES 0x0008
#define NAME_ONLY 0x0010
#define EDITABLE_TIME 0x0020
#define IGNORE 2 /* Ignore attributes entirely */
#define AllAtts FILE_NORMAL | FILE_READONLY | FILE_HIDDEN | \
FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED
/*********************************************************************/
/* Structures used throughout REXXUTIL.C */
/*********************************************************************/
/*********************************************************************/
/* RxTree Structure used by SysTree. */
/*********************************************************************/
typedef struct RxTreeData {
ULONG count; /* Number of lines processed */
SHVBLOCK shvb; /* Request block for RxVar */
ULONG open_action; /* Action taken opening the */
/* file */
ULONG stemlen; /* Length of stem */
ULONG vlen; /* Length of variable value */
CHAR TargetSpec[MAX]; /* Filespec RxTree is looking */
/* for */
CHAR truefile[MAX]; /* Used to hold actual file */
/* name */
CHAR tempfile[MAX]; /* Used to hold temp file name*/
CHAR Temp[MAX]; /* Used when building stem */
/* element */
CHAR ibuf[IBUF_LEN]; /* Input buffer */
CHAR varname[MAX]; /* Buffer for the variable */
/* name */
ULONG j; /* Temp counter */
ULONG nattrib; /* New attrib, diff for each */
/* file */
} RXTREEDATA;
/*********************************************************************/
/* RxStemData */
/* Structure which describes as generic */
/* stem variable. */
/*********************************************************************/
typedef struct RxStemData {
SHVBLOCK shvb; /* Request block for RxVar */
CHAR ibuf[IBUF_LEN]; /* Input buffer */
CHAR varname[MAX]; /* Buffer for the variable */
/* name */
CHAR stemname[MAX]; /* Buffer for the variable */
/* name */
ULONG stemlen; /* Length of stem. */
ULONG vlen; /* Length of variable value */
ULONG j; /* Temp counter */
ULONG tlong; /* Temp counter */
ULONG count; /* Number of elements */
/* processed */
} RXSTEMDATA;
/*********************************************************************/
/* RxFncTable */
/* Array of names of the REXXUTIL functions. */
/* This list is used for registration and deregistration. */
/*********************************************************************/
static PSZ RxFncTable[] =
{
"SysCls",
"SysCurpos",
"SysCurState",
"SysDriveInfo",
"SysDriveMap",
"SysDropFuncs",
"SysFileDelete",
"SysFileSearch",
"SysFileTree",
"SysGetEA",
"SysGetMessage",
"SysIni",
"SysLoadFuncs",
"SysMkDir",
"SysOS2Ver",
"SysRmDir",
"SysSearchPath",
"SysSleep",
"SysTempFileName",
"SysTextScreenRead",
"SysTextScreenSize",
"SysGetEA",
"SysPutEA",
"SysWaitNamedPipe",
};
/*********************************************************************/
/* Numeric Error Return Strings */
/*********************************************************************/
#define NO_UTIL_ERROR "0" /* No error whatsoever */
#define ERROR_NOMEM "2" /* Insufficient memory */
#define ERROR_FILEOPEN "3" /* Error opening text file */
/*********************************************************************/
/* Alpha Numeric Return Strings */
/*********************************************************************/
#define ERROR_RETSTR "ERROR:"
/*********************************************************************/
/* Numeric Return calls */
/*********************************************************************/
#define INVALID_ROUTINE 40 /* Raise Rexx error */
#define VALID_ROUTINE 0 /* Successful completion */
/*********************************************************************/
/* Some useful macros */
/*********************************************************************/
#define BUILDRXSTRING(t, s) { \
strcpy((t)->strptr,(s));\
(t)->strlength = strlen((s)); \
}
/*********************************************************************/
/**************** REXXUTIL Supporting Functions ********************/
/**************** REXXUTIL Supporting Functions ********************/
/**************** REXXUTIL Supporting Functions ********************/
/*********************************************************************/
/********************************************************************
* Function: string2long(string, number) *
* *
* Purpose: Validates and converts an ASCII-Z string from string *
* form to an unsigned long. Returns FALSE if the number *
* is not valid, TRUE if the number was successfully *
* converted. *
* *
* RC: TRUE - Good number converted *
* FALSE - Invalid number supplied. *
*********************************************************************/
BOOL string2long(PSZ string, LONG *number)
{
ULONG accumulator; /* converted number */
INT length; /* length of number */
INT sign; /* sign of number */
sign = 1; /* set default sign */
if (*string == '-') { /* negative?
sign = -1; /* change sign */
string++; /* step past sign */
}
length = strlen(string); /* get length of string */
if (length == 0 || /* if null string */
length > MAX_DIGITS) /* or too long */
return FALSE; /* not valid */
accumulator = 0; /* start with zero */
while (length) { /* while more digits */
if (!isdigit(*string)) /* not a digit? */
return FALSE; /* tell caller */
/* add to accumulator */
accumulator = accumulator *10 + (*string - '0');
length--; /* reduce length */
string++; /* step pointer */
}
*number = accumulator * sign; /* return the value */
return TRUE; /* good number */
}
/********************************************************************
* Function: mystrstr(haystack, needle, hlen, nlen, sensitive) *
* *
* Purpose: Determines if the string 'needle' is in the *
* string 'haystack' by returning it's position or *
* a NULL if not found. The length of haystack and *
* needle are given by 'hlen' and 'nlen' respectively. *
* *
* If 'sensitive' is true, then the search is case *
* sensitive, else it is case insensitive. *
* *
* RC: num - The pos where needle was found. *
* NULL - needle not found. *
* *
* Used By: SysFileSearch() *
*********************************************************************/
ULONG mystrstr(CHAR *haystack,CHAR *needle,ULONG hlen,ULONG nlen,
BOOL sensitive)
{
CHAR line[MAX];
CHAR target[MAX];
ULONG p;
/* Copy line - Change nulls to spaces and uppercase if needed */
for (p = 0; p < hlen; p++) {
if (haystack[p] == '\0')
line[p] = ' ';
else if (sensitive)
line[p] = haystack[p];
else line[p] = (CHAR)toupper(haystack[p]);
}
line[p] = '\0';
/* Copy target - Change nulls to spaces and uppercase if needed */
for (p = 0; p < nlen; p++) {
if (needle[p] == '\0')
target[p] = ' ';
else if (sensitive)
target[p] = needle[p];
else target[p] = (CHAR)toupper(needle[p]);
}
target[p] = '\0';
return ((ULONG)strstr(line, target));
}
/*****************************************************************
* Function: getpath(string, path, filename) *
* *
* Purpose: This function gets the PATH and FILENAME of the file *
* target contained in STRING. The path will end with *
* the '\' char if a path is supplied. *
* *
* Used By: RecursiveFindFile() *
**************************************************************** */
VOID getpath(CHAR *string,CHAR *path,CHAR *filename)
{
int len;
int LastSlashPos;
len = strlen(string); /* Get length of full file */
/* spec */
LastSlashPos = len; /* Get max pos of last '\' */
/* Step back through string until at begin or at '\' char */
while (string[LastSlashPos] != '\\' && LastSlashPos >= 0)
--LastSlashPos;
/* Copy filespec up to and including last '\' to path */
memcpy(path, string, LastSlashPos+1);
path[LastSlashPos+1] = '\0';
/* Get file name from filespec (just after last '\') */
strcpy(filename, &string[LastSlashPos+1]);
}
/*********************************************************************/
/* Function: ULONG SameAttr(mask, attr) */
/* */
/* Purpose: Returns the value TRUE if the attribute is identical to */
/* that specified by the mask. If not the same, then */
/* returns the value FALSE. */
/* */
/* Used By: RecursiveFindFile() */
/*********************************************************************/
ULONG SameAttr(INT *mask,ULONG attr)
{
if (mask[0] == IGNORE)
return TRUE;
if (mask[0] < 0 && attr&FILE_ARCHIVED)
return FALSE;
if (mask[0] > 0 && !(attr&FILE_ARCHIVED))
return FALSE;
if (mask[1] < 0 && attr&FILE_DIRECTORY)
return FALSE;
if (mask[1] > 0 && !(attr&FILE_DIRECTORY))
return FALSE;
if (mask[2] < 0 && attr&FILE_HIDDEN)
return FALSE;
if (mask[2] > 0 && !(attr&FILE_HIDDEN))
return FALSE;
if (mask[3] < 0 && attr&FILE_READONLY)
return FALSE;
if (mask[3] > 0 && !(attr&FILE_READONLY))
return FALSE;
if (mask[4] < 0 && attr&FILE_SYSTEM)
return FALSE;
if (mask[4] > 0 && !(attr&FILE_SYSTEM))
return FALSE;
return TRUE;
}
/*********************************************************************/
/* Function: ULONG NewAttr(mask, attr) */
/* */
/* Purpose: Returns the new file attribute, given the mask of */
/* attributes to be cleared/set and the current attribute */
/* settings. */
/* */
/* Used By: RecursiveFindFile() */
/*********************************************************************/
ULONG NewAttr(INT *mask,ULONG attr)
{
if (mask[0] == IGNORE)
return attr;
if (mask[0] < 0)
attr &= ~FILE_ARCHIVED; /* Clear */
if (mask[0] > 0)
attr |= FILE_ARCHIVED; /* Set */
if (mask[1] < 0)
attr &= ~FILE_DIRECTORY; /* Clear */
if (mask[1] > 0)
attr |= FILE_DIRECTORY; /* Set */
if (mask[2] < 0)
attr &= ~FILE_HIDDEN; /* Clear */
if (mask[2] > 0)
attr |= FILE_HIDDEN; /* Set */
if (mask[3] < 0)
attr &= ~FILE_READONLY; /* Clear */
if (mask[3] > 0)
attr |= FILE_READONLY; /* Set */
if (mask[4] < 0)
attr &= ~FILE_SYSTEM; /* Clear */
if (mask[4] > 0)
attr |= FILE_SYSTEM; /* Set */
return attr;
}
/*****************************************************************************
* Function: RecursiveFindFile( FileSpec, lpd, smask, dmask, options ) *
* *
* Purpose: Finds all files starting with FileSpec, and will look down the *
* directory tree if required. *
* *
* Params: FileSpec - ASCIIZ string which designates filespec to search *
* for. *
* *
* ldp - Pointer to local data structure. *
* *
* smask - Array of integers which describe the source attribute *
* mask. Only files with attributes matching this mask *
* will be found. *
* *
* dmask - Array of integers which describe the target attribute *
* mask. Attributes of all found files will be set *
* using this mask. *
* *
* Note: Both source and targets mask are really arrays of *
* integers. Each index of the mask corresponds *
* to a different file attribute. Each indexe and *
* its associated attribute follows: *
* *
* mask[0] = FILE_ARCHIVED *
* mask[1] = FILE_DIRECTORY *
* mask[2] = FILE_HIDDEN *
* mask[3] = FILE_READONLY *
* mask[4] = FILE_SYSTEM *
* *
* A negative value at a given index indicates that *
* the attribute bit of the file is not set. A positive *
* number indicates that the attribute should be set. *
* A value of 0 indicates a "Don't Care" setting. *
* *
* options - The search/output options. The following options *
* may be ORed together when calling this function: *
* *
* FIRST_TIME - Indicates this is initial call. This *
* should always be used. *
* RECURSE - Indicates that function should search *
* all child subdirectories recursively. *
* DO_DIRS - Indicates that directories should be *
* included in the search. *
* DO_FILES - Indicates that files should be included *
* in the search. *
* NAME_ONLY - Indicates that the output should be *
* restricted to filespecs only. *
* EDITABLE_TIME - Indicates time and date fields should *
* be output as one timestamp. *
* *
* Used By: SysFileTree() *
*****************************************************************************/
LONG RecursiveFindFile(FileSpec,ldp,smask,dmask,options)
CHAR *FileSpec; /* Filespecs to search for */
RXTREEDATA *ldp; /* Pointer to local data */
INT *smask; /* Mask of attributes to */
/* search for */
INT dmask; /* Mask of attributes to set */
ULONG options; /* Search and output format */
/* options */
{
FILEFINDBUF3 finfo; /* OS2 File Find Utility */
/* Structure */
ULONG SearchCount = 1; /* Num things searching for */
/* per DosFindFirst */
HDIR DirHandle = 0xFFFF; /* Directory handle used by */
/* DosFindFirst() */
CHAR path[MAX]; /* Path to target file(s) */
CHAR filename[MAX]; /* Current file name */
BOOL IsaDotdir = FALSE; /* Boolean for determining if */
/* file is ./.. */
BOOL IsaSubdir = FALSE; /* Boolean for determining if */
/* file is a dir */
/********************************************************************
* Search Strategy Explained: *
* *
* Get path and filespec to be searched. *
* *
* If this is the initial call (see FIRST_TIME) and *
* searching recursively, make sure to look for the *
* original filespec in the initial directory. *
* *
* From then on, look for a filespec of *.* to expand *
* the subdirectories. Once a subdirectory is expanded, *
* search for the initial filespec again. *
********************************************************************/
getpath(FileSpec, path, filename);
/********************************************************************
* Initial Recursive case: *
* *
* This section of code recurses to call itself in the *
* non-recursive form. It will allow the function to *
* gather all the files in the initial subdirectory. *
* *
* It also saves the initial filespec to be searched *
* for in all directories which will be expanded (see *
* ldp->TargetSpec). From then on, the recursive case *
* will search for directories by examining all files *
* matching the spec *.*. *
********************************************************************/
/* Onye executed first time */
if ((options&FIRST_TIME) && (options&RECURSE)) {
if (RecursiveFindFile(FileSpec, ldp, smask, dmask,
options&~RECURSE&~FIRST_TIME))
return INVALID_ROUTINE;
strcpy(ldp->TargetSpec, filename);
strcpy(filename, "*.*");
sprintf(FileSpec, "%s*.*", path);
options &= ~FIRST_TIME;
}
/********************************************************************
* Non-Recursive case: *
* *
* This section of code finds all files matching the *
* filespec (filtering out . and ..) and stores them *
* in stem elements if they meet the appropriate file *
* attribute requirements. Each found file's attributes *
* are set as required if needed. *
********************************************************************/
if (!(options&RECURSE)) {
if (!DosFindFirst((PSZ)FileSpec, (PHDIR)&DirHandle, (ULONG)
AllAtts, (PVOID)&finfo, (ULONG)sizeof(finfo), (PULONG)
&SearchCount, FIL_STANDARD)) {
IsaSubdir = (BOOL)(finfo.attrFile&FILE_DIRECTORY);
IsaDotdir = (BOOL)(!strcmp(finfo.achName, ".") ||
!strcmp(finfo.achName, ".."));
if (!IsaDotdir && SameAttr(smask, finfo.attrFile) &&
((IsaSubdir && (options&DO_DIRS)) ||
(!IsaSubdir && (options&DO_FILES)))) {
sprintf(ldp->tempfile, "%s%s", path, finfo.achName);
/* Get full path */
DosQueryPathInfo(ldp->tempfile, 5, ldp->truefile,
sizeof(ldp->truefile));
if (options&NAME_ONLY)
strcpy(ldp->Temp, ldp->truefile);
else {
if (options&EDITABLE_TIME)
sprintf(ldp->Temp, "%02d/%02d/%02d/%02d/%02d %10lu ",
(finfo.fdateLastWrite.year+80)%100,
finfo.fdateLastWrite.month,
finfo.fdateLastWrite.day,
finfo.ftimeLastWrite.hours,
finfo.ftimeLastWrite.minutes,
finfo.cbFile);
else
sprintf(ldp->Temp, "%2d/%02d/%02d %2d:%02d%c %10lu ",
finfo.fdateLastWrite.month,
finfo.fdateLastWrite.day,
(finfo.fdateLastWrite.year+80)%100,
(finfo.ftimeLastWrite.hours < 13?
finfo.ftimeLastWrite.hours:
(finfo.ftimeLastWrite.hours-(SHORT)12)),
finfo.ftimeLastWrite.minutes,
((finfo.ftimeLastWrite.hours < 12 ||
finfo.ftimeLastWrite.hours == 24)?'a':'p'),
finfo.cbFile);
ldp->nattrib = NewAttr((INT *)dmask, finfo.attrFile);
if (ldp->nattrib != finfo.attrFile) {
sprintf(ldp->tempfile, "%s%s", path, finfo.achName);
if (DosSetFileMode(ldp->tempfile, (USHORT)(ldp->nattrib&~
FILE_DIRECTORY), 0L)) /* Set the new file mode */
ldp->nattrib = finfo.attrFile;/* Just in case of */
/* failure */
}
sprintf(ldp->Temp, "%s%c%c%c%c%c %s", ldp->Temp,
((ldp->nattrib&FILE_ARCHIVED)?'A':'-'),
((ldp->nattrib&FILE_DIRECTORY)?'D':'-'),
((ldp->nattrib&FILE_HIDDEN)?'H':'-'),
((ldp->nattrib&FILE_READONLY)?'R':'-'),
((ldp->nattrib&FILE_SYSTEM)?'S':'-'),
ldp->truefile);
}
/* Place new string in Stem */
memcpy(ldp->ibuf, ldp->Temp, strlen(ldp->Temp));
ldp->vlen = strlen(ldp->Temp);
ldp->count++;
sprintf(ldp->varname+ldp->stemlen,"%d", ldp->count);
ldp->shvb.shvnext = NULL;
ldp->shvb.shvname.strptr = ldp->varname;
ldp->shvb.shvname.strlength = strlen(ldp->varname);
ldp->shvb.shvvalue.strptr = ldp->ibuf;
ldp->shvb.shvvalue.strlength = ldp->vlen;
ldp->shvb.shvnamelen = ldp->shvb.shvname.strlength;
ldp->shvb.shvvaluelen = ldp->vlen;
ldp->shvb.shvcode = RXSHV_SET;
ldp->shvb.shvret = 0;
if (RexxVariablePool(&ldp->shvb) == RXSHV_BADN)
return INVALID_ROUTINE; /* error on non-zero */
}
/* Get the rest of the files ................................*/
while (!DosFindNext((HDIR)DirHandle, (PVOID)&finfo,
(ULONG)sizeof(finfo), (PULONG)&SearchCount)) {
IsaSubdir = (BOOL)(finfo.attrFile&FILE_DIRECTORY);
IsaDotdir = (BOOL)(!strcmp(finfo.achName, ".") ||
!strcmp(finfo.achName, ".."));
if (!IsaDotdir && SameAttr(smask, finfo.attrFile) &&
((IsaSubdir && (options&DO_DIRS)) ||
(!IsaSubdir && (options&DO_FILES)))) {
sprintf(ldp->tempfile, "%s%s", path, finfo.achName);
/* Get full path */
DosQueryPathInfo(ldp->tempfile, 5, ldp->truefile,
sizeof(ldp->truefile));
if (options&NAME_ONLY)
strcpy(ldp->Temp, ldp->truefile);
else {
if (options&EDITABLE_TIME)
sprintf(ldp->Temp, "%02d/%02d/%02d/%02d/%02d %10lu ",
(finfo.fdateLastWrite.year+80)%100,
finfo.fdateLastWrite.month,
finfo.fdateLastWrite.day,
finfo.ftimeLastWrite.hours,
finfo.ftimeLastWrite.minutes, finfo.cbFile);
else
sprintf(ldp->Temp,
"%2d/%02d/%02d %2d:%02d%c %10lu ",
finfo.fdateLastWrite.month,
finfo.fdateLastWrite.day,
(finfo.fdateLastWrite.year+80)%100,
(finfo.ftimeLastWrite.hours < 13?
finfo.ftimeLastWrite.hours:
(finfo.ftimeLastWrite.hours - (SHORT)12)),
finfo.ftimeLastWrite.minutes,
((finfo.ftimeLastWrite.hours < 12 ||
finfo.ftimeLastWrite.hours == 24)?'a':'p'),
finfo.cbFile);
ldp->nattrib = NewAttr((INT *)dmask, finfo.attrFile);
if (ldp->nattrib != finfo.attrFile) {
sprintf(ldp->tempfile, "%s%s", path, finfo.achName);
if (DosSetFileMode(ldp->tempfile, (USHORT)(ldp->nattrib&~
FILE_DIRECTORY), 0L))/* Set the new file mode */
ldp->nattrib = finfo.attrFile;/* Just in case of */
/* failure */
}
sprintf(ldp->Temp, "%s%c%c%c%c%c %s", ldp->Temp,
((ldp->nattrib&FILE_ARCHIVED)?'A':'-'),
((ldp->nattrib&FILE_DIRECTORY)?'D':'-'),
((ldp->nattrib&FILE_HIDDEN)?'H':'-'),
((ldp->nattrib&FILE_READONLY)?'R':'-'),
((ldp->nattrib&FILE_SYSTEM)?'S':'-'),
ldp->truefile);
}
/* Place new string in Stem */
memcpy(ldp->ibuf, ldp->Temp, strlen(ldp->Temp));
ldp->vlen = strlen(ldp->Temp);
ldp->count++;
sprintf(ldp->varname+ldp->stemlen, "%d", ldp->count);
ldp->shvb.shvnext = NULL;
ldp->shvb.shvname.strptr = ldp->varname;
ldp->shvb.shvname.strlength = strlen(ldp->varname);
ldp->shvb.shvvalue.strptr = ldp->ibuf;
ldp->shvb.shvvalue.strlength = ldp->vlen;
ldp->shvb.shvnamelen = ldp->shvb.shvname.strlength;
ldp->shvb.shvvaluelen = ldp->vlen;
ldp->shvb.shvcode = RXSHV_SET;
ldp->shvb.shvret = 0;
if (RexxVariablePool(&ldp->shvb) == RXSHV_BADN)
return INVALID_ROUTINE; /* error on non-zero */
}
}
}
DosFindClose(DirHandle);
}
/********************************************************
* Recursive case: *
* *
* This section of code searches for directories given *
* the current FileSpec. When one is found, the *
* function is called in the non-recursive mode to find *
* all files matching the initial filespec. It is also *
* called in the recursive mode to expand all subdirect- *
* ories under the new found directory. *
*********************************************************/
else {
if (!DosFindFirst((PSZ)FileSpec, (PHDIR)&DirHandle,
(ULONG)AllAtts, (PVOID)&finfo, (ULONG)sizeof(finfo),
(PULONG)&SearchCount, FIL_STANDARD)) {
IsaSubdir = (BOOL)(finfo.attrFile&FILE_DIRECTORY);
IsaDotdir = (BOOL)(!strcmp(finfo.achName, ".") ||
!strcmp(finfo.achName, ".."));
if (!IsaDotdir && IsaSubdir) {
sprintf(ldp->tempfile, "%s%s\\%s", path, finfo.achName,
ldp->TargetSpec);
if (RecursiveFindFile(ldp->tempfile, ldp, smask, dmask,
options&~RECURSE))
return INVALID_ROUTINE;
sprintf(ldp->tempfile, "%s%s\\%s", path, finfo.achName,
filename);
if (RecursiveFindFile(ldp->tempfile, ldp, smask, dmask, options))
return INVALID_ROUTINE;
}
/* Get the rest of the files ................................*/
while (!DosFindNext((HDIR)DirHandle, (PVOID)&finfo,
(ULONG)sizeof(finfo), (PULONG)&SearchCount)) {
IsaSubdir = (BOOL)(finfo.attrFile&FILE_DIRECTORY);
IsaDotdir = (BOOL)(!strcmp(finfo.achName, ".") ||
!strcmp(finfo.achName, ".."));
if (!IsaDotdir && IsaSubdir) {
sprintf(ldp->tempfile, "%s%s\\%s", path, finfo.achName,
ldp->TargetSpec);
if (RecursiveFindFile(ldp->tempfile, ldp, smask, dmask,
options&~RECURSE))
return INVALID_ROUTINE;
sprintf(ldp->tempfile, "%s%s\\%s", path, finfo.achName,
filename);
if (RecursiveFindFile(ldp->tempfile, ldp, smask, dmask,
options))
return INVALID_ROUTINE;
}
}
}
DosFindClose(DirHandle);
}
return VALID_ROUTINE;
}
/****************************************************************
* Function: GetUniqueFileName(Template, Filler, file) *
* *
* Purpose: This function returns a unique temporary file name *
* given a template and a filler character. *
* *
* Params: CHAR* Template - The template. Must contain at *
* least one or more filler chars. *
* *
* Example: "C:\TEMP\FILE????.DAT *
* *
* CHAR Filler - The character in the Template to *
* be replaced with numbers. For *
* the above example, the filler char *
* would be '?'. *
* CHAR* file - file name produced (output) *
* *
* Used By: RxTempFileName() *
****************************************************************/
VOID GetUniqueFileName(CHAR *Template,CHAR Filler,CHAR *file)
{
CHAR numstr[6];
BOOL Unique = FALSE;
ULONG rc, /* return code for OS/2 call */
x, /* loop index */
i, /* */
j = 0, /* number of filler chars */
/* found */
num, /* temporary random number */
start, /* first random number */
max = 1; /* maximum random number */
ULONG SearchCount; /* count of files to search */
/* for. */
HDIR DirHandle; /* handle for found file */
INT seed; /* to get current time */
FILEFINDBUF3 finfo; /* OS2 File Find Utility */
/* Structure */
DATETIME DT; /* The date and time structure*/
/** Determine number of filler characters * */
for (x = 0; Template[x] != 0; x++)
if (Template[x] == Filler) {
max = max *10;
j++;
}
/** Return NULL string if less than 1 or greater than 4 * */
if (j == 0 || j > 5) {
Unique = TRUE;
strcpy(file, "");
}
/** Get a random number in the appropriate range */
DosGetDateTime((PDATETIME)&DT); /* Get the time */
seed = DT.hours*60 + DT.minutes; /* convert to hundreths */
seed = seed*60 + DT.seconds;
seed = seed*100 + DT.hundredths;
srand((INT)seed); /* Set random number seed */
num = (ULONG)rand()%max;
start = num;
/** Do until a unique name is found */
while (!Unique) {
/** Generate string which represents the number */
switch (j) {
case 1 :
sprintf(numstr, "%01u", num);
break;
case 2 :
sprintf(numstr, "%02u", num);
break;
case 3 :
sprintf(numstr, "%03u", num);
break;
case 4 :
sprintf(numstr, "%04u", num);
break;
case 5 :
sprintf(numstr, "%05u", num);
break;
}
/** Subsitute filler characters with numeric string */
i = 0;
for (x = 0; Template[x] != 0; x++)
if (Template[x] == Filler)
file[x] = numstr[i++];
else
file[x] = Template[x];
file[x] = '\0';
/** See if the file exists */
DosError(0); /* Disable Hard-Error popups */
DirHandle = 0xFFFF;
SearchCount = 1;
rc = DosFindFirst(file, &DirHandle, AllAtts, (PVOID)&finfo,
(ULONG)sizeof(finfo), (PULONG)&SearchCount, FIL_STANDARD);
if (rc == 2 || rc == 18)
Unique = TRUE;
DosFindClose(DirHandle);
DosError(1); /* Enable Hard-Error popups */
/** Make sure we are not wasting our time */
num = (num+1)%max;
if (num == start && !Unique) {
Unique = TRUE;
strcpy(file, "");
}
}
}
/*************************************************************************
*** <<<<<< REXXUTIL Functions Follow >>>>>>> ***
*** <<<<<< REXXUTIL Functions Follow >>>>>>> ***
*** <<<<<< REXXUTIL Functions Follow >>>>>>> ***
*** <<<<<< REXXUTIL Functions Follow >>>>>>> ***
*************************************************************************/
/*************************************************************************
* Function: SysCls *
* *
* Syntax: call SysCls *
* *
* Return: NO_UTIL_ERROR - Successful. *
*************************************************************************/
ULONG SysCls(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
BYTE bCell[2]; /* Char/Attribute array */
if (numargs) /* arguments specified? */
return INVALID_ROUTINE; /* raise the error */
bCell[0] = 0x20; /* Space Character */
bCell[1] = 0x07; /* Default Attrib */
VioScrollDn( 0, 0, (USHORT)0xFFFF, (USHORT)0XFFFF,
(USHORT)0xFFFF, bCell, (HVIO) 0);/* CLS */
VioSetCurPos(0, 0, (HVIO) 0); /* Pos cursor */
BUILDRXSTRING(retstr, NO_UTIL_ERROR);/* pass back result */
return VALID_ROUTINE; /* no error on call */
}
/*************************************************************************
* Function: SysCurPos - positions cursor in OS/2 session *
* *
* Syntax: call SysCurPos [row, col] *
* *
* Params: row - row to place cursor on *
* col - column to place cursor on *
* *
* Return: row, col *
*************************************************************************/
ULONG SysCurPos(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
USHORT start_row; /* Row at start */
USHORT start_col; /* Col at start */
LONG new_row; /* Row to change to */
LONG new_col; /* Col to change to */
BUILDRXSTRING(retstr, NO_UTIL_ERROR);/* set default result */
/* check arguments */
if ((numargs != 0 && numargs != 2)) /* wrong number? */
return INVALID_ROUTINE; /* raise an error */
VioGetCurPos(&start_row, &start_col, (HVIO) 0); /* get position */
sprintf(retstr->strptr, "%d %d", (int)start_row, (int)start_col);
retstr->strlength = strlen(retstr->strptr);
if (numargs != 0) { /* reset position to given */
if (!RXVALIDSTRING(args[0]) || /* not real arguments given? */
!RXVALIDSTRING(args[1]))
return INVALID_ROUTINE; /* raise an error */
/* convert row to binary */
if (!string2long(args[0].strptr, &new_row) || new_row < 0)
return INVALID_ROUTINE; /* return error */
/* convert row to binary */
if (!string2long(args[1].strptr, &new_col) || new_col < 0)
return INVALID_ROUTINE; /* return error */
/* Set the cursor position, using the input values. */
VioSetCurPos((USHORT) new_row, (USHORT) new_col, (HVIO) 0);
}
return VALID_ROUTINE; /* no error on call */
}
/*************************************************************************
* Function: SysCurState *
* *
* Syntax: call SysCurState state *
* *
* Params: state - Either 'ON' or 'OFF'. *
* *
* Return: NO_UTIL_ERROR - Successful. *
*************************************************************************/
ULONG SysCurState(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
USHORT state; /* State */
VIOCURSORINFO vioci; /* Cursor info struct */
BUILDRXSTRING(retstr, NO_UTIL_ERROR);/* pass back result */
/* validate the arguments */
if (numargs != 1)
return INVALID_ROUTINE;
/* Get state and validate */
if (stricmp(args[0].strptr, "ON") == 0)
state = (USHORT) 0;
else if (stricmp(args[0].strptr, "OFF") == 0)
state = (USHORT) -1;
else
return INVALID_ROUTINE; /* Invalid state */
VioGetCurType(&vioci, (HVIO) 0); /* Get current state */
vioci.attr= state; /* Set state info */
VioSetCurType(&vioci, (HVIO) 0); /* Set new state */
return VALID_ROUTINE; /* no error on call */
}
/*************************************************************************
* Function: SysDriveInfo *
* *
* Syntax: call SysDriveInfo drive *
* *
* Params: drive - 'C', 'D', 'E', etc. *
* *
* Return: disk free total label *
*************************************************************************/
ULONG SysDriveInfo(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
PSZ arg; /* Temp var for holding args */
UCHAR buf[256]; /* Give DosQFSInfo 256 bytes */
ULONG drivenum; /* Drive number (A=1, B=2, */
/* etc) */
FSALLOCATE FSInfoBuf; /* Structure required by */
/* DosQfsInfo */
LONG rc; /* OS/2 return code */
/* validate arguments */
if (numargs != 1 ||
args[0].strlength > 2 ||
args[0].strlength == 0)
return INVALID_ROUTINE;
/* validate the arg */
arg = args[0].strptr; /* get argument pointer */
/* drive letter? */
if ((strlen(arg) == 2 &&
arg[1] != ':') ||
!isalpha(arg[0]))
return INVALID_ROUTINE;
else /* yep, convert to a number */
drivenum = toupper(arg[0])-'A'+1; /* Get the drive number */
/* query the disk */
DosError(0); /* Disable hard-error pop-up */
/* Get the drive info */
rc = DosQueryFSInfo(drivenum, 2, buf, sizeof(buf));
DosQueryFSInfo(drivenum, 1, (char *)&FSInfoBuf, sizeof(FSInfoBuf));
if (rc == 0 || rc == 125) {
sprintf(retstr->strptr,
"%c: %-12lu %-12lu %-13s",
(drivenum+'A'-1),
FSInfoBuf.cSectorUnit * FSInfoBuf.cbSector *
FSInfoBuf.cUnitAvail,
FSInfoBuf.cSectorUnit * FSInfoBuf.cbSector *
FSInfoBuf.cUnit, &buf[5]);
/* create return string */
retstr->strlength = strlen(retstr->strptr);
}
else
retstr->strlength = 0; /* return null string */
DosError(1); /* Enable hard-error pop-up */
return VALID_ROUTINE; /* no error on call */
}
/*************************************************************************
* Function: SysDriveMap *
* *
* Syntax: call SysDriveMap [drive] [,mode] *
* *
* Params: drive - 'C', 'D', 'E', etc. The drive to start the search *
* with. *
* mode - Any of the following: 'FREE', 'USED', 'DETACHED', *
* 'LOCAL', 'REMOTE' *
* *
* Return: 'A: B: C: D: ...' *
*************************************************************************/
ULONG SysDriveMap(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
CHAR temp[MAX]; /* Entire drive map built here*/
CHAR tmpstr[MAX]; /* Single drive entries built */
/* here */
CHAR buf[256]; /* Give DosQFSInfo 256 bytes */
CHAR DeviceName[3]; /* Device name or drive letter*/
/* string */
ULONG CurDrive; /* Current drive */
ULONG DriveMap; /* Drive map */
ULONG Ordinal; /* Ordinal of entry in name */
/* list */
ULONG FSAInfoLevel; /* Type of attached FSD data */
/* required */
ULONG DataBufferLen; /* Buffer length */
ULONG dnum; /* Disk num variable */
ULONG start = 3; /* Initial disk num */
ULONG Mode = USED; /* Query mode USED, FREE, */
/* LOCAL, etc */
FSQBUFFER2 DataBuffer; /* Returned data buffer */
LONG rc; /* OS/2 return codes */
Ordinal = (ULONG )0;
FSAInfoLevel = (ULONG )1;
temp[0] = '\0';
if (numargs > 2) /* validate arguments */
return INVALID_ROUTINE;
/* check starting drive letter*/
if (numargs >= 1 && args[0].strptr) {
if ((strlen(args[0].strptr) == 2 &&
args[0].strptr[1] != ':') ||
strlen(args[0].strptr) > 2 ||
strlen(args[0].strptr) == 0 ||
!isalpha(args[0].strptr[0]))
return INVALID_ROUTINE;
start = toupper(args[0].strptr[0])-'A'+1;
}
/* check the mode */
if (numargs == 2 && args[1].strlength != 0) {
if (!stricmp(args[1].strptr, "FREE"))
Mode = FREE;
else if (!stricmp(args[1].strptr, "USED"))
Mode = USED;
else if (!stricmp(args[1].strptr, "DETACHED"))
Mode = DETACHED;
else if (!stricmp(args[1].strptr, "REMOTE"))
Mode = REMOTE;
else if (!stricmp(args[1].strptr, "LOCAL"))
Mode = LOCAL;
else
return INVALID_ROUTINE;
}
/* perform the query */
DosError(0); /* Disable Hard-Error Popups */
DosQueryCurrentDisk(&CurDrive, &DriveMap);
DriveMap>>=start-1; /* Shift to the first drive */
temp[0] = '\0'; /* Clear temporary buffer */
for (dnum = start; dnum <= 26; dnum++) {
/* Hey, we have a free drive */
if (!(DriveMap&(ULONG)1) && Mode == FREE) {
sprintf(tmpstr, "%c: ", dnum+'A'-1);
strcat(temp, tmpstr);
}
/* Hey, we have a used drive */
else if ((DriveMap&(ULONG)1) && Mode == USED) {
sprintf(tmpstr, "%c: ", dnum+'A'-1);
strcat(temp, tmpstr);
}
else if (DriveMap&(ULONG)1) { /* Check specific drive info */
sprintf(DeviceName, "%c:", dnum+'A'-1);
DataBufferLen = sizeof DataBuffer;
DosQueryFSAttach(DeviceName, Ordinal, FSAInfoLevel,
&DataBuffer, &DataBufferLen);
rc = DosQueryFSInfo(dnum, 2, buf, sizeof(buf));
if (rc == 67 && DataBuffer.iType == 4 && Mode == DETACHED) {
/* Hey, we have a detached */
/* drive */
sprintf(tmpstr, "%c: ", dnum+'A'-1);
strcat(temp, tmpstr);
}
else if (DataBuffer.iType == 4 && Mode == REMOTE) {
sprintf(tmpstr, "%c: ", dnum+'A'-1);
strcat(temp, tmpstr);
}
else if (DataBuffer.iType == 3 && Mode == LOCAL) {
sprintf(tmpstr, "%c: ", dnum+'A'-1);
strcat(temp, tmpstr);
}
}
DriveMap>>=1; /* Shift to the next drive */
}
BUILDRXSTRING(retstr, temp); /* pass back result */
if (retstr->strlength) /* if not a null string */
retstr->strlength--; /* Get rid of last space */
DosError(1); /* Enable Hard-Error Popups */
return VALID_ROUTINE; /* no error on call */
}
/*************************************************************************
* Function: SysDropFuncs *
* *
* Syntax: call SysDropFuncs *
* *
* Return: NO_UTIL_ERROR - Successful. *
*************************************************************************/
ULONG SysDropFuncs(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
INT entries; /* Num of entries */
INT j; /* Counter */
if (numargs != 0) /* no arguments for this */
return INVALID_ROUTINE; /* raise an error */
retstr->strlength = 0; /* return a null string result*/
entries = sizeof(RxFncTable)/sizeof(PSZ);
for (j = 0; j < entries; j++)
RexxDeregisterFunction(RxFncTable[j]);
return VALID_ROUTINE; /* no error on call */
}
/*************************************************************************
* Function: SysFileDelete *
* *
* Syntax: call SysFileDelete file *
* *
* Params: file - file to be deleted. *
* *
* Return: Return code from DosDelete() function. *
*************************************************************************/
ULONG SysFileDelete(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
ULONG rc; /* Ret code */
if (numargs != 1) /* we need one argument */
return INVALID_ROUTINE; /* raise an error */
rc = DosDelete(args[0].strptr); /* delete the file */
/* pass back return code */
sprintf(retstr->strptr, "%d", rc);
retstr->strlength = strlen(retstr->strptr);
return VALID_ROUTINE; /* finished */
}
/*************************************************************************
* Function: SysFileSearch *
* *
* Syntax: call SysFileSearch target, file, stem [, options] *
* *
* Params: target - String to search for. *
* file - Filespec to search. *
* stem - Stem variable name to place results in. *
* options - Any combo of the following: *
* 'C' - Case sensitive search (non-default). *
* 'N' - Preceed each found string in result stem *
* with it line number in file (non-default).*
* *
* Return: NO_UTIL_ERROR - Successful. *
* ERROR_NOMEM - Out of memory. *
*************************************************************************/
ULONG SysFileSearch(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
PSZ target; /* search string */
PSZ file; /* search file */
PSZ opts; /* option string */
CHAR line[MAX]; /* Line read from file */
ULONG ptr; /* Pointer to char str found */
ULONG num = 0; /* Line number */
ULONG len; /* Length of string */
ULONG len2; /* Length of string */
ULONG rc = 0; /* Return code of this func */
BOOL linenums = FALSE; /* Set TRUE for linenums in */
/* output */
BOOL sensitive = FALSE; /* Set TRUE for case-sens */
/* search */
FILE *fp; /* Pointer to file to search */
RXSTEMDATA ldp; /* stem data */
BUILDRXSTRING(retstr, NO_UTIL_ERROR);/* pass back result */
/* validate arguments */
if (numargs < 3 || numargs > 4 ||
!RXVALIDSTRING(args[0]) ||
!RXVALIDSTRING(args[1]) ||
!RXVALIDSTRING(args[2]))
return INVALID_ROUTINE; /* raise an error */
target = args[0].strptr; /* get target pointer */
file = args[1].strptr; /* get file name */
if (numargs == 4) { /* process options */
opts = args[3].strptr; /* point to the options */
if (strstr(opts, "N") || strstr(opts, "n"))
linenums = TRUE;
if (strstr(opts, "C") || strstr(opts, "c"))
sensitive = TRUE;
}
/* Initialize data area */
ldp.count = 0;
strcpy(ldp.varname, args[2].strptr);
ldp.stemlen = args[2].strlength;
strupr(ldp.varname); /* uppercase the name */
if (ldp.varname[ldp.stemlen-1] != '.')
ldp.varname[ldp.stemlen++] = '.';
fp = fopen(file, "r"); /* Open the file */
if (fp == NULL) { /* Open error? */
BUILDRXSTRING(retstr, ERROR_FILEOPEN);
return VALID_ROUTINE; /* finished */
}
/* do the search...found lines*/
/* are saved in stem vars */
while (fgets(line, MAX - 1, fp) != NULL) {
len = strlen(line);
num++;
ptr = mystrstr(line, target, len, args[0].strlength, sensitive);
if (ptr != '\0') {
if (linenums) {
sprintf(ldp.ibuf, "%d ", num);
len2 = strlen(ldp.ibuf);
memcpy(ldp.ibuf+len2, line, len);
ldp.vlen = len+len2;
}
else {
memcpy(ldp.ibuf, line, len);
ldp.vlen = len;
}
ldp.count++;
sprintf(ldp.varname+ldp.stemlen, "%d", ldp.count);
if (ldp.ibuf[ldp.vlen-1] == '\n')
ldp.vlen--;
ldp.shvb.shvnext = NULL;
ldp.shvb.shvname.strptr = ldp.varname;
ldp.shvb.shvname.strlength = strlen(ldp.varname);
ldp.shvb.shvnamelen = ldp.shvb.shvname.strlength;
ldp.shvb.shvvalue.strptr = ldp.ibuf;
ldp.shvb.shvvalue.strlength = ldp.vlen;
ldp.shvb.shvvaluelen = ldp.vlen;
ldp.shvb.shvcode = RXSHV_SET;
ldp.shvb.shvret = 0;
if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN)
return INVALID_ROUTINE; /* error on non-zero */
}
}
fclose(fp); /* Close that file */
/* set stem.0 to lines read */
sprintf(ldp.ibuf, "%d", ldp.count);
ldp.varname[ldp.stemlen] = '0';
ldp.varname[ldp.stemlen+1] = 0;
ldp.shvb.shvnext = NULL;
ldp.shvb.shvname.strptr = ldp.varname;
ldp.shvb.shvname.strlength = ldp.stemlen+1;
ldp.shvb.shvnamelen = ldp.stemlen+1;
ldp.shvb.shvvalue.strptr = ldp.ibuf;
ldp.shvb.shvvalue.strlength = strlen(ldp.ibuf);
ldp.shvb.shvvaluelen = ldp.shvb.shvvalue.strlength;
ldp.shvb.shvcode = RXSHV_SET;
ldp.shvb.shvret = 0;
if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN)
return INVALID_ROUTINE; /* error on non-zero */
return VALID_ROUTINE; /* no error on call */
}
/*************************************************************************
* Function: SysFileTree *
* *
* Syntax: call SysFileTree filespec, stem [, options] *
* *
* Params: filespec - Filespec to search for (may include * and ?). *
* stem - Name of stem var to store results in. *
* options - Any combo of the following: *
* 'B' - Search for files and directories. *
* 'D' - Search for directories only. *
* 'F' - Search for files only. *
* 'O' - Only output file names. *
* 'S' - Recursively scan subdirectories. *
* 'T' - Combine time & date fields into one. *
* *
* Return: NO_UTIL_ERROR - Successful. *
* ERROR_NOMEM - Out of memory. *
*************************************************************************/
ULONG SysFileTree(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
CHAR FileSpec[MAX]; /* File spec to look for */
CHAR Opts[64]; /* Search options */
ULONG options; /* Mask of options */
ULONG x; /* Temp counter */
ULONG y; /* Temp counter (II) */
INT smask[5]; /* Source attribute mask */
INT dmask[5]; /* Target attribute mask */
RXTREEDATA ldp; /* local data */
options = FIRST_TIME|DO_FILES|DO_DIRS;/* Clear if we should not */
/* display files */
smask[0] = IGNORE; /* No mask unless specified */
dmask[0] = IGNORE; /* No mask unless specified */
BUILDRXSTRING(retstr, NO_UTIL_ERROR);/* pass back result */
/* validate arguments */
if (numargs < 2 || numargs > 5 ||
!RXVALIDSTRING(args[0]) ||
!RXVALIDSTRING(args[1]) ||
args[0].strlength > 255)
return INVALID_ROUTINE; /* Invalid call to routine */
/* initialize data area */
ldp.count = 0;
strcpy(ldp.varname, args[1].strptr);
ldp.stemlen = args[1].strlength;
strupr(ldp.varname); /* uppercase the name */
if (ldp.varname[ldp.stemlen-1] != '.')
ldp.varname[ldp.stemlen++] = '.';
strcpy(FileSpec, args[0].strptr); /* get file spec */
/** If FileSpec ends in \ then append *.* * */
if (FileSpec[strlen(FileSpec)-1] == '\\')
strcat(FileSpec, "*.*");
if (numargs >= 3 && /* check third option */
!RXNULLSTRING(args[2])) {
if (!args[2].strlength) /* a zero length string isn't */
return INVALID_ROUTINE; /* valid */
strcpy(Opts, args[2].strptr);
strupr(Opts); /* Uppercase the string */
if (strchr(Opts, 'S') != NULL)
options |= RECURSE; /* Should we recurse */
if (strchr(Opts, 'O') != NULL)
options |= NAME_ONLY; /* Should include names only */
if (strchr(Opts, 'T') != NULL)
options |= EDITABLE_TIME; /* Should create editable */
/* timestamp */
if (strchr(Opts, 'F') != NULL) {
options &= ~DO_DIRS; /* Should not include dirs ! */
options |= DO_FILES; /* Should include files ! */
}
if (strchr(Opts, 'D') != NULL) {
options |= DO_DIRS; /* Should include dirs ! */
options &= ~DO_FILES; /* Should not include files ! */
}
if (strchr(Opts, 'B') != NULL) {
options |= DO_DIRS; /* Should include dirs ! */
options |= DO_FILES; /* Should include files ! */
}
}
if (numargs >= 4) { /* check fourth option */
strcpy(Opts, args[3].strptr);
smask[0] = smask[1] = smask[2] = smask[3] = smask[4] = 0;
x = min(5, strlen(Opts));
for (y = 0; y < x; y++) {
if (Opts[y] == '+')
smask[y] = 1;
if (Opts[y] == '-')
smask[y] = -1;
}
}
if (numargs == 5) { /* check fifth argument */
strcpy(Opts, args[4].strptr); /* point to string */
dmask[0] = dmask[1] = dmask[2] = dmask[3] = dmask[4] = 0;
x = min(5, strlen(Opts));
for (y = 0; y < x; y++) {
if (Opts[y] == '+')
dmask[y] = 1;
if (Opts[y] == '-')
dmask[y] = -1;
}
dmask[1] = 0; /* Ignore directory bit of */
/* destination mask */
}
/* recursively search */
if (RecursiveFindFile(FileSpec, &ldp, smask, dmask, options))
return INVALID_ROUTINE;
/* return lines read */
sprintf(ldp.ibuf, "%d", ldp.count);
ldp.varname[ldp.stemlen] = '0';
ldp.varname[ldp.stemlen+1] = 0;
ldp.shvb.shvnext = NULL;
ldp.shvb.shvname.strptr = ldp.varname;
ldp.shvb.shvname.strlength = ldp.stemlen+1;
ldp.shvb.shvnamelen = ldp.stemlen+1;
ldp.shvb.shvvalue.strptr = ldp.ibuf;
ldp.shvb.shvvalue.strlength = strlen(ldp.ibuf);
ldp.shvb.shvvaluelen = ldp.shvb.shvvalue.strlength;
ldp.shvb.shvcode = RXSHV_SET;
ldp.shvb.shvret = 0;
if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN)
return INVALID_ROUTINE; /* error on non-zero */
return VALID_ROUTINE; /* no error on call */
}
/*************************************************************************
* Function: SysGetMessage *
* *
* Syntax: call SysGetMessage [file], msgnum [,str1] ... [,str9] *
* *
* Params: file - Name of message file to get message from. *
* Default is OSO001.MSG. *
* msgnum - Number of message being queried. *
* str1 ... str9 - Insertion strings. For messages which *
* contain %1, %2, etc, the str1, str2, etc *
* strings will be inserted (if given). *
* *
* Return: The message with the inserted strings (if given). *
*************************************************************************/
ULONG SysGetMessage(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
PCHAR ivtable[9]; /* Array of pointers to */
/* variables */
CHAR dataarea[500]; /* Buffer address to return */
/* message */
ULONG msglen; /* Length of the returned */
/* message */
ULONG datalen = 500; /* Length of the input buffer */
ULONG file_handle = 1; /* Output device handle for */
/* the screen */
ULONG ivcount = 3; /* Number of variables to */
/* insert = 0 */
LONG msgnum; /* Message number to get */
LONG x; /* Loop counter */
PSZ msgfile; /* Message file */
if (numargs < 1 || numargs > 11 || /* validate arguments */
!RXVALIDSTRING(args[0]))
return INVALID_ROUTINE; /* exit with error */
/* get message number */
if (!string2long(args[0].strptr, &msgnum) || msgnum < 0)
return INVALID_ROUTINE; /* exit with error */
/* Get message file name. */
/* Use "OSO001.MSG if not */
/* given */
if (numargs >= 2 && RXVALIDSTRING(args[1]))
msgfile = args[1].strptr; /* use provided message file */
else
msgfile = "OSO001.MSG";
/* copy insertion string */
/* pointers */
for (x = 2; x < numargs; x++) {
if (RXNULLSTRING(args[x])) /* must be valid string */
return INVALID_ROUTINE; /* leave now if bad */
ivtable[x-2] = args[x].strptr;
}
/* set number of insertions */
if (numargs >= 2)
ivcount = numargs-2;
else
ivcount = 0;
/* get the message */
DosGetMessage(ivtable, ivcount, dataarea, datalen, msgnum, msgfile,
&msglen);
/* save the message */
if (msglen > retstr->strlength)
if (DosAllocMem((PPVOID)&retstr->strptr, msglen, AllocFlag)) {
BUILDRXSTRING(retstr, ERROR_NOMEM);
return VALID_ROUTINE;
}
memcpy(retstr->strptr, dataarea, msglen);
retstr->strlength = msglen;
return VALID_ROUTINE; /* no error on call */
}
/*************************************************************************
* Function: SysIni *
* *
* Syntax: call SysIni [inifile], app [,key/stem] [,val/stem] *
* *
* Params: inifile - INI file from which to query or write info. The *
* default is the current user INI file. *
* app - Application title to work with. May be either *
* of the following: *
* 'ALL:' - All app titles will be returned in the *
* stem variable specified by the next *
* parameter. *
* other - Specific app to work with. *
* key - Key to work with. May be any of the following: *
* 'ALL:' - All key titles will be returned in *
* the stem variable specified by the *
* next parameter. *
* 'DELETE:' - All keys associated with the app *
* will be deleted. *
* other - Specific key to work with. *
* val - Key to work with. May be either of the following: *
* 'DELETE:' - Delete app/key pair. *
* other - Set app/key pair info to data spec- *
* ified. *
* stem - Name of stem variable in which to store results. *
* Stem.0 = Number found (n). *
* Stem.1 - Stem.n = Entries found. *
* *
* Return: other - Info queried from specific app/key pair. *
* '' - Info queried and placed in stem or data *
* deleted successfully. *
* ERROR_NOMEM - Out of memory. *
* ERROR_RETSTR - Error opening INI or querying/writing info.*
*************************************************************************/
ULONG SysIni(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
HAB hab; /* Anchor block */
HINI hini; /* Ini file handle */
ULONG x; /* Temp counter */
ULONG len; /* Len var used when creating */
/* stem */
ULONG lSize; /* Size of queried info buffer*/
/* area */
PSZ IniFile; /* Ini file (USER, SYSTEM, */
/* BOTH, file) */
PSZ App; /* Application field */
PSZ Key; /* Key field */
CHAR *Val; /* Ptr to data associated w/ */
/* App->Key */
CHAR Temp[256]; /* Temp string var */
CHAR UserName[256]; /* Filename of User INI */
/* profile */
CHAR SysName[256]; /* Filename of System INI */
/* profile */
PRFPROFILE PrfInfo; /* Profile name structure */
LONG Error = FALSE; /* Set to true if error */
/* encountered */
BOOL WildCard = FALSE; /* Set to true if a wildcard */
/* operation */
BOOL QueryApps; /* Set to true if a query */
/* operation */
BOOL terminate = TRUE; /* perform WinTerminate call */
RXSTEMDATA ldp; /* local data */
IniFile = "";
Key = "";
/* validate arguments */
if (numargs < 2 ||
numargs > 4 ||
!RXVALIDSTRING(args[1]))
return INVALID_ROUTINE;
/* get pointers to args */
IniFile = args[0].strptr;
App = args[1].strptr;
if (numargs >= 3 && args[2].strptr)
Key = args[2].strptr;
if (numargs == 4)
Val = args[3].strptr;
/* Check KEY and APP values */
/* for "WildCard" */
if (!stricmp(App, "ALL:")) {
App = "";
QueryApps = TRUE;
WildCard = TRUE;
if (numargs != 3)
return INVALID_ROUTINE; /* Error - Not enough args */
else
x = 2; /* Arg number of STEM variable*/
}
else if (!stricmp(Key, "ALL:")) {
Key = "";
Val = "";
QueryApps = FALSE;
WildCard = TRUE;
if (numargs != 4)
return INVALID_ROUTINE; /* Error - Not enough args */
else
x = 3; /* Arg number of STEM variable*/
}
/* If this is a "WildCard */
/* search, then allocate mem */
/* for stem struct and get the*/
/* stem name */
if (WildCard == TRUE) {
ldp.count = 0; /* get the stem variable name */
strcpy(ldp.varname, args[x].strptr);
ldp.stemlen = args[x].strlength;
strupr(ldp.varname); /* uppercase the name */
if (ldp.varname[ldp.stemlen-1] != '.')
ldp.varname[ldp.stemlen++] = '.';
}
hab = WinInitialize((USHORT)0); /* create anchor block */
if (!hab) { /* already done? */
/* get desktop anchor */
hab = WinQueryAnchorBlock(HWND_DESKTOP);
terminate = FALSE; /* don't terminate */
}
/**************************************************************
* The following section of code gets the INI file handle *
* given the INI file spec (IniFile). *
* *
* Possible Ini file specs: *
* *
* NULL - Same as USERPROFILE ( OS2.INI ) *
* "BOTH" - Same as PROFILE ( OS2.INI & OS2SYS.INI ) *
* "USER" - Same as USERPROFILE ( OS2.INI ) *
* "SYSTEM" - Same as SYSTEMPROFILE ( OS2SYS.INI) *
* other - Filespec of INI file. *
**************************************************************/
hini = NULLHANDLE;
if (!IniFile)
hini = HINI_USERPROFILE;
else if (!stricmp(IniFile, "BOTH"))
hini = HINI_PROFILE;
else if (!stricmp(IniFile, "USER"))
hini = HINI_USERPROFILE;
else if (!stricmp(IniFile, "SYSTEM"))
hini = HINI_SYSTEMPROFILE;
/***********************************************************
* If Ini file spec is 'other' then make sure it does not *
* specify the current USER or SYSTEM profiles. *
* *
* Trying to open the current USER or SYSTEM ini file via *
* PrfOpenProfile() will fail. Therefore, use the function *
* PrfQueryProfile() to query the current USER and SYSTEM *
* ini file specs. If the IniFile string matches either *
* the current USER or SYSTEM file specs, then use either *
* HINI_USERPROFILE or HINI_SYSTEMPROFILE as appropriate. *
* *
* If IniFile does not specify the current USER or SYSTEM *
* ini file then use PrfOpenProfile() to get the ini file *
* handle. *
***********************************************************/
else {
PrfInfo.pszUserName = UserName;
PrfInfo.cchUserName = sizeof(UserName);
PrfInfo.pszSysName = SysName;
PrfInfo.cchSysName = sizeof(SysName);
if (PrfQueryProfile(hab, &PrfInfo)) {
if (!stricmp(IniFile, PrfInfo.pszUserName))
hini = HINI_USERPROFILE;
else if (!stricmp(IniFile, PrfInfo.pszSysName))
hini = HINI_SYSTEMPROFILE;
else
hini = PrfOpenProfile(hab, IniFile);
}
else
hini = PrfOpenProfile(hab, IniFile);
/**************************************************
* Exit with INI FILE error if the ini file handle *
* is NULL at this point (and if IniFile != BOTH, *
* as that would make the handle NULL also). *
**************************************************/
if (hini == NULLHANDLE && stricmp(IniFile, "BOTH")) {
BUILDRXSTRING(retstr, ERROR_RETSTR);
if (terminate)
WinTerminate(hab);
return VALID_ROUTINE;
}
}
/* get value if is a query */
if ((numargs == 3 && stricmp(Key, "DELETE:")) ||
WildCard == TRUE) {
lSize = 0x0000ffffL;
/* Allocate a large buffer */
if (DosAllocMem((PPVOID)&Val, lSize, AllocFlag)) {
PrfCloseProfile(hini); /* close the INI file */
if (terminate)
WinTerminate(hab);
BUILDRXSTRING(retstr, ERROR_NOMEM);
return VALID_ROUTINE;
}
if (WildCard && QueryApps)
Error = !PrfQueryProfileData(hini, NULL, NULL, Val, &lSize);
else if (WildCard && !QueryApps)
Error = !PrfQueryProfileData(hini, App, NULL, Val, &lSize);
else
Error = !PrfQueryProfileData(hini, App, Key, Val, &lSize);
if (Error) {
BUILDRXSTRING(retstr, ERROR_RETSTR);
}
else if (WildCard == FALSE) {
if (lSize > retstr->strlength)
if (DosAllocMem((PPVOID)&retstr->strptr, lSize, AllocFlag)) {
DosFreeMem(Val); /* release buffer */
PrfCloseProfile(hini); /* close the INI file */
if (terminate)
WinTerminate(hab);
BUILDRXSTRING(retstr, ERROR_NOMEM);
return VALID_ROUTINE;
}
memcpy(retstr->strptr, Val, lSize);
retstr->strlength = lSize;
DosFreeMem(Val); /* release buffer */
}
}
else {
/* set the var to new value */
if (!stricmp(Key, "DELETE:") ||
!RXVALIDSTRING(args[2]))
Error = !PrfWriteProfileData(hini, App, NULL, NULL, 0L);
else if (!stricmp(Val, "DELETE:") ||
!RXVALIDSTRING(args[3]))
Error = !PrfWriteProfileData(hini, App, Key, NULL, 0L);
else {
lSize = args[3].strlength;
Error = !PrfWriteProfileData(hini, App, Key, Val, lSize);
}
if (Error) {
BUILDRXSTRING(retstr, ERROR_RETSTR);
}
}
PrfCloseProfile(hini); /* close the INI file */
if (terminate)
WinTerminate(hab); /* destroy anchor block */
/******************************************
* If this was a wildcard search, change *
* the Val variable from one long string *
* of values to a REXX stem variable. *
******************************************/
if (WildCard == TRUE) { /* fill stem variable */
if (Error == FALSE) {
x = 0;
ldp.count = 0;
do {
/* Copy string terminated by \0 to Temp. Last string will end */
/* in \0\0 and thus have a length of 0. */
len = 0;
while (Val[x+len] != '\0')
Temp[len++] = Val[x+len];
Temp[len] = '\0';
/* if non-zero length, then */
/* set the stem element */
if (len != 0) {
x += (len+1); /* Increment pointer past the */
/* new string */
memcpy(ldp.ibuf, Temp, len);
ldp.vlen = len;
ldp.count++;
sprintf(ldp.varname+ldp.stemlen, "%d", ldp.count);
if (ldp.ibuf[ldp.vlen-1] == '\n')
ldp.vlen--;
ldp.shvb.shvnext = NULL;
ldp.shvb.shvname.strptr = ldp.varname;
ldp.shvb.shvname.strlength = strlen(ldp.varname);
ldp.shvb.shvvalue.strptr = ldp.ibuf;
ldp.shvb.shvvalue.strlength = ldp.vlen;
ldp.shvb.shvnamelen = ldp.shvb.shvname.strlength;
ldp.shvb.shvvaluelen = ldp.vlen;
ldp.shvb.shvcode = RXSHV_SET;
ldp.shvb.shvret = 0;
if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN)
return INVALID_ROUTINE; /* error on non-zero */
}
}
while (Val[x] != '\0');
}
else
ldp.count = 0;
/* set number returned */
sprintf(ldp.ibuf, "%d", ldp.count);
ldp.varname[ldp.stemlen] = '0';
ldp.varname[ldp.stemlen+1] = 0;
ldp.shvb.shvnext = NULL;
ldp.shvb.shvname.strptr = ldp.varname;
ldp.shvb.shvname.strlength = ldp.stemlen+1;
ldp.shvb.shvnamelen = ldp.stemlen+1;
ldp.shvb.shvvalue.strptr = ldp.ibuf;
ldp.shvb.shvvalue.strlength = strlen(ldp.ibuf);
ldp.shvb.shvvaluelen = ldp.shvb.shvvalue.strlength;
ldp.shvb.shvcode = RXSHV_SET;
ldp.shvb.shvret = 0;
if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN)
return INVALID_ROUTINE; /* error on non-zero */
} /* * End - IF (Wildcard ... * */
return VALID_ROUTINE; /* no error on call */
}
/*************************************************************************
* Function: SysLoadFuncs *
* *
* Syntax: call SysLoadFuncs [option] *
* *
* Params: none *
* *
* Return: null string *
*************************************************************************/
ULONG SysLoadFuncs(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
INT entries; /* Num of entries */
INT j; /* Counter */
retstr->strlength = 0; /* set return value */
/* check arguments */
if (numargs > 0)
return INVALID_ROUTINE;
entries = sizeof(RxFncTable)/sizeof(PSZ);
for (j = 0; j < entries; j++) {
RexxRegisterFunctionDll(RxFncTable[j],
"REXXUTIL", RxFncTable[j]);
}
return VALID_ROUTINE;
}
/*************************************************************************
* Function: SysMkDir *
* *
* Syntax: call SysMkDir dir *
* *
* Params: dir - Directory to be created. *
* *
* Return: NO_UTIL_ERROR *
* Return code from DosMkDir() *
*************************************************************************/
ULONG SysMkDir(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
ULONG rc; /* Ret code of func */
if (numargs != 1)
/* If no args, then its an */
/* incorrect call */
return INVALID_ROUTINE;
rc = DosMkDir(args[0].strptr, 0L); /* make the directory */
sprintf(retstr->strptr, "%d", rc); /* result is return code */
retstr->strlength = strlen(retstr->strptr);
return VALID_ROUTINE;
}
/*************************************************************************
* Function: SysOS2Ver *
* *
* Syntax: call SysOS2Ver *
* *
* Return: OS/2 Version in for 1.1, 1.2, 1.3, 2.0. *
*************************************************************************/
ULONG SysOS2Ver(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
ULONG rc = 0; /* Return code of this func */
ULONG Versions[2]; /* Major version number */
if (numargs != 0) /* validate arg count */
return INVALID_ROUTINE;
DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_MINOR, Versions,
sizeof(Versions));
sprintf(retstr->strptr, "%lu.%02lu", Versions[0]/10, Versions[1]);
retstr->strlength = strlen(retstr->strptr);
return VALID_ROUTINE;
}
/*************************************************************************
* Function: SysRmDir *
* *
* Syntax: call SysRmDir dir *
* *
* Params: dir - Directory to be removed. *
* *
* Return: NO_UTIL_ERROR *
* Return code from DosRmDir() *
*************************************************************************/
ULONG SysRmDir(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
ULONG rc; /* Ret code of func */
if (numargs != 1)
/* If no args, then its an */
/* incorrect call */
return INVALID_ROUTINE;
/* remove the directory */
rc = DosRmDir(args[0].strptr);
sprintf(retstr->strptr, "%d", rc);
retstr->strlength = strlen(retstr->strptr);
return VALID_ROUTINE;
}
/*************************************************************************
* Function: SysSearchPath *
* *
* Syntax: call SysSearchPath path, file *
* *
* Params: path - Environment variable name which specifies a path *
* to be searched (ie 'PATH', 'DPATH', etc). *
* file - The file to search for. *
* *
* Return: other - Full path and filespec of found file. *
* '' - Specified file not found along path. *
*************************************************************************/
ULONG SysSearchPath(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
UCHAR buf[MAX]; /* returned file name */
/* validate arguments */
if (numargs != 2 ||
!RXVALIDSTRING(args[0]) ||
!RXVALIDSTRING(args[1]))
return INVALID_ROUTINE;
/* use DosSearchPath */
DosSearchPath(7, args[0].strptr, args[1].strptr,
buf, sizeof(buf));
BUILDRXSTRING(retstr, buf); /* pass back result */
return VALID_ROUTINE;
}
/*************************************************************************
* Function: SysSleep *
* *
* Syntax: call SysSleep secs *
* *
* Params: secs - Number of seconds to sleep. *
* *
* Return: NO_UTIL_ERROR *
*************************************************************************/
ULONG SysSleep(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
LONG secs; /* Time to sleep in secs */
if (numargs != 1) /* Must have one argument */
return INVALID_ROUTINE;
/* get number of seconds */
if (!string2long(args[0].strptr, &secs) || secs < 0)
return INVALID_ROUTINE; /* raise error if bad */
DosSleep(secs *1000);
BUILDRXSTRING(retstr, NO_UTIL_ERROR);
return VALID_ROUTINE;
}
/*************************************************************************
* Function: SysTempFileName *
* *
* Syntax: call SysTempFileName template [,filler] *
* *
* Params: template - Description of filespec desired. For example: *
* C:\TEMP\FILE.??? *
* filler - A character which when found in template will be *
* replaced with random digits until a unique file *
* or directory is found. The default character *
* is '?'. *
* *
* Return: other - Unique file/directory name. *
* '' - No more files exist given specified template. *
*************************************************************************/
ULONG SysTempFileName(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
CHAR filler; /* filler character */
if (numargs < 1 || /* validate arguments */
numargs > 2 ||
!RXVALIDSTRING(args[0]) ||
args[0].strlength > 512)
return INVALID_ROUTINE;
if (numargs == 2 && /* get filler character */
!RXNULLSTRING(args[1])) {
if (args[1].strlength != 1) /* must be one character */
return INVALID_ROUTINE;
filler = args[1].strptr[0];
}
else
filler = '?';
/* get the file id */
GetUniqueFileName(args[0].strptr, filler, retstr->strptr);
retstr->strlength = strlen(retstr->strptr);
return VALID_ROUTINE;
}
/*************************************************************************
* Function: SysTextScreenRead *
* *
* Syntax: call SysTextScreenRead row, col [,len] *
* *
* Params: row - Horizontal row on the screen to start reading from. *
* The row at the top of the screen is 0. *
* col - Vertical column on the screen to start reading from. *
* The column at the left of the screen is 0. *
* len - The number of characters to read. The default is the *
* rest of the screen. *
* *
* Return: Characters read from text screen. *
*************************************************************************/
ULONG SysTextScreenRead(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
LONG row; /* Row from which to start */
/* read */
LONG col; /* Column from which to start */
/* read */
LONG len = 8160; /* Max length of string, */
/* default is 8160 (80x102) */
CHAR temp[8160]; /* Array of CHARs, aka PCH */
if (numargs < 2 || /* validate arguments */
numargs > 3 ||
!RXVALIDSTRING(args[0]) ||
!RXVALIDSTRING(args[1]) ||
!string2long(args[0].strptr, &row) || row < 0 ||
!string2long(args[1].strptr, &col) || col < 0)
return INVALID_ROUTINE;
if (numargs == 3) { /* check the length */
if (!RXVALIDSTRING(args[2]) || /* bad string? */
!string2long(args[2].strptr, &len) || len < 0)
return INVALID_ROUTINE; /* error */
}
/* read the screen */
VioReadCharStr( temp, (PUSHORT)&len, row, col, (HVIO) 0);
if (len > retstr->strlength) /* default too short? */
/* allocate a new one */
if (DosAllocMem((PPVOID)&retstr->strptr, len, AllocFlag)) {
BUILDRXSTRING(retstr, ERROR_NOMEM);
return VALID_ROUTINE;
}
memcpy(retstr->strptr, temp, len);
retstr->strlength = len;
return VALID_ROUTINE;
}
/*************************************************************************
* Function: SysTextScreenSize *
* *
* Syntax: call SysTextScreenSize *
* *
* Return: Size of screen in row and columns returned as: row, col *
*************************************************************************/
ULONG SysTextScreenSize(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
VIOMODEINFO ModeData; /* screen info structure */
if (numargs != 0) /* no arguments on this func. */
return INVALID_ROUTINE;
ModeData.cb = sizeof(ModeData); /* find out screen size */
VioGetMode(&ModeData, (HVIO) 0);
sprintf(retstr->strptr, "%d %d",(int)ModeData.row,(int)ModeData.col);
retstr->strlength = strlen(retstr->strptr);
return VALID_ROUTINE;
}
/*************************************************************************
* Function: SysGetEA *
* *
* Syntax: call SysGetEA file, EA_name, variable *
* *
* Params: file - file containing EA. *
* EA_name - name of EA to be retrieved *
* name of variable EA is placed in *
* *
* Return: Return code from DosQueryFileInfo. *
*************************************************************************/
ULONG SysGetEA(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
LONG rc; /* Ret code */
UCHAR geabuff[300]; /* buffer for GEA */
PVOID fealist; /* fealist buffer */
EAOP2 eaop; /* eaop structure */
PGEA2 pgea; /* pgea structure */
PFEA2 pfea; /* pfea structure */
HFILE handle; /* file handle */
ULONG act; /* open action */
RXSTEMDATA ldp; /* stem data */
if (numargs != 3 || /* wrong number of arguments? */
!RXVALIDSTRING(args[0]) ||
!RXVALIDSTRING(args[1]) ||
!RXVALIDSTRING(args[2]))
return INVALID_ROUTINE; /* raise error condition */
ldp.count = 0; /* get the stem variable name */
strcpy(ldp.varname, args[2].strptr);
ldp.stemlen = args[2].strlength;
strupr(ldp.varname); /* uppercase the name */
if (rc = DosOpen(args[0].strptr, &handle, &act,
0L, 0, OPEN_ACTION_OPEN_IF_EXISTS,
OPEN_ACCESS_READONLY + OPEN_SHARE_DENYREADWRITE +
OPEN_FLAGS_FAIL_ON_ERROR + OPEN_FLAGS_WRITE_THROUGH,NULL)) {
sprintf(retstr->strptr, "%d", rc);
retstr->strlength = strlen(retstr->strptr);
return VALID_ROUTINE;
} /* get the file status info */
if (DosAllocMem((PPVOID)&fealist, 0x00010000L, AllocFlag)) {
BUILDRXSTRING(retstr, ERROR_NOMEM);
return VALID_ROUTINE;
}
/* FEA and GEA lists */
eaop.fpGEA2List = (PGEA2LIST)geabuff;
eaop.fpFEA2List = (PFEA2LIST)fealist;
eaop.oError = 0; /* no error occurred yet */
pgea = &eaop.fpGEA2List->list[0]; /* point to first GEA */
eaop.fpGEA2List->cbList = sizeof(ULONG) + sizeof(GEA2) +
args[1].strlength;
eaop.fpFEA2List->cbList = (ULONG)0xffff;
/* fill in the EA name length */
pgea->cbName = (BYTE)args[1].strlength;
strcpy(pgea->szName, args[1].strptr);/* fill in the name */
pgea->oNextEntryOffset = 0; /* fill in the next offset */
/* read the extended attribute*/
rc = DosQueryFileInfo(handle, 3, (PSZ)&eaop, sizeof(EAOP2));
DosClose(handle); /* close the file */
if (eaop.fpFEA2List->cbList <= sizeof(ULONG))
rc = ERROR_EAS_NOT_SUPPORTED; /* this is error also */
sprintf(retstr->strptr, "%d", rc); /* format return code */
retstr->strlength = strlen(retstr->strptr);
if (rc) { /* failure? */
DosFreeMem(fealist); /* error, get out */
return VALID_ROUTINE;
}
pfea = &(eaop.fpFEA2List->list[0]); /* point to the first FEA */
ldp.shvb.shvnext = NULL;
ldp.shvb.shvname.strptr = ldp.varname;
ldp.shvb.shvname.strlength = ldp.stemlen;
ldp.shvb.shvnamelen = ldp.stemlen;
ldp.shvb.shvvalue.strptr = ((PSZ)pfea->szName+(pfea->cbName+1));
ldp.shvb.shvvalue.strlength = pfea->cbValue;
ldp.shvb.shvvaluelen = ldp.shvb.shvvalue.strlength;
ldp.shvb.shvcode = RXSHV_SET;
ldp.shvb.shvret = 0;
if (RexxVariablePool(&ldp.shvb) == RXSHV_BADN) {
DosFreeMem(fealist); /* free our buffer */
return INVALID_ROUTINE; /* error on non-zero */
}
DosFreeMem(fealist); /* free our buffer */
return VALID_ROUTINE;
}
/*************************************************************************
* Function: SysPutEA *
* *
* Syntax: call SysPutEA file, EA_name, value *
* *
* Params: file - file containing EA. *
* EA_name - name of EA to be written *
* new value for the EA *
* *
* Return: Return code from DosQueryFileInfo. *
*************************************************************************/
ULONG SysPutEA(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
LONG rc; /* Ret code */
PVOID fealist; /* fealist buffer */
EAOP2 eaop; /* eaop structure */
PFEA2 pfea; /* pfea structure */
HFILE handle; /* file handle */
ULONG act; /* open action */
if (numargs != 3 || /* wrong number of arguments? */
!RXVALIDSTRING(args[0]) ||
!RXVALIDSTRING(args[1]))
return INVALID_ROUTINE; /* raise error condition */
if (rc = DosOpen2(args[0].strptr, &handle, &act,
0L, 0, OPEN_ACTION_OPEN_IF_EXISTS,
OPEN_ACCESS_READWRITE + OPEN_SHARE_DENYWRITE +
OPEN_FLAGS_FAIL_ON_ERROR + OPEN_FLAGS_WRITE_THROUGH, NULL)) {
sprintf(retstr->strptr, "%d", rc);
retstr->strlength = strlen(retstr->strptr);
return VALID_ROUTINE;
}
if (DosAllocMem((PPVOID)&fealist, 0x00010000L, AllocFlag)) {
BUILDRXSTRING(retstr, ERROR_NOMEM);
return VALID_ROUTINE;
}
eaop.fpFEA2List = (PFEA2LIST)fealist;/* Set memory for the FEA */
eaop.fpGEA2List = NULL; /* GEA is unused */
pfea = &eaop.fpFEA2List->list[0]; /* point to first FEA */
pfea->fEA = '\0'; /* set the flags */
/* Size of FEA name field */
pfea->cbName = (BYTE)args[1].strlength;
/* Size of Value for this one */
pfea->cbValue = (SHORT)args[2].strlength;
/* Set the name of this FEA */
strcpy((PSZ)pfea->szName, args[1].strptr);
/* Set the EA value */
memcpy((PSZ)pfea->szName+(pfea->cbName+1), args[2].strptr,
args[2].strlength);
pfea->oNextEntryOffset = 0; /* no next entry */
eaop.fpFEA2List->cbList = /* Set the total size var */
sizeof(ULONG) + sizeof(FEA2) + pfea->cbName + pfea->cbValue;
/* set the file info */
rc = DosSetFileInfo(handle, 2, (PSZ)&eaop, sizeof(EAOP2));
DosClose(handle); /* Close the File */
DosFreeMem(fealist); /* Free the memory */
sprintf(retstr->strptr, "%d", rc); /* format return code */
retstr->strlength = strlen(retstr->strptr);
return VALID_ROUTINE;
}
/*************************************************************************
* Function: SysWaitNamedPipe *
* *
* Syntax: result = SysWaitNamedPipe(name, timeout) *
* *
* Params: name - name of the pipe *
* timeout - amount of time to wait. *
* *
* Return: Return code from DosWaitNPipe *
*************************************************************************/
ULONG SysWaitNamedPipe(CHAR *name, ULONG numargs, RXSTRING args[],
CHAR *queuename, RXSTRING *retstr)
{
LONG rc; /* Ret code */
LONG timeout; /* timeout value */
if (numargs < 1 || /* wrong number of arguments? */
numargs > 2 ||
!RXVALIDSTRING(args[0]))
return INVALID_ROUTINE; /* raise error condition */
if (numargs == 2) { /* have a timeout value? */
if (!string2long(args[1].strptr, &timeout) ||
(timeout < 0 && timeout != -1))
return INVALID_ROUTINE; /* raise error condition */
}
rc = DosWaitNPipe(args[0].strptr, timeout);
sprintf(retstr->strptr, "%d", rc);
retstr->strlength = strlen(retstr->strptr);
return VALID_ROUTINE;
}