Include large file support in SHOW VERSION, work on memory leaks, bufs

Show version includes the other configuration info, including READLINE and ASPI.

Fix a memory leak in Unix show devices.

Start using valgrind.  Add VLD support for Windows.

Fix memory leaks in main command processing.

add command line arguments to history if USEing_READLINE

Add atexit() and rundown support to dismount volumes at exit.

Update makefiles for READLINE - some versions require you to link with termcap or ncurses as well.

Fix memory leak in set default (including implicit set default on mount)

Free WCCFILE on search NAM$M_SYNCHK as VMS does.  Also release when returning RMS$_NMF.
Add nam$l_rlf field to NAM

Implement show devices for VMS.

When reusing a WCB for large file, ensure that the file header pointer is valid.

Add show cwd so it's easy to find out default for local files.

Add set cwd

Add spawn cmd so it's easy to inspect copied files.

Handle condition codes properly.

Finish sysmsg.

Add standard macros to stsdef.h

Deal with strerror on windows.
This commit is contained in:
Timothe Litt 2016-03-05 19:02:45 -05:00
parent 57049f51b3
commit 5f00f5b509
24 changed files with 1272 additions and 342 deletions

View File

@ -0,0 +1,3 @@
--memcheck:leak-check=yes
--suppressions=valgrind_suppressions_readline
--suppressions=valgrind_suppressions_ods2

Binary file not shown.

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -12,15 +12,18 @@
</ItemGroup>
<PropertyGroup Label="Globals">
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{BCCEAED2-1732-D796-1F70-040DE5DA42AD}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -43,10 +46,10 @@
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>DEBUG_BUILD;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions> HOME_SKIP=1 ;HOME_LOG;USE_VLD;DEBUG_BUILD;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
@ -98,6 +101,7 @@
<Command>copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir)$(TargetName)$(TargetExt) </Command>
<Outputs>$(SolutionDir)$(TargetName)$(TargetExt)</Outputs>
<Message>Copying $(TargetName)$(TargetExt)</Message>
<Inputs>$(OutDir)$(TargetName)$(TargetExt) </Inputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemGroup>

View File

