mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-22 18:41:42 +00:00
Too much to list all, but includes (in no particular order): - Cleanup for 64-bit builds, MSVC warnings. - Structured help - Help file compiler. - Supports volsets, writes/create work. - Support for I18n in messages, help. - Makefiles. - Initialize volume/volset - Command line editing/history Builds and works on Linux and Windows (VS). Not recently built or tested on other platforms, but not intentinonally broken.
1476 lines
46 KiB
C
1476 lines
46 KiB
C
|
|
/* This is part of ODS2, originally 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 contributions of the original author and
|
|
* subsequent contributors. This is free software; no
|
|
* warranty is offered, and while we believe it to be useful,
|
|
* you use it at your own risk.
|
|
*/
|
|
|
|
#if !defined( DEBUG ) && defined( DEBUG_COPYCMD )
|
|
#define DEBUG DEBUG_COPYCMD
|
|
#else
|
|
#ifndef DEBUG
|
|
#define DEBUG 0
|
|
#endif
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include "winfile.h"
|
|
#define basename winbasename
|
|
#undef fstat
|
|
#define fstat _fstat
|
|
#elif defined(VMS)
|
|
#include "vmsfile.h"
|
|
#define basename vmsbasename
|
|
#else
|
|
#include <glob.h>
|
|
#include <libgen.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifndef GLOB_BRACE
|
|
#define GLOB_BRACE 0
|
|
#endif
|
|
#ifndef GLOB_TILDE_CHECK
|
|
#define GLOB_TILDE_CHECK 0
|
|
#endif
|
|
|
|
#include "cmddef.h"
|
|
|
|
static vmscond_t copy_from( options_t options, int argc, char **argv );
|
|
static vmscond_t copy_1_from( options_t options, struct FAB *fab,
|
|
const char *to, size_t pause );
|
|
static vmscond_t put_prn( char ch, FILE *tof, pause_t *pause );
|
|
|
|
static vmscond_t copy_to( options_t options, int argc, char **argv );
|
|
static vmscond_t copy_1_to( options_t options, char *from, char *to );
|
|
|
|
char *output_file_name( const char *ofname, const char *ifname, int *flags );
|
|
#define OF_WILD 1
|
|
|
|
static int xpand( char **buf, size_t size[2], size_t add );
|
|
|
|
/******************************************************************* dotype() */
|
|
|
|
/* Display a file on the terminal */
|
|
|
|
#define type_page OPT_SHARED_20
|
|
#define type_one OPT_SHARED_19
|
|
#define copy_vfc OPT_SHARED_18
|
|
|
|
static uint32_t height;
|
|
|
|
qual_t typequals[] = { {"page", type_page, 0, VOPT(DV(&height)),
|
|
"-commands type qual_page"},
|
|
{"nopage", 0, type_page, NV, NULL},
|
|
{"onefile", type_one, 0, NV, NULL},
|
|
{"vfc_header", copy_vfc, 0, NV,
|
|
"-commands type qual_vfc"},
|
|
{"novfc_header", 0, copy_vfc, NV, NULL},
|
|
|
|
{NULL, 0, 0, NV, NULL }
|
|
};
|
|
|
|
param_t typepars[] = { {"filespec", REQ | NOLIM, FSPEC, NOPA, "commands type filespec"},
|
|
|
|
{ NULL, 0, 0, NOPA, NULL }
|
|
};
|
|
|
|
DECL_CMD(type) {
|
|
vmscond_t sts;
|
|
int theight;
|
|
options_t options;
|
|
struct FAB fab = cc$rms_fab;
|
|
struct NAM nam = cc$rms_nam;
|
|
char esa[NAM$C_MAXRSS + 1], rsa[NAM$C_MAXRSS + 1];
|
|
|
|
(void) termchar( NULL, &theight );
|
|
height = theight-1;
|
|
|
|
if( $FAILS(sts = checkquals( &options, type_page, typequals, qualc, qualv )) ) {
|
|
return sts;
|
|
}
|
|
if( !(options & type_page) ) {
|
|
height = 0;
|
|
}
|
|
|
|
--argc;
|
|
++argv;
|
|
while( $SUCCESSFUL(sts) && argc-- ) {
|
|
nam.nam$l_esa = esa;
|
|
nam.nam$b_ess = NAM$C_MAXRSS;
|
|
|
|
fab.fab$l_fna = argv++[0];
|
|
fab.fab$b_fns = (uint8_t)strlen(fab.fab$l_fna);
|
|
|
|
if( options & type_one ) { /* RMS test/debug: implicit parse/search */
|
|
if( $FAILS(sts = sys_open(&fab)) ) {
|
|
nam.nam$l_rsa[nam.nam$b_rsl] = '\0';
|
|
printmsg( TYPE_OPENIN, 0, nam.nam$l_rsa );
|
|
sts = printmsg( sts, MSG_CONTINUE, TYPE_OPENIN );
|
|
break;
|
|
}
|
|
sts = copy_1_from( options & copy_vfc, &fab, NULL, height );
|
|
sys_close(&fab);
|
|
continue;
|
|
}
|
|
fab.fab$l_nam = &nam;
|
|
|
|
if( $FAILS(sts = sys_parse(&fab)) ) {
|
|
fab.fab$l_fna[fab.fab$b_fns] = '\0';
|
|
printmsg( TYPE_PARSEFAIL, 0, fab.fab$l_fna );
|
|
sts = printmsg( sts, MSG_CONTINUE, TYPE_PARSEFAIL );
|
|
break;
|
|
}
|
|
|
|
nam.nam$l_rsa = rsa;
|
|
nam.nam$b_rss = NAM$C_MAXRSS;
|
|
fab.fab$l_fop = 0;
|
|
|
|
while( $SUCCESSFUL(sts) ) {
|
|
if( $FAILS(sts = sys_search( &fab )) ) {
|
|
if( $MATCHCOND(sts, RMS$_NMF) )
|
|
sts = SS$_NORMAL;
|
|
nam.nam$l_esa[nam.nam$b_esl] = '\0';
|
|
printmsg( TYPE_SEARCHFAIL, 0, nam.nam$l_esa );
|
|
sts = printmsg( sts, MSG_CONTINUE, TYPE_SEARCHFAIL );
|
|
break;
|
|
}
|
|
fab.fab$b_fac = FAB$M_GET;
|
|
|
|
if( nam.nam$l_fnb & NAM$M_WILDCARD )
|
|
printf( "\n%.*s\n\n", nam.nam$b_rsl, rsa );
|
|
|
|
if( $FAILS(sts = sys_open(&fab)) ) {
|
|
nam.nam$l_rsa[nam.nam$b_rsl] = '\0';
|
|
printmsg( TYPE_OPENIN, 0, nam.nam$l_rsa );
|
|
sts = printmsg( sts, MSG_CONTINUE, TYPE_OPENIN );
|
|
break;
|
|
}
|
|
sts = copy_1_from( options & copy_vfc, &fab, NULL, height );
|
|
|
|
sys_close(&fab);
|
|
}
|
|
}
|
|
printf( "\n" );
|
|
|
|
fab.fab$b_fns =
|
|
nam.nam$b_ess =
|
|
fab.fab$b_dns = 0;
|
|
nam.nam$l_rlf = NULL;
|
|
nam.nam$b_nop = NAM$M_SYNCHK;
|
|
(void) sys_parse( &fab ); /* Release context */
|
|
|
|
if( $MATCHCOND( sts, RMS$_EOF ) )
|
|
sts = SS$_NORMAL | STS$M_INHIB_MSG;
|
|
|
|
return sts;
|
|
}
|
|
|
|
/******************************************************************* docopy() */
|
|
|
|
/* Copy files to and from Files-11 volume */
|
|
|
|
#define copy_binary OPT_GENERIC_1
|
|
#define copy_log OPT_GENERIC_2
|
|
#define copy_tof11 OPT_GENERIC_3
|
|
#define copy_confirm OPT_GENERIC_4
|
|
#define copy_override OPT_GENERIC_5
|
|
|
|
#define copy_owner OPT_GENERIC_6
|
|
#define copy_protect OPT_GENERIC_7
|
|
#define copy_volume OPT_GENERIC_8
|
|
#define copy_verlim OPT_GENERIC_9
|
|
|
|
#define copy_recfmt (OPT_GENERIC_12|OPT_GENERIC_11|OPT_GENERIC_10)
|
|
#define copy_v_recfmt (OPT_V_GENERIC + 9)
|
|
|
|
/* GENERIC option space is full */
|
|
|
|
#define copy_b4 (OPT_SHARED_2|OPT_SHARED_1)
|
|
#define copy_v_b4 0
|
|
|
|
#define copy_after (OPT_SHARED_4|OPT_SHARED_3)
|
|
#define copy_v_after 2
|
|
|
|
#define copy_prn_none 0
|
|
#define copy_prn_nl 1
|
|
#define copy_prn_c0 2
|
|
#define copy_prn_vfu 3
|
|
|
|
#define copy_prn OPT_SHARED_5
|
|
#define copy_ftn OPT_SHARED_6
|
|
#define copy_cr OPT_SHARED_7
|
|
#define copy_span OPT_SHARED_8
|
|
#define copy_append OPT_SHARED_9
|
|
|
|
/* Type uses OPT_SHARED from the high end */
|
|
|
|
static uint32_t b4n, aftn;
|
|
static uint32_t vfclen;
|
|
static uint32_t reclen;
|
|
static uint32_t verlimit;
|
|
#if 0
|
|
static uint32_t volume;
|
|
#endif
|
|
static uint32_t protection;
|
|
static uint32_t ownuic;
|
|
|
|
/* Print CC */
|
|
static qual_t
|
|
prnb4[] = { {"none", copy_prn_none << copy_v_b4,
|
|
copy_b4, NV, "commands copy qual_cc print b4 none"},
|
|
{"nl", copy_prn_nl << copy_v_b4,
|
|
copy_b4, DV(&b4n), "commands copy qual_cc print b4 nl"},
|
|
{"ctl", copy_prn_c0, copy_b4, DV(&b4n), "commands copy qual_cc print b4 ctl"},
|
|
{"vfu", copy_prn_vfu << copy_v_b4,
|
|
copy_b4, DV(&b4n), "commands copy qual_cc print b4 vfu"},
|
|
|
|
{NULL, 0, 0, NV, NULL}
|
|
};
|
|
static qual_t /* Same keywords as prnb4. Use same help. */
|
|
prnafter[] = { {"none", copy_prn_none << copy_v_after,
|
|
copy_after, NV, "commands copy qual_cc print b4 none"},
|
|
{"nl", copy_prn_nl << copy_v_after,
|
|
copy_after, DV(&aftn), "commands copy qual_cc print b4 nl"},
|
|
{"ctl", copy_prn_c0, copy_b4, DV(&aftn), "commands copy qual_cc print b4 ctl"},
|
|
{"vfu", copy_prn_vfu << copy_v_after,
|
|
copy_after, DV(&aftn), "commands copy qual_cc print b4 vfu"},
|
|
|
|
{NULL, 0, 0, NV, NULL}
|
|
};
|
|
|
|
static qual_t
|
|
prnkwds[] = { {"before", 0, copy_b4, KV(prnb4), "commands copy qual_cc print b4"},
|
|
{"after", 0, copy_after, KV(prnafter), "commands copy qual_cc print after"},
|
|
|
|
{NULL, OPT_NOSORT, 0, NV, NULL}
|
|
};
|
|
|
|
/* Carriage control record attributes */
|
|
static qual_t
|
|
cckwds[] = { {"fortran", copy_ftn, copy_cr|copy_prn, NV,
|
|
"commands copy qual_cc fortran"},
|
|
{"carriage_return", copy_cr, copy_ftn|copy_prn, NV,
|
|
"commands copy qual_cc cr"},
|
|
{"print", copy_prn|(FAB$C_VFC<<copy_v_recfmt),
|
|
copy_ftn|copy_cr|copy_recfmt, KV(prnkwds),
|
|
"commands copy qual_cc print"},
|
|
{"none", 0, copy_ftn|copy_cr|copy_prn, NV,
|
|
"commands copy qual_cc none"},
|
|
|
|
{NULL, 0, 0, NV, NULL}
|
|
};
|
|
|
|
static qual_t
|
|
fmtkwds[] = { {"fixed", (FAB$C_FIX +1) << copy_v_recfmt,
|
|
copy_recfmt, DV(&reclen),
|
|
"commands copy qual_recfmt fixed"},
|
|
{"variable", (FAB$C_VAR +1) << copy_v_recfmt,
|
|
copy_recfmt, NV,
|
|
"commands copy qual_recfmt variable"},
|
|
{"vfc", (FAB$C_VFC +1) << copy_v_recfmt,
|
|
copy_recfmt, VOPT(DV(&vfclen)),
|
|
"commands copy qual_recfmt vfc"},
|
|
{"stream", (FAB$C_STM +1) << copy_v_recfmt,
|
|
copy_recfmt, NV,
|
|
"commands copy qual_recfmt stream"},
|
|
{"streamlf", (FAB$C_STMLF +1) << copy_v_recfmt,
|
|
copy_recfmt, NV,
|
|
"commands copy qual_recfmt streamlf"},
|
|
{"streamcr", (FAB$C_STMCR +1) << copy_v_recfmt,
|
|
copy_recfmt, NV,
|
|
"commands copy qual_recfmt streamcr"},
|
|
{"undefined", (FAB$C_UDF +1) << copy_v_recfmt,
|
|
copy_recfmt, NV,
|
|
"commands copy qual_recfmt undefined"},
|
|
|
|
{NULL, 0, 0, NV, NULL}
|
|
};
|
|
|
|
qual_t
|
|
copyquals[] = { {"ascii", 0, copy_binary, NV, "commands copy qual_ascii"},
|
|
{"binary", copy_binary, 0, NV, "commands copy qual_binary"},
|
|
{"append", copy_append, 0, NV, "commands copy qual_append"},
|
|
{"from_files-11", 0, copy_tof11, NV, "commands copy qual_from" },
|
|
{"to_files-11", copy_tof11, 0, NV, "commands copy qual_to" },
|
|
{"log", copy_log, 0, NV, "-commands copy qual_log"},
|
|
{"nolog", 0, copy_log, NV, NULL},
|
|
{"override", copy_override, 0, NV, NULL},
|
|
{"confirm", copy_confirm, 0, NV, "-commands copy qual_confirm"},
|
|
{"noconfirm", 0, copy_confirm, NV, NULL},
|
|
{"version_limit", copy_verlim, 0, DV(&verlimit),
|
|
"commands copy qual_verlim"},
|
|
#if 0
|
|
{"volume", copy_volume, 0, DV(&volume),
|
|
"commands copy qual_volume"},
|
|
#endif
|
|
{"owner_uic", copy_owner, 0, UV(&ownuic),
|
|
"commands copy qual_owner" },
|
|
{"protection", copy_protect, 0, PV(&protection),
|
|
"commands copy qual_protection"},
|
|
{"record_format", 0, 0, KV(fmtkwds),
|
|
"commands copy qual_recfmt"},
|
|
{"carriage_control", 0, 0, KV(cckwds),
|
|
"commands copy qual_cc"},
|
|
{"span", copy_span, 0, NV, "commands copy qual_span"},
|
|
{"nospan", 0, copy_span, NV, NULL},
|
|
{"vfc_header", copy_vfc, 0, NV,
|
|
"-commands type qual_vfc"},
|
|
{"novfc_header", 0, copy_vfc, NV, NULL},
|
|
|
|
{NULL, 0, 0, NV, NULL}
|
|
};
|
|
|
|
param_t copypars[] = { {"from_filespec", REQ | NOLIM, FSPEC, NOPA,
|
|
"commands copy fromspec"},
|
|
{"to_filespec", REQ, FSPEC, NOPA,
|
|
"commands copy tospec"},
|
|
|
|
{ NULL, 0, 0, NOPA, NULL }
|
|
};
|
|
|
|
const int copy_defaults = 0 | copy_span | copy_log;
|
|
defqualsp_t copy_defopt = NULL;
|
|
|
|
DECL_CMD(copy) {
|
|
options_t options;
|
|
vmscond_t sts;
|
|
|
|
vfclen = 0;
|
|
reclen = 0;
|
|
|
|
if( copy_defopt != NULL ) {
|
|
if( $FAILS(sts = checkquals( &options, copy_defaults, copyquals,
|
|
copy_defopt->qualc, copy_defopt->qualv )) ) {
|
|
return sts;
|
|
}
|
|
}
|
|
else
|
|
options = copy_defaults;
|
|
|
|
if( $FAILS(sts = checkquals( &options, options, copyquals, qualc, qualv )) ) {
|
|
return sts;
|
|
}
|
|
|
|
if( options & copy_tof11 )
|
|
return copy_to( options, argc, argv );
|
|
|
|
return copy_from( options, argc, argv );
|
|
|
|
}
|
|
|
|
/******************************************************************* copy_from() */
|
|
|
|
static vmscond_t copy_from( options_t options, int argc, char **argv ) {
|
|
vmscond_t sts;
|
|
struct NAM nam;
|
|
struct FAB fab;
|
|
char res[NAM$C_MAXRSS + 1], rsa[NAM$C_MAXRSS + 1];
|
|
int i, filecount = 0;
|
|
vmscond_t confirm = ODS2_CONFIRM_ALL;
|
|
|
|
if( options & copy_confirm )
|
|
confirm = COPY_CONFIRM;
|
|
|
|
sts = SS$_NORMAL;
|
|
|
|
nam = cc$rms_nam;
|
|
fab = cc$rms_fab;
|
|
|
|
for( i = 1; i < argc -1; i++ ) {
|
|
nam.nam$l_esa = res;
|
|
nam.nam$b_ess = NAM$C_MAXRSS;
|
|
fab.fab$l_nam = &nam;
|
|
fab.fab$l_fna = argv[1];
|
|
fab.fab$b_fns = (uint8_t)strlen(fab.fab$l_fna);
|
|
|
|
if( $FAILS(sts = sys_parse(&fab)) ) {
|
|
printmsg( COPY_PARSEFAIL, 0, fab.fab$l_fna );
|
|
sts = printmsg( sts, MSG_CONTINUE, COPY_PARSEFAIL );
|
|
break;
|
|
}
|
|
res[nam.nam$b_esl] = '\0';
|
|
|
|
nam.nam$l_rsa = rsa;
|
|
nam.nam$b_rss = NAM$C_MAXRSS;
|
|
fab.fab$l_fop = 0;
|
|
|
|
while( $SUCCESSFUL(sts) ) {
|
|
char name[NAM$C_MAXRSS + 1];
|
|
char *out, *inp;
|
|
int dot = FALSE;
|
|
uint32_t directory = 0;
|
|
uint16_t retlen;
|
|
struct XABPRO pro;
|
|
struct XABDAT dat;
|
|
struct XABITM itm;
|
|
struct item_list xitems[] = {
|
|
{ XAB$_UCHAR_DIRECTORY, sizeof(directory), NULL, 0 },
|
|
{ 0, 0, NULL, 0 }
|
|
};
|
|
|
|
if( $FAILS(sts = sys_search( &fab )) ) {
|
|
if( $MATCHCOND(sts, RMS$_NMF) ) {
|
|
sts = SS$_NORMAL;
|
|
break;
|
|
}
|
|
nam.nam$l_esa[nam.nam$b_esl] = '\0';
|
|
printmsg( COPY_SEARCHFAIL, 0, nam.nam$l_esa );
|
|
sts = printmsg( sts, MSG_CONTINUE, COPY_SEARCHFAIL );
|
|
break;
|
|
}
|
|
rsa[nam.nam$b_rsl] = '\0';
|
|
|
|
pro = cc$rms_xabpro;
|
|
dat = cc$rms_xabdat;
|
|
itm = cc$rms_xabitm;
|
|
|
|
dat.xab$l_nxt = &pro;
|
|
itm.xab$l_nxt = &dat;
|
|
xitems[0].buffer = &directory;
|
|
xitems[0].retlen = &retlen;
|
|
itm.xab$b_mode = XAB$K_SENSEMODE;
|
|
itm.xab$l_itemlist = xitems;
|
|
fab.fab$l_xab = &itm;
|
|
fab.fab$b_fac = FAB$M_GET;
|
|
|
|
sts = sys_open(&fab);
|
|
fab.fab$l_xab = NULL;
|
|
rsa[nam.nam$b_rsl] = '\0';
|
|
|
|
if( $FAILED(sts) ) {
|
|
int err;
|
|
err = errno;
|
|
printmsg( COPY_OPENIN, 0, rsa );
|
|
sts = printmsg( sts, MSG_CONTINUE, COPY_OPENIN );
|
|
if( err )
|
|
printmsg( ODS2_OSERROR, MSG_CONTINUE, COPY_OPENIN,
|
|
strerror( err ) );
|
|
break;
|
|
}
|
|
|
|
if( directory ) {
|
|
if( !(options & copy_override) ) {
|
|
printmsg( COPY_DIRNOTCOPIED, 0, rsa );
|
|
sys_close( &fab );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
out = name;
|
|
inp = argv[2];
|
|
|
|
while (*inp != '\0') {
|
|
if (*inp == '*') {
|
|
inp++;
|
|
if (dot) {
|
|
memcpy(out, nam.nam$l_type + 1,
|
|
nam.nam$b_type - 1);
|
|
out += nam.nam$b_type - 1;
|
|
} else {
|
|
size_t length;
|
|
|
|
length = nam.nam$b_name;
|
|
|
|
if (*inp == '\0')
|
|
length += nam.nam$b_type;
|
|
memcpy( out, nam.nam$l_name, length );
|
|
out += length;
|
|
}
|
|
continue;
|
|
}
|
|
if (*inp == '.') {
|
|
dot = TRUE;
|
|
} else {
|
|
if (strchr(":]\\/", *inp))
|
|
dot = FALSE;
|
|
}
|
|
*out++ = *inp++;
|
|
}
|
|
*out++ = '\0';
|
|
|
|
if( $MATCHCOND( confirm, COPY_CONFIRM) )
|
|
confirm = confirm_cmd( confirm, rsa, name );
|
|
|
|
if( !$MATCHCOND( confirm, ODS2_CONFIRM_ALL ) ) {
|
|
if( $MATCHCOND( confirm, ODS2_CONFIRM_YES ) ) {
|
|
confirm = COPY_CONFIRM;
|
|
} else if( $MATCHCOND( confirm, ODS2_CONFIRM_NO ) ) {
|
|
confirm = COPY_CONFIRM;
|
|
sys_close( &fab );
|
|
continue;
|
|
} else { /* ODS2_CONFIRM_QUIT */
|
|
sys_close( &fab );
|
|
sts = confirm;
|
|
break;
|
|
}
|
|
}
|
|
|
|
fab.fab$l_xab = &itm;
|
|
if( $SUCCESSFUL(sts = copy_1_from( options, &fab, name, 0 )) )
|
|
filecount++;
|
|
fab.fab$l_xab = NULL;
|
|
|
|
sys_close(&fab);
|
|
} /* search */
|
|
if( $VMS_STATUS_SEVERITY(sts) > STS$K_WARNING ||
|
|
$MATCHCOND(sts, ODS2_CONFIRM_QUIT) )
|
|
break;
|
|
} /* arg */
|
|
|
|
if( $SUCCESSFUL(sts) || $MATCHCOND(sts, ODS2_CONFIRM_QUIT) ) {
|
|
if (filecount > 0) {
|
|
if( options & copy_log )
|
|
sts = printmsg( COPY_COPIED, 0, filecount );
|
|
} else {
|
|
sts = printmsg( COPY_NOFILES, 0 );
|
|
}
|
|
}
|
|
return sts;
|
|
}
|
|
|
|
/******************************************************************* copy_1_from() */
|
|
|
|
static vmscond_t copy_1_from( options_t options, struct FAB *fab,
|
|
const char *to, size_t dopause ) {
|
|
vmscond_t sts;
|
|
uint32_t records = 0;
|
|
int stream = 0, var = 0;
|
|
FILE *tof;
|
|
char *rec;
|
|
pause_t *pause = NULL, pausectl;
|
|
struct RAB rab = cc$rms_rab;
|
|
|
|
if( dopause ) {
|
|
pausectl.interval = dopause;
|
|
pausectl.lineno = 0;
|
|
pausectl.prompt = TYPE_CONTINUE;
|
|
pause = &pausectl;
|
|
}
|
|
|
|
rab.rab$l_fab = fab;
|
|
|
|
if( $FAILS(sts = sys_connect(&rab)) ) {
|
|
printmsg( COPY_OPENIN, 0, fab->fab$l_fna );
|
|
sts = printmsg( sts, MSG_CONTINUE, COPY_OPENIN );
|
|
return sts;
|
|
}
|
|
|
|
if( (rec = malloc( MAXREC + 2 )) == NULL ) {
|
|
sys_disconnect( &rab );
|
|
printmsg( COPY_OPENIN, 0, fab->fab$l_fna );
|
|
sts = printmsg( SS$_INSFMEM, MSG_CONTINUE, COPY_OPENIN );
|
|
return sts;
|
|
}
|
|
|
|
rab.rab$l_ubf = rec;
|
|
rab.rab$w_usz = MAXREC;
|
|
rab.rab$l_rhb = NULL;
|
|
|
|
if( options & copy_binary ) {
|
|
fab->fab$b_rfm = FAB$C_UDF;
|
|
fab->fab$b_rat = 0;
|
|
} else {
|
|
switch( fab->fab$b_rfm ) {
|
|
case FAB$C_STMLF:
|
|
stream = '\n';
|
|
break;
|
|
case FAB$C_STMCR:
|
|
stream = '\r';
|
|
break;
|
|
case FAB$C_STM:
|
|
stream = EOF;
|
|
break;
|
|
case FAB$C_VFC:
|
|
var = 1;
|
|
if( fab-> fab$b_fsz != 0 ) {
|
|
++var;
|
|
rab.rab$l_rhb = malloc( fab->fab$b_fsz );
|
|
if( rab.rab$l_rhb == NULL ) {
|
|
free( rec );
|
|
sys_disconnect( &rab );
|
|
printmsg( COPY_OPENIN, 0, fab->fab$l_fna );
|
|
sts = printmsg( sts, MSG_CONTINUE, COPY_OPENIN );
|
|
return sts;
|
|
}
|
|
}
|
|
break;
|
|
case FAB$C_VAR:
|
|
var = 1;
|
|
break;
|
|
case FAB$C_FIX:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( to == NULL )
|
|
tof = stdout;
|
|
else {
|
|
if( (stream ||
|
|
(fab->fab$b_rat & (FAB$M_CR | FAB$M_PRN | FAB$M_FTN))) &&
|
|
!(options & copy_binary) ) {
|
|
tof = openf( to, (options & copy_append)? "a": "w" );
|
|
} else {
|
|
tof = openf( to, (options & copy_append)? "ab": "wb" );
|
|
}
|
|
}
|
|
if (tof == NULL) {
|
|
int err;
|
|
|
|
err = errno;
|
|
free( rec );
|
|
free( rab.rab$l_rhb );
|
|
sys_disconnect( &rab );
|
|
printmsg( COPY_OPENOUT, 0, to );
|
|
return printmsg( ODS2_OSERROR, MSG_CONTINUE, COPY_OPENOUT,
|
|
strerror( err ) );
|
|
}
|
|
|
|
while( $SUCCESSFUL(sts) ) {
|
|
char *rp;
|
|
unsigned rsz;
|
|
|
|
if( ferror( tof ) ) {
|
|
int err;
|
|
|
|
err = errno;
|
|
printmsg( COPY_WRITEERR, 0, (to == NULL)? "tty": to );
|
|
sts = printmsg( ODS2_OSERROR, MSG_CONTINUE, COPY_WRITEERR,
|
|
strerror(err) );
|
|
break;
|
|
}
|
|
if( $FAILS(sts = sys_get( &rab )) ) {
|
|
if( $MATCHCOND(sts, RMS$_EOF) )
|
|
sts |= STS$M_INHIB_MSG;
|
|
else {
|
|
printmsg( COPY_READERR, 0, fab->fab$l_fna );
|
|
sts = printmsg( sts, MSG_CONTINUE, COPY_READERR, rab.rab$l_stv);
|
|
}
|
|
break;
|
|
}
|
|
rp = rec;
|
|
rsz = rab.rab$w_rsz;
|
|
|
|
if( (options & copy_binary) || fab->fab$b_rfm == FAB$C_UDF ) {
|
|
if( rsz != 0 ) {
|
|
if( $FAILS(sts = put_strn( rp, rsz, tof, pause )) )
|
|
break;
|
|
if( fab->fab$b_rfm == FAB$C_UDF )
|
|
records += rsz;
|
|
else
|
|
records++;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if( stream ) {
|
|
if( $FAILS(sts = put_strn( rp, rsz, tof, pause )) )
|
|
break;
|
|
|
|
if( fab->fab$b_rat & (FAB$M_CR|FAB$M_FTN) ) {
|
|
if( stream == EOF ) {
|
|
if( $FAILS(sts = put_strn( "\r\n", 2, tof, pause )) )
|
|
break;
|
|
} else {
|
|
if( $FAILS(sts = put_c( stream, tof, pause )) )
|
|
break;
|
|
}
|
|
}
|
|
++records;
|
|
continue;
|
|
}
|
|
|
|
if( fab->fab$b_rat & FAB$M_FTN ) {
|
|
--rsz;
|
|
switch( *rp++ ) { /* AA-D034E-TE Table 8-5 */
|
|
case '+': /* Overprint current line and return to left margin */
|
|
if( $FAILS(sts = put_c( '\r', tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_strn( rp, rsz, tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_c( '\r', tof, pause )) )
|
|
break;
|
|
break;
|
|
case ' ': /* Single space: output to beginning of next line */
|
|
default:
|
|
if( $FAILS(sts = put_c( '\n', tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_strn(rp, rsz, tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_c( '\r', tof, pause )) )
|
|
break;
|
|
break;
|
|
case '0': /* Double space: skip a line before starting output */
|
|
if( $FAILS(sts = put_strn( "\n\n", 2, tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_strn( rp, rsz, tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_c( '\r', tof, pause )) )
|
|
break;
|
|
break;
|
|
case '1': /* Paging: start output at top of a new page */
|
|
if( $FAILS(sts = put_c( '\f', tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_strn( rp, rsz, tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_c( '\r', tof, pause )) )
|
|
break;
|
|
break;
|
|
case '$': /* Prompting: Start a beginning of next line and suppress \r */
|
|
if( $FAILS(sts = put_c( '\n', tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_strn( rp, rsz, tof, pause )) )
|
|
break;
|
|
break;
|
|
case '\0': /* Overprinting with no advance - no \r at end */
|
|
if( $FAILS(sts = put_c( '\r', tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_strn( rp, rsz, tof, pause )) )
|
|
break;
|
|
break;
|
|
}
|
|
if( $FAILED(sts) )
|
|
break;
|
|
++records;
|
|
continue;
|
|
}
|
|
|
|
if( (fab->fab$b_rat & FAB$M_CR) && $FAILS(sts = put_c( '\n', tof, pause )) )
|
|
break;
|
|
|
|
if( var == 2 ) {
|
|
if( (fab->fab$b_rat & FAB$M_PRN) && fab->fab$b_fsz == 2 ) {
|
|
if( $FAILS(sts = put_prn( rab.rab$l_rhb[0], tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_strn( rp, rsz, tof, pause )) )
|
|
break;
|
|
if( $FAILS(sts = put_prn( rab.rab$l_rhb[1], tof, pause )) )
|
|
break;
|
|
++records;
|
|
continue;
|
|
}
|
|
|
|
if( (options & copy_vfc) &&
|
|
$FAILS(sts = put_strn( rab.rab$l_rhb,
|
|
fab->fab$b_fsz, tof, pause )) )
|
|
break;
|
|
}
|
|
|
|
if( $FAILS(sts = put_strn( rp, rsz, tof, pause )) )
|
|
break;
|
|
|
|
if( fab->fab$b_rat & FAB$M_CR )
|
|
fputc( '\r', tof );
|
|
|
|
++records;
|
|
}
|
|
|
|
sys_disconnect( &rab );
|
|
|
|
if( var == 2 ) {
|
|
free( rab.rab$l_rhb );
|
|
rab.rab$l_rhb = NULL;
|
|
}
|
|
|
|
free( rec );
|
|
rec = NULL;
|
|
|
|
if( to == NULL ) { /* stdout */
|
|
if( $FAILED(sts) )
|
|
sts = printmsg( sts, 0, rab.rab$l_stv );
|
|
return sts;
|
|
}
|
|
if( fclose( tof ) ) {
|
|
int err;
|
|
|
|
err = errno;
|
|
printmsg( COPY_CLOSEOUT, 0, (to == NULL)? "tty": to );
|
|
sts = printmsg( ODS2_OSERROR, MSG_CONTINUE, COPY_CLOSEOUT, strerror( err ) );
|
|
return sts;
|
|
}
|
|
|
|
do {
|
|
struct XABDAT *dat;
|
|
time_t posixtime;
|
|
unsigned short timvec[7];
|
|
char *tz;
|
|
struct tm tm;
|
|
#ifdef _WIN32
|
|
struct _utimbuf tv;
|
|
#else
|
|
struct timeval tv[2];
|
|
#endif
|
|
|
|
for( dat = (struct XABDAT *)fab->fab$l_xab;
|
|
dat != NULL && dat->xab$b_cod != XAB$C_DAT; dat = dat->xab$l_nxt )
|
|
;
|
|
|
|
if( dat == NULL )
|
|
break;
|
|
|
|
if( $FAILS(sys_numtim( timvec, dat->xab$q_rdt )) )
|
|
break;
|
|
|
|
tm.tm_sec = timvec[5];
|
|
tm.tm_min = timvec[4];
|
|
tm.tm_hour = timvec[3];
|
|
tm.tm_mday = timvec[2];
|
|
tm.tm_mon = timvec[1] -1;
|
|
tm.tm_year = timvec[0] - 1900;
|
|
|
|
tz = get_env( "TZ" );
|
|
setenv( "TZ", "", 1 );
|
|
tzset();
|
|
posixtime = mktime( &tm );
|
|
if( posixtime != (time_t)-1 ) {
|
|
#ifdef _WIN32
|
|
tv.actime =
|
|
tv.modtime = posixtime;
|
|
(void)_utime( to, &tv );
|
|
#else
|
|
tv[0].tv_sec = posixtime;
|
|
tv[0].tv_usec = timvec[6] * 10000;
|
|
tv[1] = tv[0]; /* Set mtime to atime */
|
|
(void) utimes( to, tv );
|
|
#endif
|
|
}
|
|
if( tz != NULL )
|
|
setenv( "TZ", tz, 1 );
|
|
else
|
|
unsetenv( "TZ" );
|
|
tzset();
|
|
free( tz );
|
|
|
|
} while( 0 );
|
|
|
|
#ifndef _WIN32
|
|
do {
|
|
struct XABPRO *pro;
|
|
mode_t mode;
|
|
uint16_t prot;
|
|
|
|
for( pro = (struct XABPRO *)fab->fab$l_xab;
|
|
pro != NULL && pro->xab$b_cod != XAB$C_PRO; pro = pro->xab$l_nxt )
|
|
;
|
|
|
|
if( pro == NULL )
|
|
break;
|
|
|
|
mode = (S_IRUSR|S_IWUSR|S_IXUSR|
|
|
S_IRGRP|S_IWGRP|S_IXGRP|
|
|
S_IROTH|S_IWOTH|S_IXOTH);
|
|
|
|
prot = pro->xab$w_pro;
|
|
|
|
if( prot & ((xab$m_noread << xab$v_system) |
|
|
(xab$m_noread << xab$v_owner)) )
|
|
mode &= ~S_IRUSR;
|
|
if( prot & (((xab$m_nodel|xab$m_nowrite) << xab$v_system) |
|
|
((xab$m_nodel|xab$m_nowrite) << xab$v_owner)) )
|
|
mode &= ~S_IWUSR;
|
|
if( prot & ( (xab$m_noexe << xab$v_system) |
|
|
(xab$m_noexe << xab$v_owner) ) )
|
|
mode &= ~S_IXUSR;
|
|
if( prot & (xab$m_noread << xab$v_group) )
|
|
mode &= ~S_IRGRP;
|
|
if( prot & (xab$m_nowrite << xab$v_group) )
|
|
mode &= ~S_IWGRP;
|
|
if( prot & (xab$m_noexe << xab$v_group) )
|
|
mode &= ~S_IXGRP;
|
|
if( prot & (xab$m_noread << xab$v_world) )
|
|
mode &= ~S_IROTH;
|
|
if( prot & (xab$m_nowrite << xab$v_world) )
|
|
mode &= ~S_IWOTH;
|
|
if( prot & (xab$m_noexe << xab$v_world) )
|
|
mode &= ~S_IXOTH;
|
|
if( chmod( to, mode ) != 0 ) {
|
|
int err;
|
|
|
|
err = errno;
|
|
printmsg( COPY_PROTERR, 0, to );
|
|
sts = printmsg( ODS2_OSERROR, MSG_CONTINUE, COPY_PROTERR,
|
|
strerror( err ) );
|
|
}
|
|
} while( 0 );
|
|
#endif
|
|
|
|
if( !$MATCHCOND(sts, RMS$_EOF) )
|
|
return sts;
|
|
|
|
if( options & copy_log ) {
|
|
sts = (fab->fab$b_rfm == FAB$C_UDF)? COPY_COPIEDU: COPY_COPIEDR;
|
|
|
|
sts = printmsg( sts, 0,
|
|
fab->fab$l_nam->nam$l_rsa,
|
|
(to == NULL)? "tty": to,
|
|
records );
|
|
}
|
|
return SS$_NORMAL;
|
|
}
|
|
|
|
/******************************************************************* put_prn() */
|
|
static vmscond_t put_prn( char ch, FILE *tof, pause_t *pause ) {
|
|
vmscond_t sts;
|
|
size_t n;
|
|
/* 7 6 5 4 */
|
|
if( !(ch & 0x80) ) { /* 0 x x x */
|
|
n = ch & 0x7F;
|
|
while( n-- )
|
|
if( $FAILS(sts = put_c( '\n', tof, pause )) )
|
|
return sts;
|
|
return SS$_NORMAL;
|
|
} /* 1 x x x */
|
|
if( !(ch & 0x40) ) { /* 1 0 x x */
|
|
if( !(ch & 0x20) ) /* 1 0 0 x */
|
|
return put_c( ch & 0x1f, tof, pause ); /* C0 */
|
|
/* 1 0 1 x */
|
|
return put_c( (ch & 0x1f) | 0x80, tof, pause ); /* C1/reserved */
|
|
} /* 1 1 x x */
|
|
if( !(ch & 0x30) ) { /* 1 1 0 0 */
|
|
static const char vfuch[16] = {
|
|
'\f', '\020', '\021', '\022', /* CH 1 - 4 */
|
|
'\023', '\024', '\v', '\n', /* CH 5 - 8 */
|
|
'\n', '\n', '\n', '\n', /* CH 9 - 12 */
|
|
'\n', '\n', '\n', '\n' }; /* CH 13 - 16 */
|
|
if( tof == stdout )
|
|
return put_c( '\n', tof, pause ); /* type: 1 LF */
|
|
return put_c( vfuch[ch & 0xf], tof, pause );
|
|
/* VFU channel 1+<3:0> */
|
|
} /* 1 1 y y : yy == 01, 10, 11 */
|
|
return put_c( ch, tof, pause ); /* Device-specific/reserved -- Agrave - yumlaut */
|
|
}
|
|
|
|
/******************************************************************* copy_to() */
|
|
|
|
static vmscond_t copy_to( options_t options, int argc, char **argv ) {
|
|
glob_t globs;
|
|
int i, err, gflags = GLOB_MARK | GLOB_BRACE | GLOB_TILDE_CHECK;
|
|
size_t n, filecount = 0;
|
|
vmscond_t sts;
|
|
vmscond_t confirm = ODS2_CONFIRM_ALL;
|
|
|
|
memset( &globs, 0, sizeof( globs ) );
|
|
|
|
if( options & copy_confirm )
|
|
confirm = COPY_CONFIRM;
|
|
|
|
sts = SS$_NORMAL;
|
|
|
|
for( i = 1; i < argc -1; i++ ) {
|
|
err = glob( argv[i], gflags, NULL, &globs );
|
|
gflags |= GLOB_APPEND;
|
|
switch( err ) {
|
|
case 0:
|
|
sts = SS$_NORMAL;
|
|
break;
|
|
case GLOB_NOSPACE:
|
|
sts = printmsg( COPY_NOMEM, 0, argv[i] );
|
|
break;
|
|
case GLOB_ABORTED:
|
|
sts = printmsg( COPY_GLOBABT, 0, argv[i] );
|
|
break;
|
|
case GLOB_NOMATCH:
|
|
sts = printmsg( COPY_NOMATCH, 0, argv[i] );
|
|
break;
|
|
default:
|
|
sts = printmsg( COPY_GLOBERR, 0, err, argv[i] );
|
|
break;
|
|
}
|
|
if( $FAILED(sts) ) {
|
|
globfree( &globs );
|
|
return sts;
|
|
}
|
|
}
|
|
for( n = 0; n < globs.gl_pathc; n++ ) {
|
|
char *to;
|
|
|
|
if( (to = output_file_name( argv[ argc - 1],
|
|
globs.gl_pathv[n], NULL )) == NULL ) {
|
|
sts = printmsg( COPY_NOMEM, 0, globs.gl_pathv[n] );
|
|
globfree( &globs );
|
|
return sts;
|
|
}
|
|
|
|
if( $MATCHCOND( confirm, COPY_CONFIRM) )
|
|
confirm = confirm_cmd( confirm, globs.gl_pathv[n], to );
|
|
|
|
if( !$MATCHCOND( confirm, ODS2_CONFIRM_ALL ) ) {
|
|
if( $MATCHCOND( confirm, ODS2_CONFIRM_YES ) ) {
|
|
confirm = COPY_CONFIRM;
|
|
} else if( $MATCHCOND( confirm, ODS2_CONFIRM_NO ) ) {
|
|
confirm = COPY_CONFIRM;
|
|
free( to );
|
|
continue;
|
|
} else { /* ODS2_CONFIRM_QUIT */
|
|
sts = confirm;
|
|
free( to );
|
|
break;
|
|
}
|
|
}
|
|
sts = copy_1_to( options, globs.gl_pathv[n], to );
|
|
|
|
free( to );
|
|
if( $SUCCESSFUL(sts ) )
|
|
++filecount;
|
|
else if( $VMS_STATUS_SEVERITY(sts) > STS$K_WARNING ||
|
|
$MATCHCOND(sts, ODS2_CONFIRM_QUIT) )
|
|
break;
|
|
} /* glob */
|
|
|
|
if( $SUCCESSFUL(sts) || $MATCHCOND(sts, ODS2_CONFIRM_QUIT) ) {
|
|
if( filecount > 0 ) {
|
|
if( options & copy_log )
|
|
sts = printmsg( COPY_COPIED, 0, filecount );
|
|
} else {
|
|
sts = printmsg( COPY_NOFILES, 0 );
|
|
}
|
|
}
|
|
globfree( &globs );
|
|
return sts;
|
|
}
|
|
|
|
/******************************************************************* copy_1_to() */
|
|
static vmscond_t copy_1_to( options_t options, char *from, char *to ) {
|
|
vmscond_t sts;
|
|
size_t records = 0, bufsize = 80;
|
|
char *buf = NULL;
|
|
FILE *fromf;
|
|
struct FAB fab;
|
|
struct RAB rab;
|
|
struct NAM nam;
|
|
struct XABDAT dat;
|
|
struct XABPRO pro;
|
|
char vfc[2], rsbuf[NAM$C_MAXRSS+1];
|
|
#ifdef _WIN32
|
|
struct _stat statbuf;
|
|
#else
|
|
struct stat statbuf;
|
|
#endif
|
|
|
|
fab = cc$rms_fab;
|
|
rab = cc$rms_rab;
|
|
nam = cc$rms_nam;
|
|
dat = cc$rms_xabdat;
|
|
pro = cc$rms_xabpro;
|
|
|
|
if ( *from == '\0' ) {
|
|
return printmsg( COPY_NONAME, 0 );
|
|
}
|
|
fromf = openf( from, (options & copy_binary)? "rb": "r" );
|
|
if( fromf == NULL ) {
|
|
int err;
|
|
|
|
err = errno;
|
|
sts = printmsg( COPY_OPENIN, 0, from );
|
|
if( err )
|
|
sts = printmsg( ODS2_OSERROR, MSG_CONTINUE,
|
|
COPY_OPENIN, strerror(err) );
|
|
return sts;
|
|
}
|
|
if( fstat( Fileno( fromf ), &statbuf ) != 0 )
|
|
statbuf.st_size = 0;
|
|
else {
|
|
unsigned short tvec[7];
|
|
|
|
#ifdef _WIN32
|
|
struct tm tmd;
|
|
struct tm *tm = &tmd;
|
|
(void) gmtime_s( &tmd, &statbuf.st_mtime );
|
|
#else
|
|
struct tm *tm;
|
|
|
|
tm = gmtime( &statbuf.st_mtime );
|
|
#endif
|
|
tvec[0] = tm->tm_year + 1900;
|
|
tvec[1] = tm->tm_mon + 1;
|
|
tvec[2] = tm->tm_mday;
|
|
tvec[3] = tm->tm_hour;
|
|
tvec[4] = tm->tm_min;
|
|
tvec[5] = tm->tm_sec;
|
|
tvec[6] = 0;
|
|
|
|
if( $SUCCESSFUL(lib_cvt_vectim( tvec, dat.xab$q_rdt )) ) {
|
|
#ifdef _WIN32
|
|
(void) gmtime_s( &tmd, &statbuf.st_ctime );
|
|
tvec[0] = tm->tm_year + 1900;
|
|
tvec[1] = tm->tm_mon + 1;
|
|
tvec[2] = tm->tm_mday;
|
|
tvec[3] = tm->tm_hour;
|
|
tvec[4] = tm->tm_min;
|
|
tvec[5] = tm->tm_sec;
|
|
tvec[6] = 0;
|
|
|
|
(void) lib_cvt_vectim( tvec, dat.xab$q_cdt );
|
|
#else /* No local create time */
|
|
memcpy( &dat.xab$q_cdt, dat.xab$q_rdt, sizeof( dat.xab$q_cdt ) );
|
|
#endif
|
|
|
|
fab.fab$l_xab = &dat;
|
|
}
|
|
}
|
|
|
|
nam.nam$l_rsa = rsbuf;
|
|
nam.nam$b_rss = (uint8_t)(sizeof( rsbuf ) -1);
|
|
|
|
if( options & (copy_protect|copy_owner) ) {
|
|
pro.xab$l_nxt = fab.fab$l_xab;
|
|
fab.fab$l_xab = &pro;
|
|
|
|
if( options & copy_protect ) {
|
|
pro.xab$w_pro = (uint16_t)
|
|
((pro.xab$w_pro & ~(protection >> 16)) |
|
|
(uint16_t)protection);
|
|
}
|
|
|
|
if( options & copy_owner ) {
|
|
pro.xab$l_uic = ownuic;
|
|
}
|
|
}
|
|
|
|
fab.fab$l_nam = &nam;
|
|
|
|
fab.fab$b_fac = FAB$M_PUT;
|
|
fab.fab$l_fop = FAB$M_OFP | FAB$M_TEF;
|
|
fab.fab$b_org = FAB$C_SEQ;
|
|
|
|
#if 0
|
|
if( options & copy_binary ) {
|
|
fab.fab$w_mrs = 512;
|
|
fab.fab$b_rfm = FAB$C_FIX;
|
|
} else {
|
|
fab.fab$b_rat = 0;
|
|
fab.fab$b_rfm = FAB$C_STMLF;
|
|
}
|
|
#endif
|
|
|
|
if( !(options & copy_recfmt) ) {
|
|
options |= (FAB$C_VAR +1) << copy_v_recfmt;
|
|
if( !(options & (copy_prn|copy_ftn|copy_cr)) )
|
|
options |= copy_cr;
|
|
}
|
|
|
|
fab.fab$b_rfm = ((options & copy_recfmt) >> copy_v_recfmt) -1;
|
|
|
|
switch( fab.fab$b_rfm ) {
|
|
case FAB$C_STM:
|
|
case FAB$C_STMLF:
|
|
case FAB$C_STMCR:
|
|
fab.fab$b_rat |= FAB$M_CR;
|
|
break;
|
|
}
|
|
|
|
if( !(options & copy_span) )
|
|
fab.fab$b_rat |= FAB$M_BLK;
|
|
if( options & copy_ftn )
|
|
fab.fab$b_rat |= FAB$M_FTN;
|
|
if( options & copy_cr )
|
|
fab.fab$b_rat |= FAB$M_CR;
|
|
if( options & copy_prn ) {
|
|
fab.fab$b_rat |= FAB$M_PRN;
|
|
fab.fab$b_fsz = 2;
|
|
fab.fab$b_rfm = FAB$C_VFC;
|
|
|
|
switch( (options & copy_b4) >> copy_v_b4 ) {
|
|
case copy_prn_none:
|
|
vfc[0] = 0;
|
|
break;
|
|
case copy_prn_nl:
|
|
if( b4n < 1 || b4n > 127 )
|
|
return printmsg( COPY_INVALIDNL, 0 );
|
|
vfc[0] = b4n & 0x7f;
|
|
break;
|
|
case copy_prn_c0:
|
|
if( b4n > 31 )
|
|
return printmsg( COPY_INVALIDC0, 0 );
|
|
vfc[0] = 0x80 | b4n;
|
|
break;
|
|
case copy_prn_vfu:
|
|
if( b4n < 1 || b4n > 16 )
|
|
return printmsg( COPY_INVALIDVFU, 0 );
|
|
vfc[0] = (0xC0 | (b4n -1)) & 0xff;
|
|
}
|
|
switch( (options & copy_after) >> copy_v_after ) {
|
|
case copy_prn_none:
|
|
vfc[1] = 0;
|
|
break;
|
|
case copy_prn_nl:
|
|
if( aftn < 1 || aftn > 127 )
|
|
return printmsg( COPY_INVALIDNL, 0 );
|
|
vfc[1] = aftn & 0x7f;
|
|
break;
|
|
case copy_prn_c0:
|
|
if( aftn > 31 )
|
|
return printmsg( COPY_INVALIDC0, 0 );
|
|
vfc[1] = 0x80 | aftn;
|
|
break;
|
|
case copy_prn_vfu:
|
|
if( aftn < 1 || aftn > 16 )
|
|
return printmsg( COPY_INVALIDVFU, 0 );
|
|
vfc[1] = (0xC0 | (aftn -1)) & 0xff;
|
|
}
|
|
} /* prn */
|
|
|
|
fab.fab$l_alq = (statbuf.st_size + 511) / 512;
|
|
fab.fab$w_mrs = (uint16_t)reclen;
|
|
|
|
fab.fab$l_fna = to;
|
|
fab.fab$b_fns = (uint8_t)strlen( fab.fab$l_fna );
|
|
|
|
do {
|
|
if( options & copy_append ) {
|
|
sts = sys_open( &fab );
|
|
rab.rab$l_rop = RAB$M_EOF;
|
|
} else
|
|
sts = sys_create( &fab );
|
|
rsbuf[nam.nam$b_rsl] = '\0';
|
|
if( $FAILED(sts) ) {
|
|
fclose( fromf );
|
|
printmsg( COPY_OPENOUT, 0, (nam.nam$b_rsl? rsbuf:to) );
|
|
return printmsg( sts, MSG_CONTINUE, COPY_OPENOUT );
|
|
}
|
|
|
|
rab.rab$l_fab = &fab;
|
|
rab.rab$b_rac = RAB$C_SEQ;
|
|
|
|
if( $FAILS(sts = sys_connect( &rab )) ) {
|
|
sts = printmsg( sts, 0 );
|
|
break;
|
|
}
|
|
|
|
if( fab.fab$b_rfm == FAB$C_VFC ) {
|
|
if( options & copy_prn )
|
|
rab.rab$l_rhb = vfc;
|
|
} else
|
|
options &= ~(copy_prn|copy_vfc);
|
|
|
|
if( options & copy_binary ) {
|
|
char *buf;
|
|
uint16_t len;
|
|
|
|
if( (buf = malloc( 512 )) == NULL ) {
|
|
sts = printmsg( COPY_NOMEM, 0, from );
|
|
break;
|
|
}
|
|
rab.rab$l_rbf = buf;
|
|
while( (len = (uint16_t)fread( buf, 1, 512, fromf )) > 0 ) {
|
|
if( len != 512 )
|
|
memset( buf + len, 0, 512 - len );
|
|
rab.rab$w_rsz = 512;
|
|
|
|
if( $FAILS(sts = sys_put( &rab )) ) {
|
|
printmsg( COPY_WRITEERR, 0, rsbuf );
|
|
sts = printmsg( sts, MSG_CONTINUE, COPY_WRITEERR );
|
|
break;
|
|
}
|
|
++records;
|
|
}
|
|
free( buf );
|
|
buf = NULL;
|
|
break;
|
|
}
|
|
while( (rab.rab$l_rbf = fgetline( fromf, TRUE, &buf, &bufsize )) != NULL ) {
|
|
size_t len;
|
|
char * rp;
|
|
|
|
rp = rab.rab$l_rbf;
|
|
len = strlen( rp );
|
|
if( (options & (copy_prn | copy_vfc)) == copy_vfc ) {
|
|
if( len < fab.fab$b_fsz ) {
|
|
sts = RMS$_RSZ;
|
|
break;
|
|
}
|
|
rab.rab$l_rhb = rp;
|
|
rab.rab$l_rbf = rp + fab.fab$b_fsz;
|
|
len -= fab.fab$b_fsz;
|
|
}
|
|
|
|
do {
|
|
rab.rab$w_rsz = (uint16_t) (len % (MAXREC + 1));
|
|
sts = sys_put( &rab );
|
|
rab.rab$l_rbf += rab.rab$w_rsz;
|
|
len -= rab.rab$w_rsz;
|
|
} while( len > 0 && $SUCCESSFUL( sts ) );
|
|
++records;
|
|
if( $FAILED(sts) ) {
|
|
printmsg( COPY_WRITEERR, 0, rsbuf );
|
|
sts = printmsg( sts, MSG_CONTINUE, COPY_WRITEERR );
|
|
break;
|
|
}
|
|
}
|
|
} while( 0 );
|
|
|
|
if( buf != NULL ) free( buf );
|
|
sys_disconnect( &rab );
|
|
{
|
|
vmscond_t clsts;
|
|
|
|
if( $FAILS(clsts = sys_close( &fab )) && $SUCCESSFUL(sts) ) {
|
|
printmsg( COPY_CLOSEOUT, 0, rsbuf );
|
|
clsts = printmsg( clsts, MSG_CONTINUE, COPY_CLOSEOUT );
|
|
}
|
|
if( $SUCCESSFUL(sts) )
|
|
sts = clsts;
|
|
}
|
|
fclose( fromf );
|
|
|
|
if( options & copy_log ) {
|
|
sts = (options & copy_binary)? COPY_COPIEDB: COPY_COPIEDR;
|
|
|
|
sts = printmsg( sts, 0,
|
|
from, fab.fab$l_nam->nam$l_rsa,
|
|
records );
|
|
}
|
|
|
|
return sts;
|
|
}
|
|
|
|
/******************************************************************* output_file_name() */
|
|
|
|
char *output_file_name( const char *ofname, const char *ifname, int *flags ) {
|
|
char *ofn, *from, *fname;
|
|
const char *p, *q, *e;
|
|
size_t len, bufsize[2];
|
|
|
|
if( flags != NULL )
|
|
*flags = 0;
|
|
|
|
ofn= NULL;
|
|
bufsize[0] =
|
|
bufsize[1] = 0;
|
|
|
|
len = strlen( ifname ) +1;
|
|
if( (from = malloc( len )) == NULL ) {
|
|
return NULL;
|
|
}
|
|
memcpy( from, ifname, len );
|
|
#ifdef _WIN32
|
|
for( fname = from; *fname != '\0'; fname++ )
|
|
if( *fname == '/' )
|
|
*fname = '\\';
|
|
#endif
|
|
|
|
fname = basename( from );
|
|
e = strrchr( fname, '.' );
|
|
|
|
p = strrchr( ofname, ']' );
|
|
if( p == NULL )
|
|
p = strrchr( ofname, ':' );
|
|
if( p == NULL )
|
|
len = 0;
|
|
else
|
|
len = 1 + (size_t)( p - ofname );
|
|
|
|
if( !xpand( &ofn, bufsize, len ) ) {
|
|
free( from );
|
|
return NULL;
|
|
}
|
|
memcpy( ofn, ofname, len );
|
|
if( p == NULL )
|
|
p = ofname;
|
|
else
|
|
++p;
|
|
|
|
if( p[0] == '*' && (!p[1] || p[1] == '.' || p[1] == ';') ) {
|
|
if( flags )
|
|
*flags |= OF_WILD;
|
|
len = (e == NULL)? strlen(fname) : (size_t)(e - fname);
|
|
if( !xpand( &ofn, bufsize, len ) ) {
|
|
free( from );
|
|
return NULL;
|
|
}
|
|
memcpy( ofn+ bufsize[1] -len, fname, len );
|
|
++p;
|
|
} else {
|
|
q = strchr( p, '.' );
|
|
if( q == NULL )
|
|
q = strrchr( p, ';' );
|
|
if( q == NULL )
|
|
q = p + strlen( p );
|
|
len = (size_t)(q - p);
|
|
|
|
if( !xpand( &ofn, bufsize, len ) ) {
|
|
free( from );
|
|
return NULL;
|
|
}
|
|
memcpy( ofn + bufsize[1] - len, p, len );
|
|
p += len;
|
|
}
|
|
|
|
if( p[0] == '.' ) {
|
|
q = strrchr( p+1, ';' );
|
|
if( q == NULL )
|
|
q = strrchr( p+1, '.' );
|
|
if( q == NULL || q <= p )
|
|
q = p + strlen( p );
|
|
len = (size_t)(q - p );
|
|
if( len == 2 && p[1] == '*' ) {
|
|
if( flags )
|
|
*flags |= OF_WILD;
|
|
if( e != NULL ) {
|
|
len = strlen( e );
|
|
if( !xpand( &ofn, bufsize, len ) ) {
|
|
free( from );
|
|
return NULL;
|
|
}
|
|
memcpy( ofn+ bufsize[1] - len, e, len );
|
|
}
|
|
p += 2;
|
|
} else {
|
|
if( !xpand( &ofn, bufsize, len ) ) {
|
|
free( from );
|
|
return NULL;
|
|
}
|
|
memcpy( ofn+ bufsize[1] - len, p, len );
|
|
p += len;
|
|
}
|
|
}
|
|
if( *p == ';' || *p == '.' ) {
|
|
len = strlen( p );
|
|
if( !xpand( &ofn, bufsize, len ) ) {
|
|
free( from );
|
|
return NULL;
|
|
}
|
|
ofn[bufsize[1] - len] = ';';
|
|
memcpy( ofn+ bufsize[1] + 1 - len, p+1, len -1 );
|
|
p += len;
|
|
}
|
|
if( *p )
|
|
abort();
|
|
|
|
ofn[bufsize[1]] = '\0';
|
|
free( from );
|
|
|
|
return ofn;
|
|
}
|
|
|
|
/******************************************************************* xpand() */
|
|
|
|
static int xpand( char **buf, size_t size[2], size_t add ) {
|
|
char *nbuf;
|
|
size_t need;
|
|
|
|
need = (size[1] += add) + 1;
|
|
if( need < size[0] )
|
|
return 1;
|
|
|
|
nbuf = realloc( *buf, need + 32 + 1 );
|
|
if( nbuf == NULL ) {
|
|
free( *buf );
|
|
*buf = NULL;
|
|
return 0;
|
|
}
|
|
*buf = nbuf;
|
|
size[0] = need + 32 + 1;
|
|
return 1;
|
|
}
|