@ -51,6 +51,15 @@ struct WCBKEY {
struct WCB *prevwcb;
};
#if 0
static unsigned int delta_from_name( const char *diskname );
#endif
static unsigned int delta_from_index( size_t index );
static unsigned int compute_delta( unsigned long sectorsize,
unsigned long sectors,
unsigned long tracks,
unsigned long cylinders );
unsigned deallocfile(struct FCB *fcb); /* Update.c */
#define DEBUGx
@ -287,6 +296,7 @@ static void *wcb_create( unsigned hashval, void *keyval, unsigned *retsts ) {
curvbn = wcbkey->prevwcb->hd_basevbn;
wcb->hd_seg_num = wcbkey->prevwcb->hd_seg_num;
memcpy(&wcb->hd_fid,&wcbkey->prevwcb->hd_fid,sizeof(struct fiddef));
head = wcbkey->fcb->head;
}
while (TRUE) {
register unsigned short *mp;
@ -825,15 +835,28 @@ unsigned dismount(struct VCB * vcb)
/******************************************************************** mount() */
#ifdef DEBUG
#define HOME_LIMIT 5
#ifndef HOME_SKIP
#define HOME_SKIP 1
#endif
#ifndef HOME_LIMIT
#define HOME_LIMIT 3
#endif
#else
#define HOME_LIMIT 100
#ifndef HOME_SKIP
#define HOME_SKIP 0
#endif
#ifndef HOME_LIMIT
#define HOME_LIMIT 1000
#endif
#endif
/* mount() make disk volume available for processing... */
unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],
struct VCB **retvcb) {
unsigned mount( unsigned flags,
unsigned devices,
char *devnam[],
char *label[],
struct VCB **retvcb ) {
register unsigned device,sts = 0;
struct VCB *vcb;
struct VCBDEV *vcbdev;
@ -842,13 +865,21 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],
#ifdef DEBUG
if (sizeof(struct HOME) != 512 || sizeof(struct HEAD) != 512) return SS$_NOTINSTALL;
#endif
vcb = (struct VCB *) calloc(1, sizeof(struct VCB) + (devices - 1) * sizeof(struct VCBDEV));
if (vcb == NULL) return SS$_INSFMEM;
if( retvcb )
*retvcb = NULL;
vcb = (struct VCB *) calloc( 1, sizeof(struct VCB) +
((devices - 1) * sizeof(struct VCBDEV)) );
if( vcb == NULL )
return SS$_INSFMEM;
vcb->status = 0;
if (flags & MOU_WRITE) vcb->status |= VCB_WRITE;
if( flags & MOU_WRITE )
vcb->status |= VCB_WRITE;
vcb->fcb = NULL;
vcb->dircache = NULL;
vcb->devices = 0;
vcbdev = vcb->vcbdev;
for( device = 0; device < devices; device++, vcbdev++ ) {
char *dname;
@ -857,9 +888,12 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],
sts = SS$_NOSUCHVOL;
vcbdev->dev = NULL;
if (strlen(dname)) { /* Really want to allow skipping volumes? */
unsigned int hba;
unsigned int hba, delta, homtry;
if( label[device] != NULL && strlen(label[device]) > sizeof( volsetSYS[0].vsr$t_label ) ) {
if( label[device] != NULL && strlen(label[device]) >
sizeof( volsetSYS[0].vsr$t_label ) ) {
printf( "%%ODS2-E-BADPARAM, Label %s is too long\n",
label[device] );
sts = SS$_BADPARAM;
break;
}
@ -876,35 +910,44 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],
break;
}
}
vcb->devices++;
sts = device_lookup( strlen( dname ), dname, TRUE,
&vcbdev->dev );
if ( !( sts & STS$M_SUCCESS ) ) break;
if( !(sts & STS$M_SUCCESS) )
break;
vcbdev->dev->access = flags; /* Requested mount options */
/* (e.g., /Write) */
sts = phyio_init( vcbdev->dev );
if ( !( sts & STS$M_SUCCESS ) ) break;
vcb->devices++;
if( !(sts & STS$M_SUCCESS) )
break;
if (vcbdev->dev->vcb != NULL) {
sts = SS$_DEVMOUNT;
break;
}
for (hba = 1; hba <= HOME_LIMIT; hba++) {
delta = delta_from_index( (vcbdev->dev->access & MOU_DEVTYPE) >> MOU_V_DEVTYPE );
for( hba = 1, homtry = 0; homtry < HOME_LIMIT; homtry++, hba += delta ) {
struct HOME *hom;
#if HOME_SKIP > 100
if( homtry < HOME_SKIP )
continue;
#endif
sts = phyio_read( vcbdev->dev, hba, sizeof( struct HOME ),
(char *) &vcbdev->home );
if (!(sts & STS$M_SUCCESS)) break;
hom = &vcbdev->home;
#ifdef DEBUG
printf( "--->mount(): LBA=%u, HM2$L_HOMELBN=%u, "
#if defined( DEBUG ) || defined( HOME_LOG )
printf( "--->mount(%u): LBA=%u, HM2$L_HOMELBN=%u, "
"HM2$L_ALHOMELBN=%u, "
"HM2$T_FORMAT=\"%12.12s\", memcmp()=%u\n",
hba, VMSLONG( hom->hm2$l_homelbn ),
homtry+1,hba, VMSLONG( hom->hm2$l_homelbn ),
VMSLONG( hom->hm2$l_alhomelbn ),
hom->hm2$t_format,
memcmp( hom->hm2$t_format, "DECFILE11B ", 12 )
);
#endif
if( (hba == VMSLONG(hom->hm2$l_homelbn) ||
hba == VMSLONG(hom->hm2$l_alhomelbn)) &&
if( (hba == VMSLONG(hom->hm2$l_homelbn)) &&
(VMSLONG(hom->hm2$l_alhomelbn) != 0) &&
(VMSLONG(hom->hm2$l_altidxlbn) != 0) &&
(VMSWORD(hom->hm2$w_homevbn) != 0) &&
@ -919,7 +962,7 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],
(memcmp(hom->hm2$t_format,"DECFILE11B ",12) == 0) ) {
break;
}
#ifdef DEBUG
#if defined( DEBUG ) || defined( HOME_LOG )
printf( "--->mount(): Home block validation failure\n" );
printf( "(VMSLONG(hom->hm2$l_alhomelbn) != 0) %u\n", (VMSLONG(hom->hm2$l_alhomelbn) != 0) );
printf( "(VMSLONG(hom->hm2$l_altidxlbn) != 0) %u\n", (VMSLONG(hom->hm2$l_altidxlbn) != 0) );
@ -1102,7 +1145,11 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],
if( !(sts & 1) ) {
vcbdev = vcb->vcbdev;
for( device = 0; device < devices; device++, vcbdev++ ) {
if (vcbdev->dev == NULL) continue;
if (vcbdev->dev == NULL) {
if( flags & MOU_VIRTUAL )
virt_device( devnam[device], NULL );
continue;
}
if( vcb->status & VCB_WRITE && vcbdev->mapfcb != NULL ) {
/* sts = */
@ -1127,6 +1174,11 @@ unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],
} else { /* *** DECREF *** */
vcbdev = vcb->vcbdev;
for( device = 0; device < vcb->devices; device++, vcbdev++ ) {
if (vcbdev->dev == NULL) {
if( flags & MOU_VIRTUAL )
virt_device( devnam[device], NULL );
continue;
}
phyio_done( vcbdev->dev );
}
free(vcb);
@ -1314,3 +1366,198 @@ void show_volumes( void ) {
return;
}
/*************************************************************** acccess_rundown() */
void access_rundown( void ) {
struct VCB *vcb, *next;
unsigned sts;
for( vcb = vcb_list; vcb != NULL; vcb = next ) {
next = vcb->next;
sts = dismount( vcb );
if( !(sts & STS$M_SUCCESS) ) {
printf( "Dismount failed in rundown: %s", getmsg(sts, MSG_TEXT) );
}
}
}
/*************************************************************** compute_delta() */
/*
* The search delta is computed from the
* volume geometry, expressed in sectors, tracks (surfaces), and
* cylinders, according to the following rules, to handle the cases where
* one or two dimensions of the volume have a size of 1.
*
* Geometry: Delta
*
* s x 1 x 1: 1 Rule 1
* 1 x t x 1: 1 Rule 2
* 1 x 1 x c: 1 Rule 3
*
* s x t x 1: s+1 Rule 4
* s x 1 x c: s+1 Rule 5
* 1 x t x c: t+1 Rule 6
*
* s x t x c: (t+1)*s+1 Rule 7
*/
#define DISK( name, sectors, tracks, cylinders ) \
{#name, 512 ## ul, sectors ## ul, tracks ## ul, cylinders ## ul},
#define DISKS( name, sectorsize, sectors, tracks, cylinders ) \
{#name, sectorsize ## ul, sectors ## ul, tracks ## ul, cylinders ## ul},
struct disktype disktype[] = {
DISK(UNKNOWN, 1, 1, 1) /* First = short sequence delta = 1 */
DISK(RK05, 12, 2, 203)
DISK(RK06, 22, 3, 411)
DISK(RK07, 22, 3, 815)
DISK(RK11, 12, 2, 203)
DISK(RL01, 40, 2, 256)
DISK(RL02, 40, 2, 512)
DISK(RM02, 32, 5, 823)
DISK(RM03, 32, 5, 823)
DISK(RP04, 22, 19, 411)
DISK(RP05, 22, 19, 411)
DISK(RM80, 31, 14, 559)
DISK(RP06, 22, 19, 815)
DISK(RM05, 32, 19, 823)
DISK(RP07, 50, 32, 630)
#if 0 /* Not useful now as RSX20-F used ODS-1 */
DISKS(RM02-T, 576, 30, 5, 823)
DISKS(RM03-T, 576, 30, 5, 823)
DISKS(RP04-T, 576, 20, 19, 411)
DISKS(RP05-T, 576, 20, 19, 411)
DISKS(RM80-T, 576, 30, 14, 559)
DISKS(RP06-T, 576, 20, 19, 815)
DISKS(RM05-T, 576, 30, 19, 823)
DISKS(RP07-T, 576, 43, 32, 630)
#endif
DISK(RX50, 10, 1, 80)
DISK(RX33, 15, 2, 80)
#if 0
DISK(RD50, 99, 99, 9999)
#endif
DISK(RD51, 18, 4, 306)
DISK(RD31, 17, 4, 615)
DISK(RD52, 17, 8, 512)
DISK(RD53, 17, 7, 1024)
DISK(RD54, 17, 15, 1225)
DISK(RA72, 51, 20, 1921)
#if 0
DISK(RA80, 99, 99, 9999)
#endif
DISK(RA81, 51, 14, 1258)
DISK(RA82, 57, 15, 1435)
DISK(RA90, 69, 13, 2649)
DISK(RA92, 73, 13, 3099)
DISK(RRD40,128, 1, 10400)
DISK(RRD50,128, 1, 10400)
DISKS(RX01, 128, 26, 1, 77)
DISKS(RX02, 256, 26, 1, 77)
#if 0
DISK(RX23-SD, 99, 99, 9999)
DISK(RX23-DD, 99, 99, 9999)
DISK(RX33-SD, 10, 1, 80)
DISK(RX33-DD, 99, 99, 9999)
#endif
DISK(RX50, 10, 1, 80)
#if 0
DISK(RC25, 99, 99, 9999 )
DISK(RF30, 99, 99, 9999 )
DISK(RF31, 99, 99, 9999 )
DISK(RF35, 99, 99, 9999 )
DISK(RF36, 99, 99, 9999 )
DISK(RF71, 99, 99, 9999 )
DISK(RF72, 99, 99, 9999 )
DISK(RF73, 99, 99, 9999 )
DISK(RF74, 99, 99, 9999 )
DISK(RZ22, 99, 99, 9999 )
DISK(RZ23, 99, 99, 9999 )
DISK(RZ24, 99, 99, 9999 )
DISK(RZ25, 99, 99, 9999 )
DISK(RZ26, 99, 99, 9999 )
DISK(RZ27, 99, 99, 9999 )
DISK(RZ28, 99, 99, 9999 )
DISK(RZ29, 99, 99, 9999 )
DISK(RZ31, 99, 99, 9999 )
DISK(RZ33, 99, 99, 9999 )
DISK(RZ35, 99, 99, 9999 )
DISK(RZ55, 99, 99, 9999 )
DISK(RZ56, 99, 99, 9999 )
DISK(RZ57, 99, 99, 9999 )
DISK(RZ58, 99, 99, 9999 )
DISK(RZ59, 99, 99, 9999 )
DISK(RZ72, 99, 99, 9999 )
DISK(RZ73, 99, 99, 9999 )
DISK(RZ74, 99, 99, 9999 )
#endif
{ NULL, 0, 0, 0, 0 }
};
static unsigned int compute_delta( unsigned long sectorsize,
unsigned long sectors,
unsigned long tracks,
unsigned long cylinders ) {
if( sectorsize < 512 )
sectors = (sectorsize * sectors) / 512;
if( sectors > 1 && tracks > 1 && cylinders > 1 ) /* Rule 7 */
return (tracks + 1) * sectors +1;
if( (sectors > 1 && tracks > 1 && cylinders == 1 ) || /* Rule 4 */
(sectors > 1 && tracks == 1 && cylinders > 1 ) ) /* Rule 5 */
return sectors + 1;
if( sectors == 1 && tracks > 1 && cylinders > 1 ) /* Rule 6 */
return tracks + 1;
return 1; /* Rules 1-3 */
}
#if 0
static unsigned int delta_from_name( const char *diskname ) {
struct disktype *dp;
for( dp = disktype; dp->name != NULL; dp++ ) {
if( !strcmp( dp->name, diskname ) )
return compute_delta( dp->sectorsize, dp->sectors, dp->tracks, dp->cylinders );
}
return ~0u;
}
#endif
static unsigned int delta_from_index( size_t index ) {
struct disktype *dp;
unsigned int delta;
if( index >= sizeof(disktype)/sizeof(disktype[0]) )
abort();
dp = disktype + index;
delta = compute_delta( dp->sectorsize, dp->sectors, dp->tracks, dp->cylinders );
#if defined( DEBUG ) || HOME_SKIP > 0
printf( "HOM search index for %s is %u\n", dp->name, delta );
#endif
return delta;
}

View File

@ -256,6 +256,13 @@ struct VCB {
extern struct VCB *vcb_list;
void show_volumes( void );
struct disktype {
const char *name;
unsigned long sectorsize, sectors, tracks, cylinders;
};
extern struct disktype disktype[];
/* RVN_TO_DEV( vcb, rvn ) - returns device from relative volume number */
/* returns NULL if RVN illegal or device not mounted */
@ -289,4 +296,6 @@ unsigned update_create(struct VCB *vcb,struct fiddef *did,char *filename,
unsigned update_extend(struct FCB *fcb,unsigned blocks,unsigned contig);
vmsword checksum( vmsword *block );
void access_rundown( void );
#endif /* # ifndef _ACCESS_H */

View File

@ -5,7 +5,7 @@
*
* Microsoft deprecates sprintf, but doesn't supply standard
* replacement until very recent IDEs.
* Microsoft doesn't like fopen.
* Microsoft doesn't like fopen, or strerror, or getcwd.
* One needs to use a M$ call to translate system errors.
*
* Finding out about drive letter assignments is unique to windows.
@ -18,12 +18,14 @@
#ifdef _WIN32
#include <windows.h>
#include <string.h>
#endif
#if defined(_MSC_VER) && _MSC_VER < 1900
int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
{
/******************************************************************* c99_vsnprintf() */
int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) {
int count = -1;
if (size != 0)
@ -34,8 +36,9 @@ int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
return count;
}
int c99_snprintf(char *outBuf, size_t size, const char *format, ...)
{
/******************************************************************* c99_snprintf() */
int c99_snprintf(char *outBuf, size_t size, const char *format, ...) {
int count;
va_list ap;
@ -49,6 +52,8 @@ int c99_snprintf(char *outBuf, size_t size, const char *format, ...)
#ifdef _MSC_VER
/******************************************************************* openf() */
FILE *openf( const char *filename, const char *mode ) {
errno_t err;
FILE *fd = NULL;
@ -63,11 +68,24 @@ FILE *openf( const char *filename, const char *mode ) {
#ifdef _WIN32
/******************************************************************* ods2_strerror() */
const char *ods2_strerror( int errn ) {
static char buf[256];
if( strerror_s( buf, sizeof( buf ), errn ) != 0 )
snprintf( buf, sizeof( buf ), "Untranslatable error %u", errn );
return buf;
}
/******************************************************************* w32_errstr() */
TCHAR *w32_errstr( DWORD eno, ... ) {
va_list ap;
TCHAR *msg;
if( eno == 0 )
if( eno == NO_ERROR )
eno = GetLastError();
va_start(ap,eno);
@ -81,6 +99,8 @@ TCHAR *w32_errstr( DWORD eno, ... ) {
return msg;
}
/******************************************************************* driveFromLetter() */
char *driveFromLetter( const char *letter ) {
DWORD rv = ERROR_INSUFFICIENT_BUFFER;
size_t cs = 16;

View File

@ -20,11 +20,24 @@ FILE *openf( const char *filename, const char *mode );
#endif
#ifdef _WIN32
#include <errno.h>
#include <stdarg.h>
#include <windows.h>
#include <direct.h>
#undef getcwd
#define getcwd _getcwd
#undef chdir
#define chdir _chdir
#undef strerror
#define strerror(n) ods2_strerror(n)
const char *ods2_strerror( errno_t errn );
TCHAR *w32_errstr( DWORD eno, ... );
char *driveFromLetter( const char *letter );
#else /* Not WIN32 */
#include <unistd.h>
#endif
#define UNUSED(x) (void)(x)

View File

@ -7,7 +7,7 @@ CC=gcc
CCFLAGS = -O4 -g
DEFS = -DUSE_READLINE
LDFLAGS = -lreadline
LDFLAGS = -lreadline -ltermcap
# Object file extension
OBJ = .o

View File

@ -4,7 +4,7 @@
CCFLAGS = -O4 -g
# DEFS = -DUSE_READLINE
# LDFLAGS = -lreadline
# LDFLAGS = -lreadline -ltermcap
# Object file extension
OBJ = .o

View File

@ -9,7 +9,7 @@ CCFLAGS = -O4 -g
# Include readline support
DEFS = -DUSE_READLINE
LDFLAGS = -lreadline
LDFLAGS = -lreadline -ltermcap
# Object file extension
OBJ = .o

View File

@ -104,32 +104,38 @@
#define _BSD_SOURCE
#include <ctype.h> /* isalpha(), isspace(), tolower() */
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "version.h"
#include "compat.h"
#include "sysmsg.h"
#include "phyio.h"
#include "phyvirt.h"
#ifdef _WIN32
#include <Windows.h>
#endif
#include "version.h"
#include "access.h"
#include "compat.h"
#include "descrip.h"
#include "device.h"
#include "direct.h"
#include "ods2.h"
#include "phyio.h"
#include "phyvirt.h"
#include "rms.h"
#include "ssdef.h"
#include "stsdef.h"
#include "sysmsg.h"
#if !defined( _WIN32 ) && !defined( VMS )
#include <sys/types.h>
#include <sys/wait.h>
#else
# ifdef _WIN32
# include <process.h>
# endif
#endif
#ifdef VMS
#include <starlet.h>
#else
#include "vmstime.h"
#endif
@ -148,6 +154,14 @@
#define FALSE ( 0 != 0 )
#endif
#if defined( _WIN32 ) && defined(_MSC_VER) && defined( DEBUG_BUILD ) && defined( USE_VLD )
/* Normally done in the project file, but VLD is optional and I'd rather not provide
* instructions as they vary by IDE version. See http://vld.codeplex.com/ if interested.
*/
#include "C:\\Program Files (x86)\\Visual Leak Detector\\include\\vld.h"
#pragma comment (lib,"C:\\Program Files (x86)\\Visual Leak Detector\\lib\\Win32\\vld.lib")
#endif
#define MAXREC 32767
#define PRINT_ATTR ( FAB$M_CR | FAB$M_PRN | FAB$M_FTN )
@ -158,6 +172,7 @@
#include <readline/history.h>
#endif
/******************************************************************* fgetline() */
/* Read a line of input - unlimited length
* Removes \n, returns NULL at EOF
* Caller responsible for free()
@ -170,7 +185,7 @@ static char *fgetline( FILE *stream, int keepnl ) {
int c;
while( (c = fgetc(stream)) != EOF && c != '\n' ) {
if( idx + (keepnl != 0) +1 > bufsize ) { /* Allow space for char + (optional \n) + \0 */
if( idx + (keepnl != 0) +2 > bufsize ) { /* In buf + char + (optional \n) + \0 */
char *nbuf;
bufsize += xpnsize;
nbuf = (char *) realloc( buf, bufsize );
@ -202,11 +217,12 @@ static char *fgetline( FILE *stream, int keepnl ) {
return buf;
}
/******************************************************************* keycomp() */
/* keycomp: routine to compare parameter to a keyword - case insensitive! */
static int keycomp(const char *param, const char *keywrd) {
while (*param != '\0') {
if (tolower(*param++) != *keywrd++) return 0;
if( tolower(*param++) != tolower(*keywrd++) ) return 0;
}
return 1;
}
@ -217,11 +233,12 @@ static int keycomp(const char *param, const char *keywrd) {
*/
#define NV NOVAL, NULL
#define KV(list) KEYVAL, list
#define CV(list) KEYCOL, list
struct qual {
const char *name;
int set;
int clear;
enum qualtype { NOVAL, KEYVAL } qtype;
enum qualtype { NOVAL, KEYVAL, KEYCOL } qtype;
void *arg;
const char *helpstr;
};
@ -261,6 +278,7 @@ static void qualhelp( int par, struct qual *qtable );
static int vms_qual = 1;
static int verify_cmd = 1;
/******************************************************************* checkquals() */
/* checkquals: Given valid qualifier definitions, process qualifer
* list from a command left to right. Also handles parameters and
* qualifier values (/Qual=value).
@ -322,6 +340,7 @@ static int checkquals(int result, struct qual qualset[],int qualc,char *qualv[])
*nvp++ = '\0';
switch( qp->qtype ) {
case KEYVAL:
case KEYCOL:
result = checkquals( result, (struct qual *)qp->arg, -1, &qv );
if( result == -1 )
return result;
@ -336,6 +355,9 @@ static int checkquals(int result, struct qual qualset[],int qualc,char *qualv[])
return result;
}
/******************************************************************* dodir() */
/*********************************************************** prvmstime() */
static int prvmstime(VMSTIME vtime, const char *sfx) {
int sts = 0;
char tim[24];
@ -358,6 +380,8 @@ static int prvmstime(VMSTIME vtime, const char *sfx) {
return sts;
}
/*********************************************************** pwrap() */
static void pwrap( int *pos, const char *fmt, ... ) {
char pbuf[200], *p, *q;
va_list ap;
@ -392,6 +416,7 @@ static void pwrap( int *pos, const char *fmt, ... ) {
}
}
/*********************************************************** dirtotal() */
#define dir_extra (dir_date | dir_fileid | dir_owner | dir_prot | dir_size)
#define dir_date (1 << 0)
@ -486,6 +511,8 @@ static void dirtotal( int options, int size, int alloc ) {
return;
}
/************************************************************ dodir() */
static unsigned dodir(int argc,char *argv[],int qualc,char *qualv[]) {
char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
int options;
@ -1412,7 +1439,7 @@ static unsigned dostats( void ) {
/******************************************************************* doshow() */
/* show: version */
/*********************************************************** show_version() */
#define MNAMEX(n) #n
#define MNAME(n) MNAMEX(n)
@ -1431,23 +1458,26 @@ static void show_version( void ) {
# endif
printf( " direct SCSI access support");
#endif
printf( "\n\n" );
printf( "\n " );
phyio_show( SHOW_FILE64 );
putchar( '\n' );
return;
}
/* show: the show command */
/*********************************************************** doshow() */
static struct qual showkwds[] = { {"default", 0, 0, NV, "Default directory"},
{"devices", 1, 0, NV, "Devices"},
{"qualifier_style", 2, 0, NV, "Qualifier style (Unix, VMS)" },
{"statistics", 3, 0, NV, "Debugging statistics", },
{"time", 4, 0, NV, "Time"},
{"verify", 5, 0, NV, "Command file echo" },
{"version", 6, 0, NV, "Version"},
{"volumes", 7, 0, NV, "Mounted volume information" },
static struct qual showkwds[] = { {"cwd", 0, 0, NV, "Working directory on local system"},
{"default", 1, 0, NV, "Default directory on VMS volume"},
{"devices", 2, 0, NV, "Devices"},
{"qualifier_style", 3, 0, NV, "Qualifier style (Unix, VMS)" },
{"statistics", 4, 0, NV, "Debugging statistics"},
{"time", 5, 0, NV, "Time"},
{"verify", 6, 0, NV, "Command file echo" },
{"version", 7, 0, NV, "Version"},
{"volumes", 8, 0, NV, "Mounted volume information" },
{NULL, 0, 0, NV, NULL }
};
static struct param showpars[] = { {"item_name", REQ, KEYWD, PA(showkwds), NULL },
static struct param showpars[] = { {"item_name", REQ, KEYWD, PA(showkwds), "" },
{NULL, 0, 0, NOPA, NULL }
};
@ -1463,6 +1493,29 @@ unsigned doshow(int argc,char *argv[],int qualc,char *qualv[]) {
default:
return SS$_BADPARAM;
case 0: {
size_t size = 32;
char *buf = NULL;
while( 1 ) {
char *nbuf;
nbuf = (char *)realloc( buf, size );
if( nbuf == NULL ) {
free( buf );
return SS$_INSFMEM;
}
buf = nbuf;
if( getcwd( buf, size ) != NULL )
break;
if( errno != ERANGE ) {
perror( "getcwd" );
return SS$_BADPARAM;
}
size *= 2;
}
printf( " Current working directory is %s\n", buf );
free( buf );
return SS$_NORMAL;
}
case 1: {
int sts;
unsigned short curlen;
char curdir[NAM$C_MAXRSS + 1];
@ -1478,16 +1531,16 @@ unsigned doshow(int argc,char *argv[],int qualc,char *qualv[]) {
}
return sts;
}
case 1:
case 2:
phyio_show( SHOW_DEVICES );
virt_show( NULL );
return SS$_NORMAL;
case 2:
case 3:
printf ( " Qualifier style: %s\n", vms_qual? "/VMS": "-unix" );
return SS$_NORMAL;
case 3:
case 4:
return dostats();
case 4: {
case 5: {
unsigned sts;
char timstr[24];
unsigned short timlen;
@ -1504,56 +1557,66 @@ unsigned doshow(int argc,char *argv[],int qualc,char *qualv[]) {
}
}
return SS$_NORMAL;
case 5:
case 6:
printf( "Command file verification is %s\n", (verify_cmd? "on": "off") );
return SS$_NORMAL;
case 6:
case 7:
show_version();
return SS$_NORMAL;
case 7:
case 8:
show_volumes();
return SS$_NORMAL;
}
return SS$_NORMAL;
}
/******************************************************************* setdef() */
/******************************************************************* doset() */
/*********************************************************** setdef() */
static unsigned setdef_count = 0;
static int default_set = FALSE;
static unsigned setdef( char *newdef )
{
static unsigned setdef( char *newdef ) {
register unsigned sts;
struct dsc_descriptor defdsc;
defdsc.dsc_a_pointer = (char *) newdef;
defdsc.dsc_w_length = strlen( defdsc.dsc_a_pointer );
defdsc.dsc_w_length = (unsigned short)strlen( defdsc.dsc_a_pointer );
sts = sys_setddir( &defdsc, NULL, NULL );
if ( sts & STS$M_SUCCESS ) {
setdef_count++;
default_set = TRUE;
} else {
printf( "%%ODS2-E-SETDEF, Error %s setting default to %s\n", getmsg(sts, MSG_TEXT), newdef );
}
return sts;
}
/******************************************************************** doset() */
static unsigned setcwd( char *newdef ) {
if( chdir( newdef ) != 0 ) {
printf( "%%ODS2-W-SETDEF, Error %s setting cwd to %s\n",
strerror( errno ), newdef );
return SS$_BADPARAM;
}
return SS$_NORMAL;
}
/************************************************************ sethelp() */
static hlpfunc_t sethelp;
static struct qual setkwds[] = { {"default", 0, 0, NV, "Default directory"},
static struct qual setkwds[] = { {"cwd", 0, 0, NV, "Working directory on local system"},
{"directory_qualifiers", 1, 0, NV, "Default qualifiers for DIRECTORY command" },
{"qualifier_style", 2, 0, NV, "Qualifier style (Unix, VMS)" },
{"verify", 3, 0, NV, "-Display commands in indirect files" },
{"noverify", 4, 0, NV, NULL },
{"default", 2, 0, NV, "Default directory on VMS volume"},
{"qualifier_style", 3, 0, NV, "Qualifier style (Unix, VMS)"},
{"verify", 4, 0, NV, "-Display commands in indirect files"},
{"noverify", 5, 0, NV, NULL },
{NULL, 0, 0, NV, NULL }
};
static struct qual setqskwds[] = {{"unix", 1, 0, NV, "Unix style options, '-option'"},
{"vms", 2, 0, NV, "VMS style qualifiers, '/qualifier'"},
{NULL, 0, 0, NV, NULL }
};
static struct param setpars[] = { {"item_name", REQ, KEYWD, PA(setkwds), NULL },
{"value" , CND, KEYWD, sethelp, setqskwds, NULL },
static struct param setpars[] = { {"item_name", REQ, KEYWD, PA(setkwds), "" },
{"value" , CND, KEYWD, sethelp, setqskwds, "" },
{NULL, 0, 0, NOPA, NULL },
};
@ -1575,21 +1638,25 @@ static const char * sethelp( struct CMDSET *cmd, struct param *p, int argc, char
return NULL;
switch( par ) {
case 0:
p->helpstr = "default directory on volume - ";
p->ptype = VMSFS;
p->helpstr = "working directory for local files";
p->ptype = STRING;
break;
case 1:
p->helpstr = "default directory on volume";
p->ptype = VMSFS;
break;
case 2:
p->helpstr = "directory qualifier name ";
p->ptype = KEYWD;
p->arg = dirquals;
break;
case 2:
case 3:
p->helpstr = "style ";
p->ptype = KEYWD;
p->arg = setqskwds;
break;
case 3:
case 4:
case 5:
p->ptype = NONE;
break;
@ -1599,6 +1666,8 @@ static const char * sethelp( struct CMDSET *cmd, struct param *p, int argc, char
return NULL;
}
/*********************************************************** doset() */
static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) {
int parnum;
@ -1611,11 +1680,12 @@ static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) {
default:
return SS$_BADPARAM;
case 0: /* default */
case 2: /* current working directory */
if( qualc ) {
printf( "%%ODS2-E-NOQUAL, No qualifiers are permitted\n" );
return 0;
}
return setdef( argv[2] );
return (parnum == 0)? setdef( argv[2] ) : setcwd( argv[2] );
case 1:{ /* directory_qualifiers */
int options = checkquals(dir_default,dirquals,qualc,qualv);
if( options == -1 )
@ -1623,7 +1693,7 @@ static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) {
dir_defopt = options;
return 1;
}
case 2: { /* qualifier_style */
case 3: { /* qualifier_style */
int par = checkquals (0,setqskwds,1,argv+2);
if( par == -1 )
return SS$_BADPARAM;
@ -1639,16 +1709,16 @@ static unsigned doset(int argc,char *argv[],int qualc,char *qualv[]) {
}
return 1;
}
case 3:
case 4:
verify_cmd = 1;
return 1;
case 4:
case 5:
verify_cmd = 0;
return 1;
}
}
/* The bits we need when we don't have real VMS routines underneath... */
/******************************************************************* dodismount() */
static struct param dmopars[] = { {"drive_letter", REQ, STRING, NOPA, "Drive containing volume to dismount", },
{NULL, 0, 0, NOPA, NULL }
@ -1678,7 +1748,10 @@ unsigned dodismount(int argc,char *argv[],int qualc,char *qualv[]) {
#error MOU_WRITE != 1
#endif
static struct qual mouquals[] = { {"image", MOU_VIRTUAL, 0, NV, "Mount a disk image file", },
#define DT_NAME "drive_type"
static struct qual mouquals[] = { {DT_NAME, 0, MOU_DEVTYPE, CV(NULL), "Drive type (DEC model name) "},
{"image", MOU_VIRTUAL, 0, NV, "Mount a disk image file", },
{"readonly", 0, MOU_WRITE, NV, "Only allow reading from volume"},
{"virtual", MOU_VIRTUAL, 0, NV, NULL, },
{"write", MOU_WRITE, 0, NV, "Allow writing to volume", },
@ -1691,6 +1764,10 @@ static struct param moupars[] = { {"volumes", REQ, LIST, NOPA,
{ NULL, 0, 0, NOPA, NULL }
};
/******************************************************************* domount() */
/*********************************************************** parselist() */
static int parselist( char ***items, size_t min, char *arg, const char *label ) {
size_t n = 0, i;
char **list = NULL;
@ -1737,7 +1814,9 @@ static int parselist( char ***items, size_t min, char *arg, const char *label )
return (int)n;
}
static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) {
/*********************************************************** domount() */
static unsigned domount( int argc,char *argv[],int qualc,char *qualv[] ) {
int sts = 1,devices = 0;
char **devs = NULL, **labs = NULL;
@ -1760,7 +1839,7 @@ static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) {
struct VCB *vcb;
sts = mount( options | MOU_LOG, devices, devs, labs, &vcb );
if (sts & STS$M_SUCCESS) {
if (setdef_count == 0) {
if( !default_set ) {
char *colon, *buf;
size_t len;
@ -1770,7 +1849,8 @@ static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) {
perror( "malloc" );
} else {
colon = strchr( vcb->vcbdev[0].dev->devnam, ':' );
if( colon != NULL ) len = (size_t)(colon - vcb->vcbdev[0].dev->devnam);
if( colon != NULL )
len = (size_t)(colon - vcb->vcbdev[0].dev->devnam);
memcpy( buf, vcb->vcbdev[0].dev->devnam, len );
memcpy( buf+len, ":[000000]", sizeof( ":[000000]" ) );
setdef(buf);
@ -1788,8 +1868,68 @@ static unsigned domount(int argc,char *argv[],int qualc,char *qualv[]) {
return sts;
}
/******************************************************************* dospawn() */
static unsigned dospawn( int argc,char *argv[],int qualc,char *qualv[] ) {
#ifdef VMS
unsigned sts;
UNUSED( argc );
UNUSED( argv );
UNUSED( qualc );
UNUSED( qualv );
sts = lib$spawn( 0,0,0,0,0,0,0,0,0,0,0,0,0 );
return sts;
#else
# ifdef _WIN32
UNUSED( argc );
UNUSED( argv );
UNUSED( qualc );
UNUSED( qualv );
if( system( "cmd" ) == -1 ) {
perror( "cmd" );
return SS$_NOSUCHFILE;
}
return SS$_NORMAL;
# else
char *shell, *p;
pid_t pid;
UNUSED( argc );
UNUSED( argv );
UNUSED( qualc );
UNUSED( qualv );
if( (shell = getenv( "SHELL" )) == NULL )
shell = "/bin/sh";
if( (p = strrchr( shell, '/')) == NULL )
p = shell;
else
p++;
if( (pid = fork()) == 0 ) {
execlp( shell, p, (char *)NULL );
perror( "%s" );
exit(EXIT_FAILURE);
}
if( pid == -1 ) {
perror( shell );
return SS$_NOSUCHFILE;
}
waitpid( pid, NULL, 0 );
return SS$_NORMAL;
# endif
#endif
}
/******************************************************************* dohelp() */
/*********************************************************** cmdhelp() */
static void cmdhelp( struct CMDSET *cmdset ) {
struct CMDSET *cmd;
int n = 0;
@ -1809,10 +1949,12 @@ static void cmdhelp( struct CMDSET *cmdset ) {
printf( "\n" );
}
/*********************************************************** cmdhelp() */
static void qualhelp( int par, struct qual *qtable ) {
struct qual *q;
int n = 0;
size_t max = 0;
size_t max = 0, col = 4;
if( par < 0 )
max = -par;
@ -1838,14 +1980,28 @@ static void qualhelp( int par, struct qual *qtable ) {
if( *q->helpstr == '-' )
switch( q->qtype ) {
case NOVAL:
printf( NOSTR "%-*s - %s\n",
(int) (max-NOSTR_LEN), q->name, q->helpstr+1 );
if( *q->helpstr ) {
printf( NOSTR "%-*s - %s\n",
(int) (max-NOSTR_LEN), q->name, q->helpstr+1 );
break;
}
if( col + max > 50 ) {
printf( "\n " );
col = 8;
} else {
while( col < 8 ) {
putchar( ' ' ); col++;
}
}
printf( "%-*s", (int) max, q->name );
col += max;
break;
case KEYVAL:
case KEYCOL:
printf( NOSTR "%s=%-*s - %s\n",
q->name, (int) (max-(NOSTR_LEN+strlen(q->name)+1)), "",
q->helpstr+1 );
qualhelp( -(int)max, (struct qual *)q->arg );
qualhelp( q->qtype == KEYCOL? 1 : -(int)max, (struct qual *)q->arg );
break;
default:
abort();
@ -1853,12 +2009,26 @@ static void qualhelp( int par, struct qual *qtable ) {
else
switch( q->qtype ) {
case NOVAL:
printf("%-*s - %s\n", (int) max, q->name, q->helpstr );
if( *q->helpstr ) {
printf("%-*s - %s\n", (int) max, q->name, q->helpstr );
break;
}
if( col + max > 50 ) {
printf( "\n " );
col = 8;
} else {
while( col < 8 ) {
putchar( ' ' ); col++;
}
}
printf( "%-*s", (int) max, q->name );
col += max;
break;
case KEYVAL:
case KEYCOL:
printf( "%s=%-*s - %s\n", q->name, (int)(max-strlen(q->name)+1), "",
q->helpstr );
qualhelp( -(int)max, (struct qual *)q->arg );
qualhelp( q->qtype == KEYCOL? 1 : -(int)max, (struct qual *)q->arg );
break;
default:
abort();
@ -1871,6 +2041,8 @@ static void qualhelp( int par, struct qual *qtable ) {
#undef NOSTR
#undef NOSTR_LEN
/*********************************************************** parhelp() */
static void parhelp( struct CMDSET *cmd, int argc, char **argv) {
struct param *p;
struct param *ptable;
@ -1888,14 +2060,14 @@ static void parhelp( struct CMDSET *cmd, int argc, char **argv) {
size_t max = 0;
for( p = ptable; p->name != NULL; p++ ) {
if( 1||p->helpstr ) {
if( p->helpstr ) {
size_t len = strlen(p->name);
if( len > max )
max = len;
}
}
for( p = ptable; p->name != NULL; p++ ) {
if(1|| p->helpstr ) {
if( p->helpstr ) {
size_t len = strlen(p->name);
if( !col ) {
printf( " Parameters:\n " );
@ -1913,7 +2085,8 @@ static void parhelp( struct CMDSET *cmd, int argc, char **argv) {
col += len;
}
}
printf( "\n\n Type help PARAMETER for more about each parameter.\n" );
printf( "\n\n Type help %s PARAMETER for more about each parameter.\n",
cmd->name );
return;
}
@ -1968,13 +2141,15 @@ static void parhelp( struct CMDSET *cmd, int argc, char **argv) {
return;
}
/*********************************************************** dohelp() */
/* help: Display help guided by command table. */
#define NCMD 16
#define NCMD 17
static struct CMDSET cmdset[NCMD+1];
static struct param helppars[] = { {"command", OPT, CMDNAM, PA(cmdset), NULL },
{"parameter", OPT, STRING, NOPA, NULL },
{"value", OPT, STRING, NOPA, NULL },
static struct param helppars[] = { {"command", OPT, CMDNAM, PA(cmdset), "" },
{"parameter", OPT, STRING, NOPA, "" },
{"value", OPT, STRING, NOPA, "" },
{NULL, 0, 0, NOPA, NULL },
};
@ -1983,19 +2158,20 @@ static unsigned dohelp(int argc,char *argv[],int qualc,char *qualv[]);
static struct CMDSET cmdset[NCMD+1] = {
{ "copy", docopy, 0,copyquals,copypars, "Copy a file from VMS to host file", },
{ "import", doimport, 0,NULL, importpars, "Copy a file from host to VMS", },
{ "delete", dodelete, 0,delquals, delpars, "Delete a VMS file", },
{ "difference",dodiff, 0,NULL, diffpars, "Compare VMS file to host file", },
{ "directory", dodir, 0,dirquals,dirpars, "List directory of VMS files", },
{ "dismount", dodismount,0,NULL, dmopars, "Dismount a VMS volume", },
{ "exit", NULL, 2,NULL, NULL, "Exit ODS2", },
{ "extend", doextend, 0,NULL, extendpars, NULL },
{ "help", dohelp, 0,NULL, helppars, "Obtain help on a command", },
{ "quit", NULL, 2,NULL, NULL, "Exit ODS-2", },
{ "show", doshow, 0,NULL, showpars, "Display state", },
{ "search", dosearch, 0,NULL, searchpars, "Search VMS file for a string", },
{ "set", doset, 0,NULL, setpars, "Set PARAMETER - set HELP for list", },
{ "dismount", dodismount,0,NULL, dmopars, "Dismount a VMS volume", },
{ "import", doimport, 0,NULL, importpars, "Copy a file from host to VMS", },
{ "mount", domount, 0,mouquals, moupars, "Mount a VMS volume", },
{ "quit", NULL, 2,NULL, NULL, "Exit ODS-2", },
{ "search", dosearch, 0,NULL, searchpars, "Search VMS file for a string", },
{ "set", doset, 0,NULL, setpars, "Set PARAMETER - set HELP for list", },
{ "show", doshow, 0,NULL, showpars, "Display state", },
{ "spawn", dospawn, 0,NULL, NULL, "Open a command subprocess", },
{ "test", dotest, 0,NULL, testpars, NULL },
{ "type", dotype, 0,NULL, typepars, "Display a VMS file on the terminal", },
{ NULL, NULL, 0,NULL, NULL, NULL } /* ** END MARKER ** */
@ -2064,15 +2240,6 @@ static unsigned dohelp(int argc,char *argv[],int qualc,char *qualv[]) {
}
printf( "%s: command not found\n", argv[1] );
return 0;
printf(" set_default type\n");
printf(" Example:-\n $ mount e:\n");
printf(" $ search e:[vms_common.decc*...]*.h rms$_wld\n");
printf(" $ set default e:[sys0.sysmgr]\n");
printf(" $ copy *.com;-1 c:\\*.*\n");
printf(" $ directory/file/size/date [-.sys*...].%%\n");
printf(" $ exit\n");
return 1;
}
/*************************************************************** cmdexecute() */
@ -2142,7 +2309,7 @@ static int cmdexecute( int argc, char *argv[], int qualc, char *qualv[] ) {
/* cmdsplit: break a command line into its components */
/*
* New feature for Unix: '//' or '--' stops qualifier parsing.
* Feature for Unix: '//' or '--' stops qualifier parsing.
* This enables us to copy to Unix directories with VMS style /qualifiers.
* copy /bin // *.com /tmp/ *
* is split into argv[0] -> "*.com" argv[1] -> "/tmp/ *" qualv[0]-> "/bin"
@ -2156,60 +2323,71 @@ static int cmdsplit(char *str) {
char *sp = str;
int i;
char q = vms_qual? '/': '-';
for (i = 0; i < MAXITEMS; i++) argv[i] = qualv[i] = "";
while (*sp != '\0') {
while (*sp == ' ') sp++;
if (*sp != '\0') {
if (*sp == q) {
*sp++ = '\0';
if (*sp == q) {
sp++;
q = '\0';
continue;
}
if( qualc >= MAXITEMS ) {
printf( "%%ODS2-E-CMDERR, Too many qualifiers specified\n" );
return 0;
for( i = 0; i < MAXITEMS; i++ ) argv[i] = qualv[i] = "";
while( *sp != '\0' ) {
while( *sp == ' ' ) sp++;
if( *sp == '\0' )
break;
if( *sp == q ) { /* Start of qualifier */
*sp++ = '\0'; /* Terminate previous word */
if (*sp == q) { /* qq = end of qualifiers */
sp++;
q = '\0';
continue;
}
if( qualc >= MAXITEMS ) {
printf( "%%ODS2-E-CMDERR, Too many qualifiers specified\n" );
return 0;
}
qualv[qualc++] = sp;
} else { /* New argument */
if( argc >= MAXITEMS ) {
printf( "%%ODS2-E-CMDERR, Too many arguments specified\n" );
return 0;
}
argv[argc++] = sp;
if( *sp == '"' ) {
++argv[argc-1];
for( ++sp; *sp && (*sp != '"' || sp[1] == '"'); sp++ ) {
if( *sp == '"' ) /* Interior "" => " */
memmove( sp, sp+1, strlen(sp+1)+1 );
}
qualv[qualc++] = sp;
} else {
if( argc >= MAXITEMS ) {
printf( "%%ODS2-E-CMDERR, Too many arguments specified\n" );
return 0;
}
argv[argc++] = sp;
if( *sp == '"' ) {
++argv[argc-1];
for( ++sp; *sp && (*sp != '"' || sp[1] == '"'); sp++ ) {
if( *sp == '"' )
memmove( sp, sp+1, strlen(sp+1)+1 );
}
if( *sp == '"' ) {
*sp++ = '\0';
if( *sp && *sp != ' ' ) {
printf( "%%ODS2-E-CMDERR, Unterminated string\n" );
return 0;
}
} else {
if( *sp == '"' ) { /* Ending " of string */
*sp++ = '\0';
if( *sp && *sp != ' ' ) { /* Something following */
printf( "%%ODS2-E-CMDERR, Unterminated string\n" );
return 0;
}
continue;
} else {
printf( "%%ODS2-E-CMDERR, Unterminated string\n" );
return 0;
}
}
while (*sp != ' ' && *sp != q && *sp != '\0') sp++;
if (*sp == '\0') {
break;
} else {
if (*sp != q) *sp++ = '\0';
}
continue;
} /* Quoted string */
}
/* Find end of atom */
while( !(*sp == '\0' || *sp == ' ' || *sp == q) ) sp++;
if (*sp == '\0')
break;
if( *sp == ' ' )
*sp++ = '\0';
}
if (argc > 0) return cmdexecute(argc,argv,qualc,qualv);
if( argc > 0 )
return cmdexecute( argc, argv, qualc, qualv );
return 1;
}
/******************************************************************* main() */
/*********************************************************** getcmd() */
#ifdef VMS
static char *getcmd( char *inp, size_t max, char *prompt ) {
struct dsc_descriptor prompt_d = { strlen(prompt),DSC$K_DTYPE_T,
@ -2242,6 +2420,7 @@ static char *getcmd( char *inp, size_t max, char *prompt ) {
}
#endif /* VMS */
/*********************************************************** main() */
/* main: the simple mainline of this puppy... */
/*
@ -2285,10 +2464,43 @@ int main( int argc,char *argv[] ) {
history_truncate_file( hfname, 200 );
stifle_history( 200 );
read_history( hfname );
} else {
hfname = NULL;
}
#endif
sts = sys_initialize();
if( !(sts & STS$M_SUCCESS) ) {
printf( "Unable to initialize library: %s\n", getmsg( sts, MSG_TEXT ) );
exit(EXIT_FAILURE);
}
{ /* Build parser keyword list from disk table entries */
struct qual *qp, *kp = NULL;
struct disktype * dp;
size_t n = 0;
for( dp = disktype; dp->name != NULL; dp++ )
;
n = (size_t) (dp - disktype);
kp = (struct qual *)calloc( n+1, sizeof( struct qual ) );
if( kp == NULL ) {
perror( "malloc" );
exit( EXIT_FAILURE );
}
for( qp = mouquals; qp->name != NULL; qp++ )
if( !strcmp( qp->name, DT_NAME ) )
break;
qp->arg = kp;
for( dp = disktype; dp->name != NULL; dp++ ) {
kp->name = dp->name;
kp->set = (int)((dp-disktype) << MOU_V_DEVTYPE);
kp->clear = MOU_DEVTYPE;
kp->qtype = NOVAL;
if( dp != disktype )
kp->helpstr = "";
kp++;
}
if( (((unsigned)(dp-disktype)) << MOU_V_DEVTYPE) & ~MOU_DEVTYPE )
abort(); /* MOU_DEVTYPE isn't wide enough for the max index */
}
if( argc > 1 ) {
int i, l = 0;
@ -2327,6 +2539,10 @@ int main( int argc,char *argv[] ) {
*p = '\0';
i += strlen( ptr ) +1;
}
#ifdef USE_READLINE
if( ptr != NULL && *ptr )
add_history( ptr );
#endif
}
if( ptr == NULL ) {
if (atfile != NULL) {
@ -2404,18 +2620,30 @@ int main( int argc,char *argv[] ) {
}
} /* while 1 */
free( command_line );
if( rl != NULL ) {
free( rl );
}
#ifdef USE_READLINE
if( hfname != NULL ) {
write_history( hfname );
clear_history();
}
wordfree( &wex ); /* hfname points into wex and should not be free()d */
#endif
if (atfile != NULL) fclose(atfile);
#ifdef VMS
return 1;
#else
return 0;
#endif
if (atfile != NULL)
fclose(atfile);
{
struct qual *qp;
for( qp = mouquals; qp->name != NULL; qp++ )
if( !strcmp( qp->name, DT_NAME ) ) {
free( qp-> arg );
qp->arg = NULL;
break;
}
}
exit( EXIT_SUCCESS );
}

View File

@ -5,10 +5,11 @@
#ifndef _ODS2_H
#define _ODS2_H
#define MOU_WRITE 1
#define MOU_VIRTUAL 2
#define MOU_LOG 4
#define MOU_WRITE 1
#define MOU_VIRTUAL 2
#define MOU_LOG 4
#define SUB_DELETE 1
#define MOU_V_DEVTYPE 8
#define MOU_DEVTYPE (0xffff << MOU_V_DEVTYPE)
#endif /* #ifndef _ODS2_H */

View File

@ -40,6 +40,7 @@
#include "stsdef.h"
#include "compat.h"
#include "phyvirt.h"
#include "sysmsg.h"
#ifdef USE_ASPI
#include "scsidefs.h"
@ -558,9 +559,11 @@ static void getsysversion( void ) {
OSVERSIONINFO sysver;
memset( &sysver, 0, sizeof( sysver ) );
#pragma warning (disable : 4996)
sysver.dwOSVersionInfoSize = sizeof( sysver );
GetVersionEx( &sysver /* lpVersionInfo */
);
#pragma warning (default : 4996)
is_NT = ( sysver.dwPlatformId == VER_PLATFORM_WIN32_NT ) ? 1 : 0 ;
}
@ -580,21 +583,21 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) {
sector, dev->bytespersector, dev->IoBuffer );
} else
#endif
{
{
if ( dev->access & MOU_VIRTUAL || is_NT ) {
DWORD DistanceLow, DistanceHigh, BytesRead;
DistanceLow = ( sector * dev->blockspersector ) << 9;
DistanceHigh = ( sector * dev->blockspersector ) >> 23;
SetLastError( 0 );
SetFilePointer( dev->API.Win32.handle,/* hFile */
DistanceLow, /* lDistanceToMove */
&DistanceHigh, /* lpDistanceToMoveHigh */
FILE_BEGIN /* dwMoveMethod */
);
if ( GetLastError() != NO_ERROR ) {
TCHAR *msg = w32_errstr(0);
printf( "PHYIO_READ: SetFilePointer() failed: %s\n",
msg );
DWORD BytesRead;
__int64 distance;
LARGE_INTEGER li;
distance = (((__int64)sector) * dev->blockspersector) << 9;
li.QuadPart = distance;
if( SetFilePointer( dev->API.Win32.handle,/* hFile */
li.LowPart, /* lDistanceToMove */
&li.HighPart, /* lpDistanceToMoveHigh */
FILE_BEGIN /* dwMoveMethod */
) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ) {
TCHAR *msg = w32_errstr(NO_ERROR);
printf( "PHYIO_READ: SetFilePointer() failed at sector %lu: %s\n",
sector, msg );
LocalFree(msg);
sts = SS$_PARITY;
}
@ -607,9 +610,14 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) {
&BytesRead, /* lpNumberOfBytesRead */
NULL /* lpOverlapped */
) || BytesRead != dev->bytespersector ) {
TCHAR *msg = w32_errstr(0);
printf( "PHYIO_READ: ReadFile() failed: %s\n",
msg );
TCHAR *msg;
if( BytesRead == 0 )
return SS$_ENDOFFILE;
msg = w32_errstr(NO_ERROR);
printf( "PHYIO_READ: ReadFile() failed at sector %lu: %s\n",
sector, msg );
LocalFree(msg);
sts = SS$_PARITY;
}
@ -641,7 +649,7 @@ static unsigned phy_getsect( struct DEV *dev, unsigned sector ) {
NULL /* lpOverlapped */
) && !( reg.reg_Flags & 0x0001 );
if ( !result ) {
TCHAR *msg = w32_errstr(0);
TCHAR *msg = w32_errstr(NO_ERROR);
printf( "PHYIO_READ: Read sector %d failed: %s\n",
sector, msg );
LocalFree(msg);
@ -672,34 +680,33 @@ static unsigned phy_putsect( struct DEV *dev, unsigned sector ) {
#endif
{
if ( dev->access & MOU_VIRTUAL || is_NT ) {
DWORD DistanceLow, DistanceHigh, BytesWritten;
DistanceLow = ( sector * dev->blockspersector ) << 9;
DistanceHigh = ( sector * dev->blockspersector ) >> 23;
SetLastError( 0 );
SetFilePointer( dev->API.Win32.handle, /* hFile */
DistanceLow, /* lDistanceToMove */
&DistanceHigh, /* lpDistanceToMoveHigh */
FILE_BEGIN /* dwMoveMethod */
);
if ( GetLastError() != NO_ERROR ) {
TCHAR *msg = w32_errstr(0);
printf( "PHYIO_WRITE: SetFilePointer() failed: %s\n",
msg );
DWORD BytesWritten;
__int64 distance;
LARGE_INTEGER li;
distance = (((__int64)sector) * dev->blockspersector) << 9;
li.QuadPart = distance;
if( SetFilePointer( dev->API.Win32.handle,/* hFile */
li.LowPart, /* lDistanceToMove */
&li.HighPart, /* lpDistanceToMoveHigh */
FILE_BEGIN /* dwMoveMethod */
) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ) {
TCHAR *msg = w32_errstr(NO_ERROR);
printf( "PHYIO_WRITE: SetFilePointer() failed at sector %lu: %s\n",
sector, msg );
LocalFree(msg);
sts = SS$_PARITY;
}
if ( sts & STS$M_SUCCESS ) {
/* hFile */
if ( !WriteFile( dev->API.Win32.handle,
dev->IoBuffer, /* lpBuffer */
/* nNumberOfBytesToWrite */
if ( !WriteFile( dev->API.Win32.handle, /* hFile */
dev->IoBuffer, /* lpBuffer */
/* nNumberOfBytesToWrite */
dev->bytespersector,
&BytesWritten, /* lpNumberOfBytesWritten */
NULL /* lpOverlapped */
&BytesWritten, /* lpNumberOfBytesWritten */
NULL /* lpOverlapped */
) || BytesWritten != dev->bytespersector ) {
TCHAR *msg = w32_errstr(0);
printf( "PHYIO_WRITE: WriteFile() failed: %s\n",
msg );
TCHAR *msg = w32_errstr(NO_ERROR);
printf( "PHYIO_WRITE: WriteFile() failed at sector %lu: %s\n",
sector, msg );
LocalFree(msg);
sts = SS$_PARITY;
}
@ -730,7 +737,7 @@ static unsigned phy_putsect( struct DEV *dev, unsigned sector ) {
NULL /* lpOverlapped */
) && !( reg.reg_Flags & 0x0001 );
if ( !result ) {
TCHAR *msg = w32_errstr(0);
TCHAR *msg = w32_errstr(NO_ERROR);
printf( "PHYIO_WRITE: Write sector %d failed: %s\n",
sector, msg );
LocalFree(msg);
@ -751,7 +758,7 @@ void phyio_show( showtype_t type ) {
init_count, read_count, write_count );
return;
case SHOW_FILE64:
printf( "\nLarge ODS-2 image files (>2GB) are supported.\n" );
printf( "Large ODS-2 image files (>2GB) are %ssupported.\n", "" );
return;
case SHOW_DEVICES: {
TCHAR *namep = NULL, *dname = NULL;
@ -793,8 +800,8 @@ void phyio_show( showtype_t type ) {
free(namep);
}
}
}
return;
}
default:
abort();
}
@ -934,15 +941,15 @@ unsigned phyio_init( struct DEV *dev ) {
);
}
if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE ) {
TCHAR *msg = w32_errstr(0);
TCHAR *msg = w32_errstr(NO_ERROR);
printf( "PHYIO_INIT: Open( \"%s\" ) failed: %s\n",
dev->devnam, msg );
LocalFree(msg);
return SS$_NOSUCHDEV;
}
if ( !LockVolume( dev ) ) {
TCHAR *msg = w32_errstr(0);
printf( "PHYIO_INIT: LockVolume( \"%s\" ) failed: %a\n",
TCHAR *msg = w32_errstr(NO_ERROR);
printf( "PHYIO_INIT: LockVolume( \"%s\" ) failed: %s\n",
dev->devnam, msg );
LocalFree(msg);
phyio_done( dev );
@ -950,7 +957,7 @@ unsigned phyio_init( struct DEV *dev ) {
}
}
if ( !GetDiskGeometry( dev, &dev->sectors, &dev->bytespersector ) ) {
TCHAR *msg = w32_errstr(0);
TCHAR *msg = w32_errstr(NO_ERROR);
printf( "PHYIO_INIT: GetDiskGeometry( \"%s\" ) failed: %s\n",
dev->devnam, msg );
LocalFree(msg);
@ -989,6 +996,10 @@ unsigned phyio_init( struct DEV *dev ) {
);
}
if ( dev->API.Win32.handle == INVALID_HANDLE_VALUE ) {
TCHAR *msg = w32_errstr(NO_ERROR);
printf( "PHYIO_INIT: CreateFile() failed for %s: %s\n",
virtual, msg );
LocalFree(msg);
return SS$_NOSUCHFILE;
}
SetLastError( 0 );
@ -1078,8 +1089,8 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
offset = 0;
}
if ( !( sts & STS$M_SUCCESS ) ) {
printf( "PHYIO_READ Error %d Block %d Length %d",
sts, block, length );
printf( "PHYIO_READ Error %s Block %d Length %d",
getmsg(sts, MSG_TEXT), block, length );
#ifdef USE_ASPI
printf( " (ASPI: %x %x %x)",
ASPI_status, ASPI_HaStat, ASPI_TargStat );

View File

@ -111,8 +111,10 @@ static void showdevs( void ) {
free( fs );
continue;
}
if( !S_ISBLK( stb.st_mode ) )
if( !S_ISBLK( stb.st_mode ) ) {
free( fs );
continue;
}
memmove( fs, fs + sizeof( DEV_PREFIX ) -1, len +1 );
unit = ~0;
@ -126,14 +128,17 @@ static void showdevs( void ) {
if( unit < (*list)[i].low )
(*list)[i].low = unit;
}
free( fs );
break;
}
}
if( i >= n ) {
nl = (struct devdat (*)[1])
realloc( list, (n+1) * sizeof( struct devdat ) );
if( nl == NULL )
if( nl == NULL ) {
free( fs );
break;
}
list = nl;
(*list)[n].name = fs;
(*list)[n].low = unit;
@ -206,7 +211,8 @@ void phyio_show( showtype_t type ) {
init_count, read_count, write_count );
return;
case SHOW_FILE64:
printf( "\nLarge ODS-2 image files (>2GB) are supported.\n" );
printf( "Large ODS-2 image files (>2GB) are %ssupported.\n",
(sizeof( off_t ) < 8)? "NOT ": "" );
return;
case SHOW_DEVICES:
printf( " Physical devices\n" );
@ -338,6 +344,9 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
return SS$_PARITY;
}
if ( ( res = read( dev->handle, buffer, length ) ) != length ) {
if( res == 0 ) {
return SS$_ENDOFFILE;
}
perror( "read " );
printf("read failed %" PRIuMAX "u\n", (uintmax_t)res);
return SS$_PARITY;

View File

@ -52,7 +52,7 @@ void virt_show( const char *devnam ) {
unsigned devlen, devsiz;
struct VDEV *vp;
if ( devnam == NULL ) {
if( devnam == NULL ) {
size_t maxd = sizeof( "Device" ) -1,
maxp = sizeof( "File" ) -1,
n;
@ -61,7 +61,7 @@ void virt_show( const char *devnam ) {
printf( " No virtual devices are assigned\n" );
return;
}
for ( vp = virt_device_list; vp != NULL; vp = vp->next ) {
for( vp = virt_device_list; vp != NULL; vp = vp->next ) {
n = strlen( vp->devnam );
if( n > maxd )
maxd = n;
@ -79,23 +79,23 @@ void virt_show( const char *devnam ) {
for( n = 0; n < maxp; n++ ) putchar( '-' );
putchar( '\n' );
for ( vp = virt_device_list; vp != NULL; vp = vp->next ) {
for( vp = virt_device_list; vp != NULL; vp = vp->next ) {
n = strlen( vp->path );
printf( " %-*s %.*s\n", (int)maxd, vp->devnam, (int)maxp,
(n > maxp)? vp->path+(n-maxp): vp->path );
}
} else {
devlen = strlen( devnam );
for ( devsiz = 0; devsiz < devlen; devsiz++ ) {
if ( devnam[devsiz] == ':' ) {
for( devsiz = 0; devsiz < devlen; devsiz++ ) {
if( devnam[devsiz] == ':' ) {
break;
}
}
if ( devsiz == 0 ) {
if( devsiz == 0 ) {
return;
}
for ( vp = virt_device_list; vp != NULL; vp = vp->next ) {
if ( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) {
for( vp = virt_device_list; vp != NULL; vp = vp->next ) {
if( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) {
printf( " %s => %s\n", vp->devnam, vp->path );
return;
}
@ -111,13 +111,13 @@ static int virt_compare( unsigned keylen, const char *keynam,
register int cmp;
cmp = 0;
while ( keylen-- > 0 ) {
while( keylen-- > 0 ) {
cmp = toupper( *keynam++ ) - toupper( *devnam++ );
if ( cmp != 0 ) {
if( cmp != 0 ) {
break;
}
}
if ( cmp == 0 && *devnam != '\0' && *devnam != ':' ) {
if( cmp == 0 && *devnam != '\0' && *devnam != ':' ) {
cmp = -1;
}
return cmp;
@ -133,16 +133,16 @@ char *virt_lookup( const char *devnam ) {
struct VDEV *vp;
devlen = strlen( devnam );
for ( devsiz = 0; devsiz < devlen; devsiz++ ) {
if ( devnam[devsiz] == ':' ) {
for( devsiz = 0; devsiz < devlen; devsiz++ ) {
if( devnam[devsiz] == ':' ) {
break;
}
}
if ( devsiz == 0 ) {
if( devsiz == 0 ) {
return NULL;
}
for ( vp = virt_device_list; vp != NULL; vp = vp->next ) {
if ( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) {
for( vp = virt_device_list; vp != NULL; vp = vp->next ) {
if( virt_compare( devsiz, (char *) devnam, vp->devnam ) == 0 ) {
return vp->path;
}
}
@ -176,21 +176,22 @@ unsigned virt_device( char *devnam, char **vname ) {
}
path = p;
for ( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) {
for( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) {
if( strcmp( (*vpp)->path, path ) == 0 ) {
printf( "%%ODS2-E-MAPPED, %s is in use on virtual drive %s\n", path, (*vpp)->devnam );
free( path );
return SS$_DEVMOUNT;
}
}
}
devlen = strlen( devnam );
for ( devsiz = 0; devsiz < devlen; devsiz++ ) {
if ( devnam[devsiz] == ':' ) {
for( devsiz = 0; devsiz < devlen; devsiz++ ) {
if( devnam[devsiz] == ':' ) {
break;
}
}
if ( devsiz == 0 ) {
if( devsiz == 0 ) {
free( path );
return SS$_BADPARAM;
}
@ -216,21 +217,21 @@ static struct VDEV *virt_insert( const char *devnam, unsigned devsiz,
struct VDEV *vp, **vpp, **here;
here = NULL;
for ( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) {
if ( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) < 0 ) {
for( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) {
if( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) < 0 ) {
here = vpp;
}
}
if ( here == NULL ) {
if( here == NULL ) {
here = vpp;
}
vp = (struct VDEV *) malloc( sizeof( struct VDEV ) );
if ( vp == NULL ) {
if( vp == NULL ) {
return NULL;
}
vp->devnam = (char *) malloc( devsiz + 1 );
vp->path = (char *) malloc( (pathsiz = strlen( path )) + 1 );
if ( vp->devnam == NULL || vp->path == NULL ) {
if( vp->devnam == NULL || vp->path == NULL ) {
free( vp->devnam );
free( vp->path );
free( vp );
@ -251,8 +252,8 @@ static void virt_remove( const char *devnam, unsigned devsiz ) {
struct VDEV *vp, **vpp;
for ( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) {
if ( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) == 0 ) {
for( vpp = &virt_device_list; *vpp != NULL; vpp = &(*vpp)->next ) {
if( virt_compare( devsiz, (char *) devnam, (*vpp)->devnam ) == 0 ) {
vp = *vpp;
*vpp = (*vpp)->next;
free( vp->devnam );

View File

@ -39,6 +39,7 @@
#include <mntdef.h>
#include <rms.h> /* struct FAB */
#include <ssdef.h>
#include <stsdef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -67,15 +68,23 @@ unsigned sys$dassgn();
#include <starlet.h>
#endif
#ifndef SS$_NOMOREDEV
#define SS$_NOMOREDEV 2648
#endif
#ifndef EFN$C_ENF
#define EFN$C_ENF 0 /* 128 in recent VMS */
#endif
#include "ods2.h"
#include "phyio.h"
#include "virtual.h"
struct ITMLST {
unsigned short length;
unsigned short itmcod;
void *buffer;
unsigned long *retlen;
unsigned short length;
unsigned short itmcod;
void *buffer;
unsigned short *retlen;
};
#define chk( sts ) { register chksts; \
@ -83,10 +92,86 @@ struct ITMLST {
lib$stop( chksts ); \
}
#define MSGID(sts) ((sts) & (STS$M_COND_ID|STS$M_SEVERITY))
static unsigned init_count = 0;
static unsigned read_count = 0;
static unsigned write_count = 0;
/*************************************************************** showdevs() */
static void showdevs( void ) {
unsigned long status;
size_t max = 0;
int pass;
max = 0
for( pass = 0; pass < 2; pass++ ) {
unsigned long ctx[2] = { 0, 0 };
size_t col = 0;
unsigned short retlen, iosb[4];
char devnam[64+1],
dspnam[64+1];
struct dsc$descriptor_s retdsc = { sizeof( devnam ) -1,
DSC$K_DTYPE_T,
DSC$K_CLASS_S, devnam };
$DESCRIPTOR( searchdsc, "*" );
unsigned long devclass = DC$_DISK;
struct ITMLST scanlist[] = {
{ sizeof( devclass ), DC$_DISK, &devclass, NULL },
{ 0, 0, NULL, NULL }
};
struct ITMLST dvilist[] = {
{ sizeof( dspnam ) -1, DVI$_DISPLAY_DEVNAM, dspnam, &retlen },
{ 0, 0, NULL, NULL }
};
while( 1 ) {
char *name;
size_t len;
status = sys$device_scan( &retdsc, &retlen,
&searchdsc, scanlist, &ctx );
if( MSGID(status) != SS$_NORMAL )
break;
name = devnam;
name[retlen] = '\0';
len = retlen;
status = sys$getdviw( EFN$C_ENF, 0, &retdsc, dvilist, iosb,
NULL, 0, NULL );
if( MSGID(status) == SS$_NORMAL ) {
name = dspnam;
dspnam[retlen] = '\0';
len = retlen;
}
if( pass == 0 ) {
if( len > max )
max = len;
continue;
}
if( col + max > 75 ) {
putchar( '\n' );
col = 0;
}
col += 1+ max;
printf( " %-*s", (int)max, name );
}
}
switch( MSGID(status) ) {
case SS$_NOMOREDEV:
break;
case SS$_NOSUCHDEV:
printf( "No devices found\n" );
case SS$_NORMAL:
break;
default:
printf( "%%ODS2-W-ERRDEV, Error scanning devices: %s\n",
getmsg( status, MSG_TEXT ) );
break;
}
return;
}
/*************************************************************** phyio_show() */
void phyio_show( showtype_t type ) {
@ -96,13 +181,12 @@ void phyio_show( showtype_t type ) {
init_count, read_count, write_count );
return;
case SHOW_FILE64:
printf( "\nLarge ODS-2 image files (>2GB) are supported.\n" );
printf( "Large ODS-2 image files (>2GB) are %ssupported.\n",
(sizeof( off_t ) < 8)? "NOT ": "" );
return;
case SHOW_DEVICES:
#if 0 /* VMS doesn't make listing devices easy */
printf( " Physical devices\n" );
showdevs();
#endif
return;
default:
abort();
@ -178,6 +262,7 @@ unsigned phyio_init( struct DEV *dev ) {
unsigned long devclass, cylinders, tracks, sectors;
char devname[65];
unsigned long devchar;
unsigned short iosb[4];
struct ITMLST dvi_itmlst[7] = {
{ sizeof( devclass ), DVI$_DEVCLASS, &devclass, NULL },
{ sizeof( devname ), DVI$_ALLDEVNAM, &devname, NULL },
@ -191,7 +276,7 @@ unsigned phyio_init( struct DEV *dev ) {
/* Get some device information: device name, class, and mount status */
devdsc.dsc$w_length = strlen( dev->devnam );
devdsc.dsc$a_pointer = dev->devnam;
sts = sys$getdviw( 0, 0, &devdsc, &dvi_itmlst, 0, 0, 0, 0 );
sts = sys$getdviw( EFN$C_ENF, 0, &devdsc, &dvi_itmlst, iosb, 0, 0, 0 );
if ( !( sts & STS$M_SUCCESS ) ) {
return sts;
}
@ -295,6 +380,9 @@ unsigned phyio_read( struct DEV *dev, unsigned block, unsigned length,
return SS$_PARITY;
}
if ( ( res = read( dev->handle, buffer, length ) ) != length ) {
if( res == 0 ) {
return SS$_ENDOFFILE;
}
perror( "read " );
printf( "read failed %d\n", res );
return SS$_PARITY;

View File

@ -37,6 +37,7 @@
#include "ssdef.h"
#include "stsdef.h"
#include "compat.h"
#include "sysmsg.h"
#ifndef TRUE
#define TRUE ( 0 == 0 )
@ -455,6 +456,7 @@ unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile)
wcc->wcd_reslen - 6,".DIR;1",6);
} else {
sts = RMS$_NMF;
cleanup_wcf(&wccfile);
break; /* giveup */
}
}
@ -753,7 +755,13 @@ unsigned do_parse(struct FAB *fab,struct WCCFILE **wccret)
}
if (wccret != NULL) *wccret = wccfile;
if (nam != NULL) {
nam->nam$l_wcc = wccfile;
if( (nam->nam$b_nop & NAM$M_SYNCHK) &&
!fab->fab$b_dns && !nam->nam$l_rlf ) {
cleanup_wcf(&wccfile);
if( wccret ) *wccret = NULL;
} else {
nam->nam$l_wcc = wccfile;
}
}
return SS$_NORMAL;
}
@ -795,14 +803,21 @@ unsigned sys_setddir(struct dsc_descriptor *newdir,unsigned short *oldlen,
sts = sys_parse(&fab);
if (sts & STS$M_SUCCESS) {
if (nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver > 2) {
return RMS$_DIR;
sts = RMS$_DIR;
} else {
if (nam.nam$l_fnb & NAM$M_WILDCARD)
sts = RMS$_WLD;
else {
default_name = default_buffer;
default_size[0] = nam.nam$b_dev;
default_size[1] = nam.nam$b_dir;
memcpy(default_name + nam.nam$b_dev + nam.nam$b_dir,".;",3);
}
}
if (nam.nam$l_fnb & NAM$M_WILDCARD) return RMS$_WLD;
default_name = default_buffer;
default_size[0] = nam.nam$b_dev;
default_size[1] = nam.nam$b_dir;
memcpy(default_name + nam.nam$b_dev + nam.nam$b_dir,".;",3);
}
fab.fab$b_dns = 0;
nam.nam$l_rlf = 0;
sys$parse( &fab );
}
return sts;
}
@ -1473,3 +1488,18 @@ unsigned sys_extend(struct FAB *fab)
fab->fab$l_alq - ifi_table[ifi_no]->wcf_fcb->hiblock,0);
return sts;
}
/*************************************************************** sys_initialize() */
static void sys_rundown( void ) {
access_rundown();
sysmsg_rundown();
}
/*************************************************************** sys_initialize() */
unsigned sys_initialize( void ) {
if( atexit( sys_rundown ) != 0 )
return SS$_INSFMEM;
return SS$_NORMAL;
}

View File

@ -15,6 +15,8 @@
#include "vmstime.h"
#define RMS$_FACILITY 1
#define RMS$_RTB 98728
#define RMS$_EOF 98938
#define RMS$_FNF 98962
@ -170,10 +172,11 @@ struct NAM {
void *nam$l_wcc;
int nam$b_nop;
int nam$l_fnb;
struct NAM *nam$l_rlf;
};
#ifdef RMS$INITIALIZE
struct NAM cc$rms_nam = {0,0,0,0,0,0,0,0,0,0,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,0,0};
struct NAM cc$rms_nam = {0,0,0,0,0,0,0,0,0,0,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0,0,0,NULL};
#else
extern struct NAM cc$rms_nam;
#endif
@ -317,4 +320,6 @@ unsigned sys_extend(struct FAB *fab);
unsigned sys_setddir(struct dsc_descriptor *newdir,unsigned short *oldlen,
struct dsc_descriptor *olddir);
unsigned sys_initialize(void);
#endif /* #ifndef _RMS_H */

View File

@ -13,6 +13,8 @@
#ifndef _SSDEF_H
#define _SSDEF_H
#define SYSTEM$_FACILITY 0
#define SS$_NORMAL 1
#define SS$_WASCLR 1
#define SS$_WASSET 9
@ -45,6 +47,7 @@
#define SS$_NOSUCHFILE 2320
#define SS$_NOMOREFILES 2352
#define SS$_ITEMNOTFOUND 2640
#define SS$_NOMOREDEV 2648
#define SS$_NOSUCHVOL 3882
#define SS$_NOTINSTALL 8212
#define SS$_DEVNOTDISM 8628

View File

@ -5,6 +5,52 @@
#ifndef _STSDEF_H
#define _STSDEF_H
#define STS$M_SUCCESS 1
#define STS$V_SEVERITY 0
#define STS$M_SEVERITY 0x00000007
#define STS$S_SEVERITY 3
#define STS$V_COND_ID 3
#define STS$M_COND_ID 0x0FFFFFF8
#define STS$S_COND_ID 25
#define STS$V_CONTROL 28
#define STS$M_CONTROL 0xF0000000
#define STS$S_CONTROL 4
#define STS$V_SUCCESS 0
#define STS$M_SUCCESS 0x01
#define STS$S_SUCCESS 1
#define STS$V_MSG_NO 3
#define STS$M_MSG_NO 0x0000FFF8
#define STS$S_MSG_NO 13
#define STS$V_CODE 3
#define STS$M_CODE 0x00007FF8
#define STS$S_CODE 12
#define STS$V_FAC_SP 15
#define STS$M_FAC_SP 0x00008000
#define STS$S_FAC_SP 1
#define STS$V_CUST_DEF 27
#define STS$M_CUST_DEF 0x08000000
#define STS$S_CUST_DEF 1
#define STS$V_INHIB_MSG 28
#define STS$M_INHIB_MSG 0x10000000
#define STS$S_INHIB_MSG 1
#define STS$V_FAC_NO 16
#define STS$M_FAC_NO 0x0FFF0000
#define STS$S_FAC_NO 12
#define STS$K_WARNING 0
#define STS$K_SUCCESS 1
#define STS$K_ERROR 2
#define STS$K_INFO 3
#define STS$K_SEVERE 4
#define $VMS_STATUS_CODE(code) ( ( (code) & STS$M_CODE ) >> STS$V_CODE )
#define $VMS_STATUS_COND_ID(code) ( ( (code) & STS$M_COND_ID ) >> STS$V_COND_ID )
#define $VMS_STATUS_CONTROL(code) ( ( (code) & STS$M_CONTROL ) >> STS$V_CONTROL )
#define $VMS_STATUS_CUST_DEF(code) ( ( (code) & STS$M_CUST_DEF ) >> STS$V_CUST_DEF )
#define $VMS_STATUS_FAC_NO(code) ( ( (code) & STS$M_FAC_NO ) >> STS$V_FAC_NO )
#define $VMS_STATUS_FAC_SP(code) ( ( (code) & STS$M_FAC_SP ) >> STS$V_FAC_SP )
#define $VMS_STATUS_INHIB_MSG(code) ( ( (code) & STS$M_INHIB_MSG ) >> STS$V_INHIB_MSG )
#define $VMS_STATUS_MSG_NO(code) ( ( (code) & STS$M_MSG_NO ) >> STS$V_MSG_NO )
#define $VMS_STATUS_SEVERITY(code) ( ( (code) & STS$M_SEVERITY ) >> STS$V_SEVERITY )
#define $VMS_STATUS_SUCCESS(code) ( ( (code) & STS$M_SUCCESS ) >> STS$V_SUCCESS )
#endif /* #ifndef _STSDEF_H */

View File

@ -1,7 +1,18 @@
/* Timothe Litt litt _at_ acm _ddot_ org */
/*
This is part of ODS2 written by Paul Nankervis,
email address: Paulnank@au1.ibm.com
ODS2 is distributed freely for all members of the
VMS community to use. However all derived works
must maintain comments in their source to acknowledge
the contibution of the original author.
*/
/* Message code translations for non-VMS systems */
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -16,83 +27,226 @@
#include "compat.h"
#include "sysmsg.h"
#define MSG(code,text) { $VMS_STATUS_COND_ID(code), #code, text },
static
const struct VMSFAC {
unsigned int code;
const char *const text;
} fac2text[] = {
{ SYSTEM$_FACILITY, "SYSTEM" },
{ RMS$_FACILITY, "RMS" },
{ 0, NULL },
{ 0, "NONAME" }
};
static const char sev2text[(STS$M_SEVERITY>>STS$V_SEVERITY)+1] =
{ 'W', 'S', 'E', 'I', 'F', '?', '?', '?', };
/* Unknown facility or message code */
#ifndef SS$_NOMSG
#define SS$_NOMSG 0xFFFFFFFF
#endif
static const char nofmt[] = "Message number %08X";
static char notext[sizeof(nofmt)+8];
static
const struct VMSMSG {
unsigned int code;
const char *const text;
} *mp, vms2text[] = {
{RMS$_BUG, "%RMS-F-BUG, fatal RMS condition detected, process deleted"},
{RMS$_DIR, "%RMS-F-DIR, error in directory name"},
{RMS$_DNF, "%RMS-E-DNF, directory not found"},
{RMS$_EOF, "%RMS-E-EOF, end of file detected"},
{RMS$_ESS, "%RMS-F-ESS, expanded string area too small"},
{RMS$_FNF, "%RMS-E-FNF, file not found"},
{RMS$_FNM, "%RMS-F-FNM, error in file name"},
{RMS$_IFI, "%RMS-F-IFI, invalid internal file identifier (IFI) value"},
{RMS$_NAM, "%RMS-F-NAM, invalid NAM block or NAM block not accessible"},
{RMS$_NMF, "%RMS-E-NMF, no more files found"},
{RMS$_RSS, "%RMS-F-RSS, invalid resultant string size"},
{RMS$_RSZ, "%RMS-F-RSZ, invalid record size"},
{RMS$_RTB, "%RMS-W-RTB, !UL byte record too large for user's buffer"},
{RMS$_WCC, "%RMS-E-WCC, invalid wild card context (WCC) value"},
{RMS$_WLD, "%RMS-F-WLD, invalid wildcard operation"},
{SS$_ABORT, "%SYSTEM-F-ABORT, abort"},
{SS$_BADFILENAME, "%SYSTEM-W-BADFILENAME, bad file name syntax"},
{SS$_BADIRECTORY, "%SYSTEM-W-BADIRECTORY, bad directory file format"},
{SS$_BADPARAM, "%SYSTEM-F-BADPARAM, bad parameter value"},
{SS$_BUGCHECK, "%SYSTEM-F-BUGCHECK, internal consistency failure"},
{SS$_DATACHECK, "%SYSTEM-F-DATACHECK, write check error"},
{SS$_DEVICEFULL, "%SYSTEM-W-DEVICEFULL, device full - allocation failure"},
{SS$_DEVMOUNT, "%SYSTEM-F-DEVMOUNT, device is already mounted"},
{SS$_DEVNOTALLOC, "%SYSTEM-W-DEVNOTALLOC, device not allocated"},
{SS$_DEVNOTDISM, "%SYSTEM-F-DEVNOTDISM, device not dismounted"},
{SS$_DEVNOTMOUNT, "%SYSTEM-F-DEVNOTMOUNT, device is not mounted"},
{SS$_DUPFILENAME, "%SYSTEM-W-DUPFILENAME, duplicate file name"},
{SS$_DUPLICATE, "%SYSTEM-F-DUPLNAM, duplicate name"},
{SS$_ENDOFFILE, "%SYSTEM-W-ENDOFFILE, end of file"},
{SS$_FILELOCKED, "%SYSTEM-W-FILELOCKED, file is deaccess locked"},
{SS$_FILESEQCHK, "%SYSTEM-W-FILESEQCHK, file identification sequence number check"},
{SS$_ILLEFC, "%SYSTEM-F-ILLEFC, illegal event flag cluster"},
{SS$_INSFMEM, "%SYSTEM-F-INSFMEM, insufficient dynamic memory"},
{SS$_ITEMNOTFOUND, "%SYSTEM-W-ITEMNOTFOUND, requested item cannot be returned"},
{SS$_IVCHAN, "%SYSTEM-F-IVCHAN, invalid I/O channel"},
{SS$_IVDEVNAM, "%SYSTEM-F-IVDEVNAM, invalid device name"},
{SS$_NOIOCHAN, "%SYSTEM-F-NOIOCHAN, no I/O channel available"},
{SS$_NOMOREFILES, "%SYSTEM-W-NOMOREFILES, no more files"},
{SS$_NORMAL, "%SYSTEM-S-NORMAL, normal successful completion"},
{SS$_NOSUCHDEV, "%SYSTEM-W-NOSUCHDEV, no such device available"},
{SS$_NOSUCHFILE, "%SYSTEM-W-NOSUCHFILE, no such file"},
{SS$_NOSUCHVOL, "%SYSTEM-E-NOSUCHVOL, No such volume"},
{SS$_NOTINSTALL, "%SYSTEM-F-NOTINSTALL, writable shareable images must be installed"},
{SS$_PARITY, "%SYSTEM-F-PARITY, parity error"},
{SS$_UNSUPVOLSET, "%SYSTEM-E-UNSUPVOLSET, Volume set not supported"},
{SS$_WASCLR, "%SYSTEM-S-NORMAL, normal successful completion"},
{SS$_WASSET, "%SYSTEM-S-WASSET, Event flag was set"},
{SS$_WRITLCK, "%SYSTEM-F-WRITLCK, write lock error"},
{SS$_OFFSET_TOO_BIG, "SYSTEM-F-OFFSET_TOO_BIG, Volume is too large for local file system: needs 64-bit I/O" },
{0, NULL},
};
unsigned int code;
const char *const txtcode;
char *text;
} vms2text[] = {
MSG(RMS$_BUG, "fatal RMS condition detected, process deleted")
MSG(RMS$_DIR, "error in directory name")
MSG(RMS$_DNF, "directory not found")
MSG(RMS$_EOF, "end of file detected")
MSG(RMS$_ESS, "expanded string area too small")
MSG(RMS$_FNF, "file not found")
MSG(RMS$_FNM, "error in file name")
MSG(RMS$_IFI, "invalid internal file identifier (IFI) value")
MSG(RMS$_NAM, "invalid NAM block or NAM block not accessible")
MSG(RMS$_NMF, "no more files found")
MSG(RMS$_RSS, "invalid resultant string size")
MSG(RMS$_RSZ, "invalid record size")
MSG(RMS$_RTB, "%u byte record too large for user's buffer") /* !UL byte */
MSG(RMS$_WCC, "invalid wild card context (WCC) value")
MSG(RMS$_WLD, "invalid wildcard operation")
MSG(SS$_ABORT, "abort")
MSG(SS$_BADFILENAME, "bad file name syntax")
MSG(SS$_BADIRECTORY, "bad directory file format")
MSG(SS$_BADPARAM, "bad parameter value")
MSG(SS$_BUGCHECK, "internal consistency failure")
MSG(SS$_DATACHECK, "write check error")
MSG(SS$_DEVICEFULL, "device full - allocation failure")
MSG(SS$_DEVMOUNT, "device is already mounted")
MSG(SS$_DEVNOTALLOC, "device not allocated")
MSG(SS$_DEVNOTDISM, "device not dismounted")
MSG(SS$_DEVNOTMOUNT, "device is not mounted")
MSG(SS$_DUPFILENAME, "duplicate file name")
MSG(SS$_DUPLICATE, "duplicate name")
MSG(SS$_ENDOFFILE, "end of file")
MSG(SS$_FILELOCKED, "file is deaccess locked")
MSG(SS$_FILESEQCHK, "file identification sequence number check")
MSG(SS$_ILLEFC, "illegal event flag cluster")
MSG(SS$_INSFMEM, "insufficient dynamic memory")
MSG(SS$_ITEMNOTFOUND, "requested item cannot be returned")
MSG(SS$_NOMOREDEV, "no more devices")
MSG(SS$_IVCHAN, "invalid I/O channel")
MSG(SS$_IVDEVNAM, "invalid device name")
MSG(SS$_NOIOCHAN, "no I/O channel available")
MSG(SS$_NOMOREFILES, "no more files")
MSG(SS$_NORMAL, "normal successful completion")
MSG(SS$_NOSUCHDEV, "no such device available")
MSG(SS$_NOSUCHFILE, "no such file")
MSG(SS$_NOSUCHVOL, "No such volume")
MSG(SS$_NOTINSTALL, "writable shareable images must be installed")
MSG(SS$_PARITY, "parity error")
MSG(SS$_UNSUPVOLSET, "Volume set not supported")
MSG(SS$_WASCLR, "normal successful completion")
MSG(SS$_WASSET, "Event flag was set")
MSG(SS$_WRITLCK, "write lock error")
MSG(SS$_OFFSET_TOO_BIG, "Volume is too large for local file system: needs 64-bit I/O" )
{0, NULL, NULL},
{ SS$_NOMSG, "SS$_NOMSG", notext }
};
const char *getmsg( unsigned int vmscode, unsigned int flags ) {
const char fmt[] = "%%SYSTEM-E-NOSUCHMSG, Unknown message code %08X";
static char buf[sizeof(fmt)+8+1];
const char *txtp = NULL;
static char *buf = NULL;
static size_t bufsize = 0;
for( mp = vms2text; mp->text; mp++ ) {
if( vmscode == mp-> code ) {
txtp = mp->text;
break;
}
/******************************************************************* xpand() */
static int xpand( size_t used, size_t add ) {
char *nbuf;
size_t need;
need = used + add + 1; /* Always allow for \0 */
if( need < bufsize ) {
return 1;
}
if( txtp == NULL ) {
txtp = buf;
nbuf = realloc( buf, need + 16 + 1); /* 16 minimizes reallocs */
if( nbuf == NULL ) {
return 0;
}
if( flags == MSG_TEXT ) {
txtp = strchr( txtp, ',' );
if( txtp == NULL ) abort();
return txtp+2;
buf = nbuf;
bufsize = need + 16 + 1;
return 1;
}
/******************************************************************* getmsg() */
const char *getmsg( unsigned int vmscode, unsigned int flags, ... ) {
const struct VMSMSG *mp = NULL;
const struct VMSFAC *fp = NULL;
if( !(flags & MSG_FULL) )
flags = (flags & ~MSG_FULL) | MSG_FULL;
while( 1 ) {
size_t i = 0, len;
do {
if( flags & (MSG_FACILITY|MSG_SEVERITY|MSG_NAME) ) {
if( !xpand( i, 1 ) )
return strerror( errno );
buf[i++] = '%';
if( fp == NULL ) {
for( fp = fac2text; fp->text != NULL; fp++ ) {
if( fp->code == $VMS_STATUS_FAC_NO(vmscode) )
break;
}
}
if( fp->text == NULL )
break;
if( flags & MSG_FACILITY ) {
len = strlen( fp->text );
if( !xpand( i, len +1 ) )
return strerror( errno );
memcpy( buf+i, fp->text, len );
i += len;
if( flags & (MSG_SEVERITY|MSG_NAME) )
buf[i++] = '-';
}
if( flags & MSG_SEVERITY ) {
if( !xpand( i, 2 ) )
return strerror( errno );
buf[i++] = sev2text[$VMS_STATUS_SEVERITY(vmscode)];
if( flags & MSG_NAME )
buf[i++] = '-';
}
if( flags & MSG_NAME ) {
char *p;
if( mp == NULL ) {
for( mp = vms2text; mp->text != NULL; mp++ ) {
if( $VMS_STATUS_COND_ID(vmscode) == mp-> code )
break;
}
}
if( mp->text == NULL )
break;
p = strchr( mp->txtcode, '_' );
if( p == NULL )
abort();
len = strlen( ++p );
if( !xpand( i, len ) )
return strerror( errno );
memcpy( buf+i, p, len );
i += len;
}
if( flags & MSG_TEXT ) {
if( !xpand( i, 2 ) )
return strerror( errno );
buf[i++] = ',';
buf[i++] = ' ';
}
}
if( flags & MSG_TEXT ) {
va_list ap;
if( mp == NULL ) {
for( mp = vms2text; mp->text; mp++ ) {
if( $VMS_STATUS_COND_ID(vmscode) == mp-> code )
break;
}
if( mp->text == NULL )
break;
}
if( flags & MSG_WITHARGS ) {
va_start( ap, flags );
len = vsnprintf( buf+i, 1, mp->text, ap );
va_end( ap );
} else
len = strlen( mp->text );
if( !xpand( i, len ) )
return strerror( errno );
if( flags & MSG_WITHARGS ) {
va_start( ap, flags );
(void) vsnprintf( buf+i, len+1, mp->text, ap );
va_end( ap );
} else
memcpy( buf+i, mp->text, len );
i += len;
}
buf[i] = '\0';
return buf;
} while( 0 );
if( fp == NULL || fp->text == NULL )
fp = fac2text + (sizeof(fac2text)/sizeof(fac2text[0])) -1;
mp = vms2text + (sizeof(vms2text)/sizeof(vms2text[0])) -1;
snprintf( notext, sizeof(notext), nofmt, vmscode );
}
return txtp;
}
/******************************************************************* sysmsg_rundown() */
void sysmsg_rundown( void ) {
free( buf );
buf = NULL;
}
/*

View File

@ -1,8 +1,18 @@
#ifndef SYSMSG_H
#define SYSMSG_H
#define MSG_TEXT 0
#define MSG_FULL 1
const char *getmsg( unsigned int vmscode, unsigned int flags );
#include <stdarg.h>
#define MSG_FACILITY (1 << 0)
#define MSG_SEVERITY (1 << 1)
#define MSG_NAME (1 << 2)
#define MSG_TEXT (1 << 3)
#define MSG_WITHARGS (1 << 4)
#define MSG_FULL (MSG_FACILITY|MSG_SEVERITY|MSG_NAME|MSG_TEXT)
const char *getmsg( unsigned int vmscode, unsigned int flags, ... );
void sysmsg_rundown( void );
#endif

View File

@ -0,0 +1,2 @@
# suppression rules for ods2
# The goal is that there aren't any.

View File

@ -0,0 +1,46 @@
# Suppression rules for users of readline
# This attempts to suppress the stuff that
# readline creates from termcap, etc, while
# still tracking the data returned to the caller.
#
# Most history memory can be released with the
# clear_history() call - after write_history
# if desired. However, the master history
# structure remains. Don't know how to
# distinguish the two, so the history calls
# that add lines are suppressed. Note
# that read_history calls add_history internally.
{
history
Memcheck:Leak
match-leak-kinds: reachable
...
fun:add_history
}
{
readline
Memcheck:Leak
match-leak-kinds: reachable
...
fun:rl_initialize
...
fun:readline
}
{
readline
Memcheck:Leak
match-leak-kinds: reachable
...
fun:init_line_structures
...
fun:readline
}
{
readline
Memcheck:Leak
match-leak-kinds: reachable
...
fun:rl_set_prompt
fun:readline
}