Import most recent simtools.zip and add a few extra tape converters

This commit is contained in:
Mark Pizzolato
2015-05-21 15:07:13 -07:00
parent abf806277d
commit 9eb5d72553
40 changed files with 10333 additions and 183 deletions

66
README.md Normal file
View File

@@ -0,0 +1,66 @@
simh support/migration tools.
ods2_readme.txt
config11 - a program for calculating the floating address space layout of a PDP-11 or VAX.
config11\config11.c
config11\config11.txt
converters - tools to convert/support simulator data files formats
converters\asc.c
converters\asc.txt
converters\dtos8cvt.c
converters\dtos8cvt.txt
converters\gt7cvt.c
converters\littcvt.c
converters\mtcvtfix.c
converters\mtcvtodd.c
converters\mtcvtv23.c
converters\mtcvtv23.txt
converters\mt2tpc.c
converters\sfmtcvt.c
converters\tar2mt.c
converters\tar2mt.txt
converters\tp512cvt.c
converters\tpc2mt.c
crossassemblers - cross assemblers for various machine architectures
crossassemblers\macro1.c
crossassemblers\macro11
crossassemblers\macro7.c
crossassemblers\macro8x.c
crossassemblers\macro11\changes
crossassemblers\macro11\depends
crossassemblers\macro11\dumpobj.c
crossassemblers\macro11\dumpobj.dsp
crossassemblers\macro11\license
crossassemblers\macro11\macro11.c
crossassemblers\macro11\macro11.dsp
crossassemblers\macro11\macro11.dsw
crossassemblers\macro11\macro11.h
crossassemblers\macro11\makefile
crossassemblers\macro11\mlb.c
crossassemblers\macro11\mlb.h
crossassemblers\macro11\object.c
crossassemblers\macro11\object.h
crossassemblers\macro11\rad50.c
crossassemblers\macro11\rad50.h
crossassemblers\macro11\stream2.c
crossassemblers\macro11\stream2.h
crossassemblers\macro11\todo
crossassemblers\macro11\util.c
crossassemblers\macro11\util.h
extracters - data extraction tools
extracters\backup
extracters\ckabstape.c
extracters\mmdir.c
extracters\mtdump.c
extracters\mtdump.txt
extracters\rawcopy
extracters\sdsdump.c
extracters\backup\backup.c
extracters\backup\backup.h
extracters\backup\backup.txt
extracters\rawcopy\RawCopy.c
extracters\rawcopy\RawCopy.txt
putr
putr\putr.com
putr\putr.txt
putr\readme.txt

69
converters/decsys.c Normal file
View File

@@ -0,0 +1,69 @@
/* This program converts a decimal listing to a DECtape file
Copyright (c) 1993-2003, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[])
{
int i, j, k, word;
char *ppos, oname[256];
int fill[256] = { 0 };
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".dtp");
else strcat (oname, ".dtp");
ifile = fopen (argv[i], "r");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
fwrite (fill, sizeof (int), 256, ofile);
for (j = 0;; j++) {
k = fscanf (ifile, "%d", &word);
if (k == EOF) break;
// printf ("%06o\n", word);
fwrite (&word, sizeof (int), 1, ofile);
}
fclose (ifile);
fclose (ofile);
}
return 0;
}

424
converters/hpconvert.c Normal file
View File

@@ -0,0 +1,424 @@
/* Convert an HP disc image between SIMH and HPDrive formats.
Copyright (c) 2012, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of the author shall not be used
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the author.
HPDrive is a free program written by Ansgar Kueckes that uses a PC and a GPIB
card to emulate a variety of vintage Hewlett-Packard disc and tape drives
that interface to computers via the HP-IB. It is available from:
http://www.hp9845.net/9845/projects/hpdrive/
This program converts an HP disc image from SIMH to HPDrive format or
vice-versa. This permits interchanging images between the two programs.
Usage: hpconvert <disc-image-file>
SIMH writes and reads disc images in little-endian format, regardless of the
byte order of the host. In addition, SIMH accesses images for the the 7905
and 7906 drives in platter order (i.e., all tracks on heads 0 and 1, followed
by all tracks on heads 2 and 3) to improve locality of access. It accesses
images for the 7920, 7925, and all CS/80 drives in cylinder order.
HPDrive writes and reads images in big-endian format, regardless of the byte
order of the host, and accesses all images in cylinder order.
This program swaps each pair of bytes in the disc image. In addition, if the
image is precisely the size of a 7905 or 7906 drive (15,151,104 or 20,201,472
bytes, respectively), the access order is restructured from platter to
cylinder, or vice-versa.
Note that SIMH does not currently create full-size disc images unless the
last sector on the drive is written. Therefore, it is recommended that new
images be initialized using the RTE FORMT or SWTCH programs to ensure that
the image files are of the correct size for this program and HPDrive.
This program creates a scratch file to store the converted image. Only when
conversion is complete is the original file deleted and the scratch file
renamed to the original file's name. Running the program twice on the same
file will return the file to its original configuration.
To decide the mode used in a 7905 or 7906 image, the program examines the OS
signature at the start of the file and compares it against a list of known
operating systems. If the OS signature is not recognized, the program
terminates without altering the file. Signature checking is not performed on
images other than those for the 7905 and 7906; those images are byte-swapped
unconditionally.
Signatures for these operating systems and compatible 7905/06 drives are
recognized:
- HP 1000 RTE-IVB: 7906H ICD
- HP 1000 RTE-6/VM: 7906H ICD
- HP 3000 MPE: 7905A/7906A MAC
The signatures are contained in the first four words at the start of each
disc image. In hex representation, they are:
- RTE-IVB ICD: 676D 06C0 776B 0B40 (LDA HHIGH ; CMA,CCE ; STA HRCNT ; ERB)
- RTE-6/VM ICD: 676D 06C0 776B 0B40 (LDA HHIGH ; CMA,CCE ; STA HRCNT ; ERB)
- MPE MAC: 5359 5354 454D 2044 ("SYSTEM D")
These represent the start of the boot extension for RTE and the start of the
system disc label for MPE. The boot extension machine instructions are:
RTE-IVB ICD
-----------
62000 LDA EQU 062000B
72000 STA EQU 072000B
01200 O0 EQU HSTRT-1400B
02600 063555 HSTRT ABS LDA+HHIGH-O0 (word 1)
02601 003300 CMA,CCE (word 2)
02602 073553 ABS STA+HRCNT-O0 (word 3)
02603 005500 ERB (word 4)
02753 000000 HRCNT NOP
02755 077377 NW#DS OCT 77377
02755 HHIGH EQU NW#DS
RTE-6/VM ICD
------------
062000 LDA EQU 062000B
072000 STA EQU 072000B
000000R O0 EQU HSTRT-1400B
01400 063555 HSTRT ABS LDA+HHIGH-O0 (word 1)
01401 003300 CMA,CCE (word 2)
01402 073553 ABS STA+HRCNT-O0 (word 3)
01403 005500 ERB (word 4)
01553 000000 HRCNT NOP
01555 077377 NW#DS OCT 77377
001555R HHIGH EQU NW#DS
And the disc label is:
MPE MAC and CS/80
-----------------
00000 051531 LABEL ASC 6,SYSTEM DISC (word 1)
00001 051524 (word 2)
00002 042515 (word 3)
00003 020104 (word 4)
00004 044523
00005 041440
*/
#include <memory.h>
#include <stdio.h>
/* MSVC does not provide "stdbool.h" or "unistd.h" */
#if defined (_MSC_VER)
typedef int bool;
const int false = 0;
#define isatty _isatty
#else
#include <stdbool.h>
#include <unistd.h>
#endif
#define TRACK_SIZE ( 1 * 1 * 48 * 256)
#define CYLINDER_SIZE ( 1 * 2 * 48 * 256)
#define HP7905_SIZE (411 * 3 * 48 * 256)
#define HP7906_SIZE (411 * 4 * 48 * 256)
int main (int argc,
char **argv)
{
const char *format [] = { "HPDrive", "SIMH" };
const char *signatures [] = { "\x67\x6D\x06\xC0\x77\x6B\x0B\x40", /* RTE ICD */
"SYSTEM D" }; /* MPE */
#define SIGNATURE_SIZE sizeof (signatures [0])
const int signature_count = sizeof (signatures) / SIGNATURE_SIZE;
FILE *fin, *fout;
size_t file_size, record_size;
char *name_in, *name_out;
char sig_fwd [SIGNATURE_SIZE], sig_rev [SIGNATURE_SIZE];
char hold, cylinder [CYLINDER_SIZE];
bool identified = false, reversed = false, debug = false;
int i, cyl, from_cyl, to_cyl, remap;
int platter, cylinder_size, hole_size;
/* Read the disc image filename. */
if (argc != 2) {
puts ("\nHPConvert version 1.1");
puts ("\nUsage: hpconvert <disc-image>");
return 1;
}
name_in = argv [1];
/* Open the source image file. */
fin = fopen (name_in, "rb");
if (!fin) {
printf ("Error: cannot open %s\n", name_in);
return 1;
}
/* Get the size of the image. */
fseek (fin, 0, SEEK_END);
file_size = ftell (fin);
/* The blocks of a 7905 or 7906 image (as determined by the image file size)
will need to be rearranged. Set "remap" to the number of surfaces that must
be remapped. */
if (file_size == HP7905_SIZE)
remap = 1;
else if (file_size == HP7906_SIZE)
remap = 2;
else
remap = 0;
/* If the image is a 7905 or 7906, it must be remapped it for the target system.
To do that, check the OS signature to determine if it is in SIMH or HPDrive
format, and set the "reversed" flag if the signature bytes in the image are
reversed (this implies a platter-to-cylinder remapping of a 7905 or 7906
image. */
if (remap) {
rewind (fin);
file_size = fread (sig_fwd, 1, SIGNATURE_SIZE, fin);
for (i = 0; i < SIGNATURE_SIZE; i = i + 2) {
sig_rev [i] = sig_fwd [i + 1];
sig_rev [i + 1] = sig_fwd [i];
}
for (i = 0; i < signature_count && identified == false; i++) {
reversed = strncmp (sig_rev, signatures [i], SIGNATURE_SIZE) == 0;
identified = reversed || strncmp (sig_fwd, signatures [i], SIGNATURE_SIZE) == 0;
}
/* If the signature cannot be identified, then we do not know how to remap it,
so report the problem and exit. */
if (identified == false) {
printf ("Error: 790%i image OS signature not recognized.\n", remap + 4);
fclose (fin);
return 1;
}
}
/* Generate a temporary filename for the converted image. */
name_out = tmpnam (NULL);
if (name_out == NULL) {
puts ("Error: cannot generate a temporary filename.");
fclose (fin);
return 1;
}
/* Create the temporary target image. */
fout = fopen (name_out, "wb");
if (!fout) {
printf ("Error: cannot create %s\n", name_out);
fclose (fin);
return 1;
}
/* Report the conversion that will be performed. */
if (remap)
printf ("Converting and remapping 790%i %s disc image to %s format.\n",
remap + 4,
format [reversed],
format [!reversed]);
else
puts ("Converting disc image.");
/* Enable debugging output if stdout has been redirected to a file. */
debug = isatty (fileno (stdout)) == 0;
/* Copy the source to the target image while swapping each byte pair. If the
disc image is for a 7905 or 7906, remap from platter to cylinder mode (or
vice-versa if the source image is not reversed).
In a platter-mode image, the upper platter tracks appear in order before the
lower platter tracks. For the 7906, the cylinder-head order of the tracks is
0-0, 0-1, 1-0, 1-1, ..., 410-0, 410-1, 0-2, 0-3, 1-2, 1-3, ..., 410-2, 410-3.
The 7905 order is the same, except that head 3 tracks are omitted.
In a cylinder-mode image, all tracks appear in cylinder-head order, i.e.,
0-0, 0-1, 0-2, 0-3, 1-0, 1-1, ..., 410-2, 410-3, for the 7906.
Remapping is performed in two passes, corresponding to the two platters. In
the first pass, the source tracks corresponding to the upper platter are
spread (platter-to-cylinder) or condensed (cylinder-to-platter) as they are
copied to the target file. In the second pass, the source tracks
corresponding to the lower platter are interleaved (platter-to-cylinder) or
appended (cylinder-to-platter) as they are copied to the target file.
In either case, the bytes of each 16-bit word are swapped before copying.
*/
rewind (fin);
/* If the image is not a 7905/06, simply swap each pair of bytes until EOF. */
if (!remap)
while (!feof (fin)) {
record_size = fread (cylinder, 1, CYLINDER_SIZE, fin);
for (i = 0; i < record_size; i = i + 2) {
hold = cylinder [i];
cylinder [i] = cylinder [i + 1];
cylinder [i + 1] = hold;
}
fwrite (cylinder, 1, record_size, fout);
}
/* If the image is a 7905/06, remap the tracks and swap pairs of bytes. Because
we know the disc type, we know the number of platters and cylinders present
in the image. */
else
for (platter = 0; platter < 2; platter++) {
/* Calculate the number of bytes per cylinder for the current platter. The
upper platter always has two tracks per cylinder. The lower platter has
either one (7905) or two (7906) tracks per cylinder. */
if (platter == 0) {
cylinder_size = TRACK_SIZE * 2;
hole_size = TRACK_SIZE * remap;
}
else {
cylinder_size = TRACK_SIZE * remap;
hole_size = TRACK_SIZE * 2;
}
/* Copy a platter. */
for (cyl = 0; cyl < 411; cyl++) {
/* If stdout has been redirected, output the remapping information. */
if (debug) {
from_cyl = ftell (fin) / TRACK_SIZE;
to_cyl = ftell (fout) / TRACK_SIZE;
if (platter == 1 && remap == 1)
printf ("track %i => %i\n", from_cyl, to_cyl);
else
printf ("track %i, %i => %i, %i\n",
from_cyl, from_cyl + 1, to_cyl, to_cyl + 1);
}
/* Read a cylinder from the source location. */
record_size = fread (cylinder, 1, cylinder_size, fin);
/* Swap the bytes. */
for (i = 0; i < record_size; i = i + 2) {
hold = cylinder [i];
cylinder [i] = cylinder [i + 1];
cylinder [i + 1] = hold;
}
/* Write the cylinder to the target location. */
fwrite (cylinder, 1, record_size, fout);
/* For platter-to-cylinder remapping, spread the tracks by seeking ahead in the
target file; this leaves room for the lower-platter tracks in between the
upper-platter tracks. For cylinder-to-platter remapping, condense the
cylinders by seeking ahead in the source file to the next track on the
current platter. */
if (reversed)
fseek (fout, hole_size, SEEK_CUR);
else
fseek (fin, hole_size, SEEK_CUR);
}
/* End of the current platter. For platter-to-cylinder remapping, reposition
the target file to the first "hole" left for the lower-platter tracks. For
cylinder-to-platter remapping, reposition the source file to access the first
lower-platter tracks. */
if (reversed)
fseek (fout, cylinder_size, SEEK_SET);
else
fseek (fin, cylinder_size, SEEK_SET);
}
/* Close the files. */
fclose (fin);
fclose (fout);
/* Delete the original file and replace it by the reversed file. */
if (unlink (name_in)) {
puts ("Error: cannot replace original file, which is unchanged.");
unlink (name_out);
return 1;
}
else if (rename (name_out, name_in)) {
printf ("Error: cannot rename temporary file %s.\n", name_out);
return 1;
}
/* Return success. */
return 0;
}

120
converters/indent.c Normal file
View File

@@ -0,0 +1,120 @@
/* This program converts a SIMH source to 4-tabbing
Copyright (c) 2005, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#define COMM_POS 56
int main (int argc, char *argv[])
{
int i, j, fill, itc, incomm, in8tab, ip, op;
char *ppos, iline[256], oline[256], oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: asc file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new");
else strcat (oname, ".new");
ifile = fopen (argv[i], "ra");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wa");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
for (incomm = in8tab = 0;;) {
for (j = 0; j < 256; j++) iline[j] = oline[j] = 0;
if (fgets (iline, 256, ifile) == NULL) break;
ip = 0;
if (!incomm) {
if (strncmp (iline, " ", 4) == 0) in8tab = 1;
else if (!isspace (iline[0]) && (iline[0] != '#') && strncmp (iline, "/*", 2)) in8tab = 0;
if ((strncmp (iline, "else {\t", 7) == 0) &&
!isspace (iline[7])) {
fputs ("else {\n", ofile);
ip = 6;
}
else if ((strncmp (iline, "do {\t", 5) == 0) &&
!isspace (iline[5])) {
fputs ("do {\n", ofile);
ip = 4;
}
}
for (itc = op = 0; iline[ip]; ip++) {
if (!incomm && (op == 0)) {
if (iline[ip] == '\t') {
itc++;
continue;
}
else if (itc) {
fill = (itc * 8) - (in8tab? 0: 4);
while (fill--) oline[op++] = ' ';
}
}
switch (iline[ip]) {
case '/':
if (!incomm && (iline[ip + 1] == '*')) {
incomm = 1;
if (ip != 0) {
while (op < COMM_POS) oline[op++] = ' ';
}
}
oline[op++] = iline[ip];
break;
case '*':
if (incomm && (iline[ip + 1] == '/')) incomm = 0;
oline[op++] = iline[ip];
break;
case '\t':
fill = 8 - (op % 8);
while (fill--) oline[op++] = ' ';
break;
case '\r':
break;
default:
oline[op++] = iline[ip];
break;
}
}
if (op) fputs (oline, ofile);
}
fclose (ifile);
fclose (ofile);
}
return 0;
}

71
converters/m8376.c Normal file
View File

@@ -0,0 +1,71 @@
/* This program assembles 8 PROM files into a 32bit binary file
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static const int fnum[8] = { 60, 58, 74, 73, 90, 89, 106, 105 };
int main (int argc, char *argv[])
{
FILE *fi[8], *outf;
char fname[256];
int c, i, j;
unsigned int wd[1024];
for (i = 0; i < 8; i++) {
sprintf (fname, "C:\\temp\\m8376\\m8376e%03d.bin", fnum[i]);
fi[i] = fopen (fname, "rb");
if (fi[i] == NULL) {
printf ("Can't open file %s\n", fname);
return 0;
}
}
for (i = 0; i < 1024; i++) {
wd[i] = 0;
for (j = 7; j >=0; j--) {
c = fgetc (fi[j]);
if (c == EOF) {
printf ("Premature end of file on file %d\n", i);
return 0;
}
wd[i] = (wd[i] << 4) | (c & 0xF);
}
}
for (i = 0; i < 8; i++) fclose (fi[i]);
outf = fopen ("c:\\prom.bin", "wb");
if (outf == NULL) {
printf ("Can't open output file\n");
return 0;
}
fwrite (wd, 1024, sizeof (int), outf);
fclose (outf);
return 0;
}

87
converters/mt2tpc.c Normal file
View File

@@ -0,0 +1,87 @@
/* This program converts a simh simulated magtape to TPC format
Copyright (c) 1993-1999, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define FLPSIZ 65536
int main (int argc, char *argv[])
{
int i, k, fc, wc, rc;
unsigned char bc[4] = { 0 };
unsigned char buf[FLPSIZ];
char *progname = argv[0];
char *ppos, oname[256];
FILE *ifile, *ofile;
if (argc < 2) {
fprintf (stderr, "Usage: %s file {file2 ...}\n", progname);
fprintf (stderr, "This will create a TPC tape image file named file.tpc from the input simh image file\n");
exit (0);
}
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".tpc");
else strcat (oname, ".tpc");
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
fc = 1; rc = 0;
for (;;) {
k = fread (bc, sizeof (char), 4, ifile);
if (k == 0) break;
if (bc[2] | bc[3]) {
printf ("Invalid record size, record %d, size = 0x%02X%02X%02X%02X\n", rc, bc[3], bc[2], bc[1], bc[0]);
break; }
wc = ((unsigned int) bc[1] << 8) | (unsigned int) bc[0];
wc = (wc + 1) & ~1;
fwrite (bc, sizeof (char), 2, ofile);
if (wc) {
k = fread (buf, sizeof (char), wc, ifile);
for ( ; k < wc; k++) buf[k] =0;
fwrite (buf, sizeof (char), wc, ofile);
k = fread (bc, sizeof (char), 4, ifile);
rc++; }
else { if (rc) printf ("End of file %d, record count = %d\n", fc, rc);
else printf ("End of tape\n");
fc++;
rc = 0; }
}
fclose (ifile);
fclose (ofile);
}
return 0;
}

66
converters/noff.c Normal file
View File

@@ -0,0 +1,66 @@
/* This program strips FF from a source listing
Copyright (c) 2005, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
int main (int argc, char *argv[])
{
int i, c, ffc;
char *ppos, oline[256], oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: asc file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new");
else strcat (oname, ".new");
ifile = fopen (argv[i], "ra");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wa");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
for (ffc = 0; (c = fgetc (ifile)) != EOF; ) {
if (c == '\f') ffc++;
else fputc (c, ofile);
}
if (ffc) printf ("Form feeds removed: %d\n", ffc);
fclose (ifile);
fclose (ofile);
}
return 0;
}

72
converters/strrem.c Normal file
View File

@@ -0,0 +1,72 @@
/* This program removes a string
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
const char *srem = "e-drive\\";
int main (int argc, char *argv[])
{
int i, slen;
char *ppos, *fpos, *tpos, oname[256], line[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: strrem file [file...]\n");
exit (0); }
slen = strlen (srem);
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new");
else strcat (oname, ".new");
ifile = fopen (argv[i], "r");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "w");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
while (fgets (line, 255, ifile) != NULL) {
tpos = strstr (line, srem);
if (tpos) {
fpos = tpos + slen;
while (*fpos) *tpos++ = *fpos++;
*tpos = 0;
}
fputs (line, ofile);
}
fclose (ifile);
fclose (ofile);
}
return 0;
}

74
converters/strsub.c Normal file
View File

@@ -0,0 +1,74 @@
/* This program removes a string
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[])
{
int i, rmvlen;
char *ppos, *fpos, *tpos, *rmv, *ins, oname[256], line[256];
FILE *ifile, *ofile;
if ((argc < 4) || (argv[0] == NULL)) {
printf ("Usage is: strsub s1 s2 file [file...]\n");
exit (0); }
rmv = argv[1];
rmvlen = strlen (rmv);
ins = argv[2];
for (i = 3; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new");
else strcat (oname, ".new");
ifile = fopen (argv[i], "r");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "w");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
while (fgets (line, 255, ifile) != NULL) {
tpos = strstr (line, rmv);
if (tpos) {
*tpos = 0;
fputs (line, ofile);
fputs (ins, ofile);
fpos = tpos + rmvlen;
fputs (fpos, ofile);
}
else fputs (line, ofile);
}
fclose (ifile);
fclose (ofile);
}
return 0;
}

92
converters/tar2mt.c Normal file
View File

@@ -0,0 +1,92 @@
/* This program converts a tar file to a simulated 8192B blocked magtape
Copyright (c) 2015, Mark Pizzolato
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
MARK PIZZOLATO BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Mark Pizzolato shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Mark Pizzolato.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
main (int argc, char **argv)
{
FILE *fIn = NULL, *fOut = NULL;
size_t blocksize = 8192, bytes_read;
unsigned char *br = (unsigned char *)&bytes_read;
char *progname = argv[0];
char *buf = NULL;
char *tapname = NULL;
if (argc < 2) {
fprintf (stderr, "Usage: %s {-b blocksize} tarfile {tarfile2 ...}\n", progname);
fprintf (stderr, "This will create a simh tap file named tarfile.tap from the input tar file\n");
fprintf (stderr, "blocksize defaults to 8192\n");
exit (0);
}
if ((argc >= 3) && ((strcmp("-b", argv[1])) || (strcmp("--blocksize", argv[1])))) {
if (atoi (argv[2]) <= 0) {
fprintf (stderr, "Invalid blocksize: %s\n", argv[2]);
exit (0);
}
blocksize = (size_t)atoi (argv[2]);
argc -= 2;
argv += 2;
}
while (--argc > 0) {
++argv;
tapname = realloc (tapname, 5 + strlen (argv[0]));
if (NULL == (fIn = fopen (argv[0], "rb"))) {
fprintf (stderr, "Error Opening tar file '%s': %s\n", argv[0], strerror (errno));
break;
}
strcpy (tapname, argv[0]);
strcat (tapname, ".tap");
if (NULL == (fOut = fopen (tapname, "wb"))) {
fprintf (stderr, "Error Opening tap file '%s': %s\n", tapname, strerror (errno));
break;
}
buf = realloc (buf, blocksize);
while (1) {
bytes_read = fread (buf, 1, blocksize, fIn);
if (bytes_read == 0)
break;
fputc (br[0], fOut); fputc (br[1], fOut); fputc (br[2], fOut); fputc (br[3], fOut);
fwrite (buf, 1, bytes_read, fOut);
fputc (br[0], fOut); fputc (br[1], fOut); fputc (br[2], fOut); fputc (br[3], fOut);
}
fputc (br[0], fOut); fputc (br[1], fOut); fputc (br[2], fOut); fputc (br[3], fOut);
fputc (br[0], fOut); fputc (br[1], fOut); fputc (br[2], fOut); fputc (br[3], fOut);
fclose (fIn);
fIn = NULL;
fclose (fOut);
fOut = NULL;
}
if (fIn)
fclose (fIn);
if (fOut)
fclose (fOut);
free (tapname);
free (buf);
exit(0);
}

25
converters/tar2mt.txt Normal file
View File

@@ -0,0 +1,25 @@
tar2mt converts a tar file to a simh .tap tape image.
.tap format tape images have the format
4 byte record length 1
record 1
repeat of 4 byte record length 1
4 byte record length 2
record 2
repeat of 4 byte record length 2
:
4 bytes = 00000000 for end of file
and so on. This is the tape format expected by simh, Tim Stark's TS10,
and John Wilson's E11.
tar2mt is invoked by
tar2mt {-b blocksize} file1 file2 file3...
blocksize defaults to 8192.
Each file in turn is converted from a tar file to a .tap tape image. The
input file can have any extension; the converted file will have a .tap
extension.

84
converters/tpc2mt.c Normal file
View File

@@ -0,0 +1,84 @@
/* This program converts a TPC simulated magtape to simh format
Copyright (c) 2015, Robert M. Supnik, Mark Pizzolato
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define FLPSIZ 65536
int main (int argc, char *argv[])
{
int i, k, fc, wc, rc;
unsigned char bc[4] = { 0 };
unsigned char buf[FLPSIZ];
char *progname = argv[0];
char *ppos, oname[256];
FILE *ifile, *ofile;
if (argc < 2) {
fprintf (stderr, "Usage: %s file {file2 ...}\n", progname);
fprintf (stderr, "This will create a simh tap file named file.tap from the input tpc image file\n");
exit (0);
}
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".tap");
else strcat (oname, ".tap");
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
fc = 1; rc = 0;
for (;;) {
k = fread (bc, sizeof (char), 2, ifile);
if (k == 0) break;
wc = ((unsigned int) bc[1] << 8) | (unsigned int) bc[0];
wc = (wc + 1) & ~1;
fwrite (bc, sizeof (char), 4, ofile);
if (wc) {
k = fread (buf, sizeof (char), ((unsigned int) bc[1] << 8) | (unsigned int) bc[0], ifile);
for ( ; k < wc; k++) buf[k] =0;
fwrite (buf, sizeof (char), wc, ofile);
k = fwrite (bc, sizeof (char), 4, ofile);
rc++; }
else { if (rc) printf ("End of file %d, record count = %d\n", fc, rc);
else printf ("End of tape\n");
fc++;
rc = 0; }
}
fclose (ifile);
fclose (ofile);
}
return 0;
}

930
crossassemblers/hpasm.c Normal file
View File

@@ -0,0 +1,930 @@
/*
** HPASM.C -- Assembler for HP2100
*/
/****************************************************/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/****************************************************/
#define MXSYM 1500
#define MXLABEL 5
#define ALLOW_SPECIALS_IN_LABEL 1
/****************************************************/
typedef struct {
char name[MXLABEL+1];
long value;
} SYM;
/****************************************************/
long nbsyms;
SYM symtab[MXSYM];
long pass;
long addr;
char line[80];
long lp;
long line_count;
long err_count;
long print_flag; /* =1 if current line has been printed */
int ifn_flag=0; /* =1 if IFN does not skip */
int ifz_flag=0; /* =1 if IFZ does not skip */
int xif_flag=0; /* =1 if we are skipping until XIF */
int rep_count=0; /* >0 if REP statement in process */
/****************************************************/
/*
** Variables for listing output routines
*/
char listfilename[256];
FILE *listfile;
/****************************************************/
start_listing (nam)
/*
** Initialize listing output file
*/
char *nam;
{
char *ppos;
strncpy (listfilename, nam, 250);
if (ppos = strrchr (listfilename, '.')) strcpy (ppos, ".lst");
else strcat (listfilename, ".lst");
listfile = fopen (listfilename, "w");
}
/****************************************************/
finish_listing () {
/*
** Finish off listing output file
*/
fclose (listfile);
printf ("Listing is in %s\n", listfilename);
}
/****************************************************/
/*
** Variables for binary output routines
*/
char outfilename[256];
FILE *outfile;
long outaddr;
long outcount;
long outbufsize=27;
long outbuf[27];
/****************************************************/
start_output (nam)
/*
** Initialize binary output file
*/
char *nam;
{
char *ppos;
strncpy (outfilename, nam, 250);
if (ppos = strrchr (outfilename, '.')) strcpy (ppos, ".bin");
else strcat (outfilename, ".bin");
outfile = fopen (outfilename, "wb");
outaddr = 0;
outcount = 0;
}
/****************************************************/
send_output () {
/*
** Write block to binary output file
*/
long ii,sum;
fputc (outcount, outfile);
fputc (0, outfile);
fputc (outaddr >> 8, outfile);
fputc (outaddr & 255, outfile);
sum = outaddr;
for (ii=0 ; ii < outcount ; ii++) {
fputc (outbuf[ii] >> 8, outfile);
fputc (outbuf[ii] & 255, outfile);
sum += outbuf[ii];
}
fputc (sum >> 8, outfile);
fputc (sum & 255, outfile);
outcount = 0;
}
/****************************************************/
output_word (addr,word)
/*
** Write word to binary output file
*/
long addr;
long word;
{
if (outcount && (outaddr + outcount) != addr) {
send_output();
}
if (!outcount) outaddr = addr;
outbuf[outcount++] = word;
if (outcount == outbufsize) {
send_output();
}
}
/****************************************************/
finish_output () {
/*
** Finish current output block, write trailing leader,
** and close output file
*/
int ii;
if (outcount) send_output();
for (ii=0; ii<20; ii++) fputc (0, outfile);
fclose (outfile);
printf ("Output is in %s\n", outfilename);
}
/****************************************************/
emit (code)
long code;
{
fprintf (listfile, " %05lo %06lo ", addr, code);
if (!print_flag) {
fprintf (listfile, "%s", line);
print_flag = 1;
}
fprintf (listfile, "\n");
output_word (addr, code);
addr++;
}
/****************************************************/
err (text)
char *text;
{
if (!print_flag) {
fprintf (listfile, " %12s %s\n", " ", line);
print_flag = 1;
}
fprintf (listfile, "ERROR: %s\n", text);
err_count++;
}
/****************************************************/
int is_valid_label_char (ch)
char ch;
{
if (isalpha(ch)) return (1);
if (isdigit(ch)) return (1);
if (ch=='.') return (1);
#if ALLOW_SPECIALS_IN_LABEL
if (ch=='&') return (1);
if (ch=='?') return (1);
if (ch=='#') return (1);
if (ch=='/') return (1);
if (ch=='%') return (1);
if (ch=='$') return (1);
if (ch=='[') return (1);
if (ch=='@') return (1);
if (ch=='!') return (1);
if (ch=='^') return (1);
#endif
return (0);
}
/****************************************************/
void insert_label (label, value)
char *label;
long value;
/*
** Insert label into symbol table
*/
{
long i;
if (strlen(label)>MXLABEL) {
err ("Symbol name > 5");
return;
}
for (i=0; i<nbsyms; i++) {
if (!strcmp(symtab[i].name, label)) {
err ("Duplicate symbol");
return;
}
}
if (nbsyms == MXSYM) {
err ("Symbol table is full!");
return;
}
strcpy (symtab[nbsyms].name, label);
symtab[nbsyms].value = value;
nbsyms++;
}
/****************************************************/
void find_label (label, value)
char *label;
long *value;
{
long i;
for (i=0; i<nbsyms; i++) {
if (!strcmp(symtab[i].name, label)) {
*value = symtab[i].value;
return;
}
}
err ("Undefined symbol");
*value=0;
}
/****************************************************/
show_labels ()
{
long i;
for (i=0; i<nbsyms; i++) {
fprintf (listfile, "%-6s %06lo \n", symtab[i].name, symtab[i].value );
}
}
/****************************************************/
int double_to_hp (num, a, b)
double num;
long *a,*b;
/*
** Convert floating point number to HP 21xx format
** Accepts:
** num Number to convert
** Returns:
** a,b Number in HP format
** ret 0=Success, -2=Underflow, -3=Overflow
*/
{
int neg=0;
long frac;
int exp=0;
*a = 0; *b = 0;
if (num == 0.0) return (0);
if (num < 0.0) { num = -num; neg = 1; }
while (num >= 1.0) { num = num / 2; exp++; }
while (num < 0.5) { num = num * 2; exp--; }
if (neg) num = -num;
if (neg) num += (0177 / 65536.0 / 65536.0);
else num += (0200 / 65536.0 / 65536.0);
if (neg && num >= -0.5) { num = num * 2; exp--; }
if (!neg && num >= 1.0) { num = num / 2; exp++; }
if (exp < -128) return (-2);
if (exp > 127) {
if (neg) { *a = 0x8000; *b = 0x01FE; }
else { *a = 0x7FFF; *b = 0xFFFE; }
return (-3);
}
frac = num * 65536.0 * 128.0 * 256.0;
exp = exp << 1;
if (exp < 0) exp++;
*a = (frac >> 16) & 0xFFFF;
*b = (frac & 0xFF00) | (exp & 0x00FF);
return (0);
}
/****************************************************/
parse_digits (base, out)
int base;
long *out;
{
long dig, val;
val = 0;
dig = line[lp] - '0';
while (dig>=0 && dig<base) {
val = val*base + dig;
dig = line[++lp] - '0';
}
*out = val;
}
/****************************************************/
parse_const (out)
long *out;
{
long save, val;
save = lp;
parse_digits (10, &val);
if (toupper(line[lp])=='B') {
lp = save;
parse_digits (8,&val);
if (toupper(line[lp])=='B') lp++;
else err ("Illegal octal digit");
}
*out = val;
}
/****************************************************/
parse_sym (out)
long *out;
{
char sym[MXLABEL+1];
int count,done;
char ch;
count=0;
done=0;
while (!done) {
ch = line[lp];
if (is_valid_label_char(ch)) {
if (count<MXLABEL) sym[count]=ch;
count++;
lp++;
} else {
done=1;
}
}
if (count>MXLABEL) {
err ("Illegal symbol");
*out=0;
} else {
sym[count]=0;
find_label (sym, out);
}
}
/****************************************************/
parse_term (out)
long *out;
{
char ch;
ch = line[lp];
if (isdigit(ch)) parse_const (out);
else if (is_valid_label_char(ch)) parse_sym (out);
else if (ch=='*') { lp++; *out = addr; }
else {
err ("Syntax error in expression");
*out=0;
}
}
/****************************************************/
parse_neg (out)
long *out;
{
long temp;
if (line[lp]=='-') {
lp++;
parse_term (&temp);
*out = (-temp) & 0xFFFF;
} else if (line[lp]=='+') {
lp++;
parse_term (out);
} else {
parse_term (out);
}
}
/****************************************************/
parse_sum (out)
long *out;
{
long v1,v2,op;
parse_neg (&v1);
while (line[lp]=='+' || line[lp]=='-') {
op = line[lp++];
parse_neg (&v2);
if (op=='+') v1 = v1 + v2;
if (op=='-') v1 = v1 - v2;
}
*out = v1 & 0xFFFF;
}
/****************************************************/
parse_arg (out)
long *out;
{
while (isspace (line[lp])) lp++;
/* while (line[lp]==' ') lp++; */
parse_sum (out);
}
/****************************************************/
parse_oct (out)
long *out;
{
long sign,val;
while (isspace (line[lp])) lp++;
/* while (line[lp]==' ') lp++; */
sign = line[lp];
if (sign=='+' || sign=='-') lp++;
parse_digits (8, &val);
if (sign=='-') val = (-val) & 0xFFFF;
*out =val;
}
/****************************************************/
parse_dec (out, nbwords)
long *out, *nbwords;
{
long save,sign,val,a,b;
extern double atof();
double num;
while (isspace (line[lp])) lp++;
/* while (line[lp]==' ') lp++; */
save = lp;
sign = line[lp];
if (sign=='+' || sign=='-') lp++;
parse_digits (10, &val);
if (sign=='-') val = (-val) & 0xFFFF;
out[0] = val;
*nbwords = 1;
if (line[lp]=='.' || toupper(line[lp])=='E') {
num = atof( &(line[save]) );
while (isdigit(line[lp]) || line[lp]=='.' || toupper(line[lp])=='E') lp++;
double_to_hp (num, &a, &b);
out[0] = a;
out[1] = b;
*nbwords = 2;
}
}
/****************************************************/
mem_group (opcode, code)
int opcode;
long *code;
{
long arg, out;
parse_arg (&arg);
if (arg < 02000) {
out = opcode + arg;
} else if ((arg & 0776000) == (addr & 0776000)) {
out = opcode + 02000 + (arg & 01777);
} else {
err ("Operand page error");
out = opcode;
}
if (line[lp]==',' && toupper(line[lp+1])=='I') {
out = out + 0100000L;
lp += 2;
}
code[0] = out;
}
/****************************************************/
io_group (opcode, code)
int opcode;
long *code;
{
long arg, out;
parse_arg (&arg);
if (arg > 077) {
err ("Select code > 77B");
arg = 0;
}
out = opcode + arg;
if (line[lp]==',' && toupper(line[lp+1])=='C') {
out += 001000;
lp += 2;
}
code[0] = out;
}
/****************************************************/
overflow_group (opcode, code)
int opcode;
long *code;
{
code[0] = opcode;
if (isspace (line[lp]) && toupper(line[lp+1])=='C') {
/* if (line[lp]==' ' && line[lp+1]=='C') { */
code[0] += 001000;
lp += 2;
}
}
/****************************************************/
parse_label (label)
char *label;
{
int i=0;
while (is_valid_label_char(line[lp])) {
if (i<MXLABEL) label[i++]=line[lp];
lp++;
}
label[i]=0;
}
/****************************************************/
int try (instr)
char *instr;
{
int ii,out;
for (ii=0; instr[ii]; ii++) {
if (toupper(line[lp+ii]) != instr[ii]) {
return (0);
}
}
if (isalpha(line[lp+ii])) out=0;
else {
lp += ii;
if (line[lp]==',') lp++;
out=1;
}
return (out);
}
/****************************************************/
int end_of_line()
{
int ll,out;
ll=lp;
out=0;
if (isspace (line[ll])) return 1;
while (isspace (line[ll])) ll++;
/* if (line[ll]=' ') return(1);
while (line[ll]==' ') ll++; */
if (line[ll]==';' || line[ll]=='\n' || line[ll]==0) {
out=1;
}
return (out);
}
/****************************************************/
int try_mem_group (code)
long *code;
{
int ok=1;
if (try("NOP")) code[0]=0;
else if (try("AND")) mem_group (010000, code);
else if (try("XOR")) mem_group (020000, code);
else if (try("IOR")) mem_group (030000, code);
else if (try("JSB")) mem_group (014000, code);
else if (try("JMP")) mem_group (024000, code);
else if (try("ISZ")) mem_group (034000, code);
else if (try("ADA")) mem_group (040000, code);
else if (try("ADB")) mem_group (044000, code);
else if (try("CPA")) mem_group (050000, code);
else if (try("CPB")) mem_group (054000, code);
else if (try("LDA")) mem_group (060000, code);
else if (try("LDB")) mem_group (064000, code);
else if (try("STA")) mem_group (070000, code);
else if (try("STB")) mem_group (074000, code);
else ok=0;
return (ok);
}
/****************************************************/
int try_srg_a (code)
long *code;
{
int ok=0;
long out=0;
long save=lp;
if (try("ALS")) out += 001000;
else if (try("ARS")) out += 001100;
else if (try("RAL")) out += 001200;
else if (try("RAR")) out += 001300;
else if (try("ALR")) out += 001400;
else if (try("ERA")) out += 001500;
else if (try("ELA")) out += 001600;
else if (try("ALF")) out += 001700;
if (try("CLE")) out += 000040;
if (try("SLA")) out += 000010;
if (try("ALS")) out += 000020;
else if (try("ARS")) out += 000021;
else if (try("RAL")) out += 000022;
else if (try("RAR")) out += 000023;
else if (try("ALR")) out += 000024;
else if (try("ERA")) out += 000025;
else if (try("ELA")) out += 000026;
else if (try("ALF")) out += 000027;
if (out && end_of_line()) {
code[0] = out;
ok=1;
} else {
lp = save;
ok=0;
}
return (ok);
}
/****************************************************/
int try_srg_b (code)
long *code;
{
int ok=0;
long out=0;
long save=lp;
if (try("BLS")) out += 001000;
else if (try("BRS")) out += 001100;
else if (try("RBL")) out += 001200;
else if (try("RBR")) out += 001300;
else if (try("BLR")) out += 001400;
else if (try("ERB")) out += 001500;
else if (try("ELB")) out += 001600;
else if (try("BLF")) out += 001700;
if (try("CLE")) out += 000040;
if (try("SLB")) out += 000010;
if (try("BLS")) out += 000020;
else if (try("BRS")) out += 000021;
else if (try("RBL")) out += 000022;
else if (try("RBR")) out += 000023;
else if (try("BLR")) out += 000024;
else if (try("ERB")) out += 000025;
else if (try("ELB")) out += 000026;
else if (try("BLF")) out += 000027;
if (out && end_of_line()) {
code[0] = out + 004000;
ok=1;
} else {
lp = save;
ok=0;
}
return (ok);
}
/****************************************************/
int try_asg_a (code)
long *code;
{
int ok=0;
long out=0;
long save=lp;
if (try("CLA")) out += 000400;
else if (try("CMA")) out += 001000;
else if (try("CCA")) out += 001400;
if (try("SEZ")) out += 000040;
if (try("CLE")) out += 000100;
else if (try("CME")) out += 000200;
else if (try("CCE")) out += 000300;
if (try("SSA")) out += 000020;
if (try("SLA")) out += 000010;
if (try("INA")) out += 000004;
if (try("SZA")) out += 000002;
if (try("RSS")) out += 000001;
if (out && end_of_line()) {
code[0] = out + 002000;
ok=1;
} else {
lp = save;
ok=0;
}
return (ok);
}
/****************************************************/
int try_asg_b (code)
long *code;
{
int ok=0;
long out=0;
long save=lp;
if (try("CLB")) out += 000400;
else if (try("CMB")) out += 001000;
else if (try("CCB")) out += 001400;
if (try("SEZ")) out += 000040;
if (try("CLE")) out += 000100;
else if (try("CME")) out += 000200;
else if (try("CCE")) out += 000300;
if (try("SSB")) out += 000020;
if (try("SLB")) out += 000010;
if (try("INB")) out += 000004;
if (try("SZB")) out += 000002;
if (try("RSS")) out += 000001;
if (out && end_of_line()) {
code[0] = out + 006000;
ok=1;
} else {
lp = save;
ok=0;
}
return (ok);
}
/****************************************************/
int try_io_group (code)
long *code;
{
int ok=1;
if (try("NOP")) code[0]=0;
else if (try("HLT")) io_group (0102000, code);
else if (try("STF")) io_group (0102100, code);
else if (try("CLF")) io_group (0103100, code);
else if (try("SFC")) io_group (0102200, code);
else if (try("SFS")) io_group (0102300, code);
else if (try("MIA")) io_group (0102400, code);
else if (try("MIB")) io_group (0106400, code);
else if (try("LIA")) io_group (0102500, code);
else if (try("LIB")) io_group (0106500, code);
else if (try("OTA")) io_group (0102600, code);
else if (try("OTB")) io_group (0106600, code);
else if (try("STC")) io_group (0102700, code);
else if (try("CLC")) io_group (0106700, code);
else ok=0;
return (ok);
}
/****************************************************/
int try_overflow (code)
long *code;
{
int ok=1;
if (try("STO")) code[0] = 0102101;
else if (try("CLO")) code[0] = 0103101;
else if (try("SOC")) overflow_group (0102201, code);
else if (try("SOS")) overflow_group (0102301, code);
else ok=0;
return (ok);
}
/****************************************************/
asm_pass (f)
FILE *f;
{
int done,count;
char label[MXLABEL+1];
long arg,code[2];
done=0;
while (!done) {
if (!fgets(line, sizeof(line), f)) {
done=1;
} else {
line_count++;
lp=strlen(line);
if (lp>0 && line[lp-1]=='\n') line[lp-1]=0;
print_flag = 0;
count = rep_count;
if (!count) count=1;
rep_count=0;
if (line[0]=='*') {
if (pass==2) {
fprintf (listfile, "%s\n", line);
print_flag = 1;
}
} else
while (count > 0) {
count--;
lp=0;
parse_label (label);
while (isspace (line[lp])) lp++;
/* while (line[lp]==' ') lp++; */
if (try("IFN")) {
if (!ifn_flag) xif_flag=1;
} else if (try("IFZ")) {
if (!ifz_flag) xif_flag=1;
} else if (try("XIF")) {
xif_flag=0;
} else if (xif_flag) {
while (line[lp]) lp++;
} else if (try("ORG")) {
parse_arg (&arg);
addr = arg;
if (pass==2) {
fprintf (listfile, " %05lo %s\n", addr, line);
print_flag = 1;
if (strlen(label)) err ("Unexpected label");
}
} else if (try("EQU")) {
parse_arg (&arg);
if (pass==1) {
if (strlen(label)) insert_label (label, arg);
} else {
fprintf (listfile, " %05lo %s\n", arg, line);
print_flag = 1;
if (!strlen(label)) err ("Label required");
}
} else if (!isalpha(line[lp])) {
if (pass==2) err ("No instruction on line");
} else {
if (pass==1 && strlen(label)) insert_label (label,addr);
if (try("HED") || try("SUP") || try("SPC") ||
try("SKP") || try("UNS") || try("UNL") ||
try("LST")) {
/* Listing control ops are ignored */
} else if (try("END")) {
/* No action required */
} else if (try("REP")) {
parse_arg (&arg);
if (arg < 1 || arg > 9999) {
err ("Illegal repeat count");
} else {
rep_count = arg;
}
} else if (try("ABS")) {
if (pass==1) addr++;
else {
parse_arg (code);
emit (code[0]);
}
} else if (try("DEF")) {
if (pass==1) addr++;
else {
parse_arg (code);
if (line[lp]==',' && toupper(line[lp+1])=='I') {
code[0] |= 0x8000;
lp += 2;
}
emit (code[0]);
}
} else if (try("DEC")) {
long nbwords;
parse_dec (code, &nbwords);
if (pass==1) addr += nbwords;
else {
if (nbwords > 0) emit (code[0]);
if (nbwords > 1) emit (code[1]);
}
} else if (try("OCT")) {
while (1) {
parse_oct (code);
if (pass==1) addr++;
else emit (code[0]);
if (line[lp]==',') lp++;
else break;
}
} else if (try("ASC")) {
long nbwords,c1,c2;
parse_arg (&nbwords);
if (pass==1) addr += nbwords;
else if (line[lp++]!=',') err ("Missing comma");
else
while (nbwords>0) {
if (line[lp]>31) c1=line[lp++]; else c1=' ';
if (line[lp]>31) c2=line[lp++]; else c2=' ';
emit (c1*256 + c2);
nbwords--;
}
} else if (try("BSS")) {
long nbwords;
if (pass==2) {
fprintf (listfile, " %05lo %s\n",
addr, line);
print_flag = 1;
}
parse_arg (&nbwords);
addr += nbwords;
}
else if (pass==1) addr++;
else if (try_mem_group(code)) emit (code[0]);
else if (try_srg_a(code)) emit (code[0]);
else if (try_srg_b(code)) emit (code[0]);
else if (try_asg_a(code)) emit (code[0]);
else if (try_asg_b(code)) emit (code[0]);
else if (try_io_group(code)) emit (code[0]);
else if (try_overflow(code)) emit (code[0]);
else {
emit (0L);
err ("Unknown instruction");
}
}
if (pass==2 && !end_of_line()) err ("Missing End-of-line");
if (pass==2 && !print_flag) fprintf (listfile, " %12s %s\n",
" ", line);
}
}
}
}
/****************************************************/
main (argc,argv)
int argc;
char *argv[];
{
FILE *f1;
int ii,jj;
jj=1;
for (ii=1 ; ii < argc ; ii++) {
if (!strcmp(argv[ii],"-n")) ifn_flag=1;
else if (!strcmp(argv[ii],"-z")) ifz_flag=1;
else argv[jj++] = argv[ii];
}
argc = jj;
if (argc < 2) {
printf ("Usage: hpasm options filename...\n");
return (-1);
}
start_output (argv[1]);
start_listing (argv[1]);
printf ("<< PASS 1 >>\n");
nbsyms=0;
err_count=0;
pass=1;
for (ii=1 ; ii < argc; ii++) {
f1 = fopen (argv[ii], "r");
if (!f1) {
printf ("File '%s' not found!\n\n", argv[ii]);
} else {
line_count=0;
printf ("%s ", argv[ii]);
fflush (stdout);
asm_pass (f1);
fclose (f1);
printf ("%d lines\n", line_count);
}
}
show_labels();
printf ("<< PASS 2 >>\n");
pass=2;
for (ii=1 ; ii < argc; ii++) {
f1 = fopen (argv[ii], "r");
if (!f1) {
printf ("File '%s' not found!\n\n", argv[ii]);
} else {
line_count=0;
printf ("%s ", argv[ii]);
fflush (stdout);
asm_pass (f1);
printf ("%d lines\n", line_count);
fclose (f1);
}
}
fprintf (listfile, "%ld ERRORS\n", err_count);
printf ("%ld ERRORS\n", err_count);
finish_output();
finish_listing();
return (0);
}
/****************************************************/

View File

@@ -1,6 +1,6 @@
/* This program dumps the format of a simulated magtape
Copyright (c) 1993-2003, Robert M. Supnik
Copyright (c) 1993-2007, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -22,6 +22,9 @@
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
07-Mar-07 JDB Fixed precedence error in gap marker test
30-Aug-06 JDB Added erase gap support
*/
#include <stddef.h>
@@ -41,7 +44,7 @@ int main (int argc, char *argv[])
int obj, i, k, fc, rc, tpos;
unsigned int bc, fmt, rlntsiz;
unsigned char *s, bca[4];
int preveof;
int preveof, gapcount, gpos, gincr;
FILE *ifile;
#define MAXRLNT 65536
@@ -75,7 +78,7 @@ for (i = 1; i < argc; i++) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
printf ("Processing input file %s\n", argv[i]);
tpos = 0; rc = 1; fc = 1; preveof = 0;
tpos = 0; rc = 1; fc = 1; preveof = 0; gapcount = 0;
printf ("Processing tape file %d\n", fc);
for (obj = 1;;) {
fseek (ifile, tpos, SEEK_SET);
@@ -89,6 +92,20 @@ for (i = 1; i < argc; i++) {
bc = (((unsigned int) bca[1]) << 8) | ((unsigned int) bca[0]);
break;
}
if (k && ((bc == 0xFFFFFFFE) | (bc == 0xFFFEFFFF))) {
if (gapcount == 0)
gpos = tpos;
gincr = (bc == 0xFFFFFFFE ? 4 : 2);
gapcount = gapcount + gincr;
tpos = tpos + gincr;
continue; }
else if (gapcount) {
printf ("Obj %d, position %d, erase gap, length = %d (0x%X)\n",
obj, gpos, gapcount, gapcount);
obj++;
gapcount = 0; }
if ((k == 0) || (bc == 0xFFFFFFFF)) {
printf ("End of physical tape\n");
break; }

View File

@@ -1,10 +1,10 @@
mtdump dumps the record structure of a tape image file in SIMH, E11, or
TPC format. mtdump is invoked by
mtdump dumps the record structure of a tape image file in SIMH, E11, TPC, or
P7B format. mtdump is invoked by
mtdump {-sec} file1 file2 file3...
mtdump {-secp} file1 file2 file3...
where -s specifies SIMH format, -e E11 format, and -c TPC format. The
default is SIMH format. Output is to stdout, unless redirected.
where -s specifies SIMH format, -e E11 format, -c TPC format, and -p P7B
format. The default is SIMH format. Output is to stdout, unless redirected.
SIMH format is as follows:
@@ -33,6 +33,18 @@ TPC format is as follows:
and so on. Records are padded to even byte length.
P7B format is confined to 7 track tapes, as follows:
start of record + first 6b character and parity
:
last character
start of record + first 6b character and parity
and so on. A P7B tape must have a dummy "last record" with a start of
record indicator. A tape mark is indicated by a character of 317 (start
of record, character 17, wrong parity for odd parity, reserved character
for even parity).
mmdir is a variant of mtdump that dumps the directory structure of an
Interdata MMD (multimedia diagnostic) tape. The tape must be in SMIH
format.

862
extracters/ods2/access.c Normal file
View File

@@ -0,0 +1,862 @@
/* Access.c v1.2 */
/*
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.
*/
/* This module implements 'accessing' files on an ODS2
disk volume. It uses its own low level interface to support
'higher level' APIs. For example it is called by the
'RMS' routines. I also had a module to implement
SYS$ASSIGN, SYS$QIOW, etc which called these routines,
the directory routines, physical I/O etc.... */
/*
Oh to have time to make mount do a bit more checking... :-(
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include "ssdef.h"
#include "access.h"
#include "phyio.h"
#define DEBUGx on
/* checksum: to produce block checksum values... */
unsigned short checksum(unsigned short *block)
{
register int count = 255;
register unsigned result = 0;
register unsigned short *ptr = block;
do {
result += *ptr++;
} while (--count > 0);
return result;
}
/* deaccesshead: release header from INDEXF... */
unsigned deaccesshead(struct VIOC *vioc,struct HEAD *head,unsigned modmask)
{
#ifdef DEBUG
printf("Deaccessing header %x\n",vioc->cache.keyval);
#endif
if (modmask) head->fh2$w_checksum = checksum((u_word *) head);
return deaccesschunk(vioc,modmask,1);
}
/* accesshead: find file or extension header from INDEXF... */
unsigned accesshead(struct VCB *vcb,struct fiddef *fid,
struct VIOC **vioc,struct HEAD **headbuff,
unsigned *modmask,unsigned wrtflg)
{
register unsigned sts;
register struct VCBDEV *vcbdev;
register unsigned idxblk = fid->fid$w_num + (fid->fid$b_nmx << 16) - 1;
if (fid->fid$b_rvn > vcb->devices) return SS$_NOSUCHFILE;
if (fid->fid$b_rvn < 2) {
vcbdev = vcb->vcbdev;
} else {
vcbdev = &vcb->vcbdev[fid->fid$b_rvn - 1];
}
if (vcbdev->dev == NULL) return SS$_NOSUCHFILE;
if (wrtflg && ((vcb->status & VCB_WRITE) == 0)) return SS$_WRITLCK;
#ifdef DEBUG
printf("Accessing header (%d,%d,%d)\n",(fid->fid$b_nmx << 16) +
fid->fid$w_num,fid->fid$w_seq,fid->fid$b_rvn);
#endif
idxblk += vcbdev->home.hm2$w_ibmapvbn + vcbdev->home.hm2$w_ibmapsize;
if (idxblk >= swapw(vcbdev->idxfcb->head->fh2$w_recattr.fat$l_efblk)) return SS$_NOSUCHFILE;
sts = accesschunk(vcbdev->idxfcb,idxblk,vioc,(char **) headbuff,
NULL,wrtflg ? 1 : 0,modmask);
if (sts & 1) {
register struct HEAD *head = *headbuff;
if (checksum((u_word *) head) != head->fh2$w_checksum) {
#ifdef DEBUG
printf("Accesshead checksum %d != %d\n",checksum((u_word *) head),head->fh2$w_checksum);
#endif
sts = SS$_NOSUCHFILE;
} else {
if (head->fh2$w_fid.fid$w_num != fid->fid$w_num ||
head->fh2$w_fid.fid$b_nmx != fid->fid$b_nmx ||
head->fh2$w_fid.fid$w_seq != fid->fid$w_seq ||
(head->fh2$w_fid.fid$b_rvn != fid->fid$b_rvn &&
head->fh2$w_fid.fid$b_rvn != 0)) {
#ifdef DEBUG
printf("Accesshead fileid doesn't match %d %d %d\n",
fid->fid$w_num,fid->fid$w_seq,fid->fid$b_rvn);
#endif
sts = SS$_NOSUCHFILE;
} else {
if (head->fh2$b_idoffset < 38 ||
head->fh2$b_idoffset > head->fh2$b_mpoffset ||
head->fh2$b_mpoffset > head->fh2$b_acoffset ||
head->fh2$b_acoffset > head->fh2$b_rsoffset ||
head->fh2$b_map_inuse > (head->fh2$b_acoffset - head->fh2$b_mpoffset)) {
#ifdef DEBUG
printf("Accesshead areas incorrect\n");
#endif
sts = SS$_NOSUCHFILE;
}
}
}
if ((sts & 1) == 0) deaccesschunk(*vioc,0,0);
}
return sts;
}
unsigned getwindow(struct FCB *fcb,unsigned vbn,unsigned *phyrvn,unsigned *phyblk,unsigned *phylen);
/* This routine has bugs and does NOT work properly yet!!!!
It may be something simple but I haven't had time to look...
So DON'T use mount/write!!! */
unsigned deallocfile(struct FCB *fcb)
{
register unsigned sts = 1;
/*
First mark all file clusters as free in BITMAP.SYS
*/
register unsigned vbn = 1;
while (vbn <= fcb->hiblock) {
register unsigned sts;
unsigned rvn,mapblk,maplen;
register struct VCBDEV *vcbdev;
sts = getwindow(fcb,vbn,&rvn,&mapblk,&maplen);
if ((sts & 1) == 0) break;
if (rvn > fcb->vcb->devices) break;
if (rvn < 2) {
vcbdev = fcb->vcb->vcbdev;
} else {
vcbdev = &fcb->vcb->vcbdev[rvn - 1];
}
if (vcbdev->dev == NULL) {
break;
} else {
unsigned *bitmap,blkcount,modmask;
struct VIOC *vioc;
register unsigned clustersz = vcbdev->home.hm2$w_cluster;
register unsigned clusterno = mapblk / clustersz;
sts = accesschunk(vcbdev->mapfcb,clusterno / 4096 + 2,
&vioc,(char **) &bitmap,&blkcount,1,&modmask);
if (sts & 1) {
register unsigned wordno = (clusterno % 4096) / (sizeof(unsigned) * 8);
register unsigned bitno = clusterno % (sizeof(unsigned) * 8);
do {
register unsigned mask = 1 << bitno;
vbn += clustersz;
maplen -= clustersz;
while (maplen > 0 && ++bitno < (sizeof(unsigned) * 8)) {
mask |= (mask << 1);
vbn += clustersz;
maplen -= clustersz;
}
bitmap[wordno++] |= mask;
bitno = 0;
} while (maplen > 0 && wordno < blkcount / (sizeof(unsigned) * 8));
sts = deaccesschunk(vioc,modmask,1);
}
}
}
/*
Now reset file header bit map in INDEXF.SYS and
update each of the file headers...
*/
{
unsigned rvn = fcb->rvn;
unsigned modmask = fcb->modmask;
struct HEAD *head = fcb->head;
struct VIOC *headvioc = fcb->headvioc;
do {
struct fiddef extfid;
register struct VCBDEV *vcbdev;
if (rvn > fcb->vcb->devices) break;
if (rvn < 2) {
vcbdev = fcb->vcb->vcbdev;
} else {
vcbdev = &fcb->vcb->vcbdev[rvn - 1];
}
if (vcbdev->dev == NULL) {
break;
} else {
unsigned *bitmap,viocmask;
struct VIOC *vioc;
register unsigned fileno = (head->fh2$w_fid.fid$b_nmx << 16) +
head->fh2$w_fid.fid$w_num - 1;
register unsigned idxblk = fileno / 4096 +
vcbdev->home.hm2$w_cluster * 4 + 1;
sts = accesschunk(vcbdev->idxfcb,idxblk,&vioc,
(char **) &bitmap,NULL,1,&viocmask);
if (sts & 1) {
bitmap[(fileno % 4096) / (sizeof(unsigned) * 8)] &=
~(1 << (fileno % (sizeof(unsigned) * 8)));
sts = deaccesschunk(vioc,viocmask,1);
} else {
break;
}
}
head->fh2$w_fid.fid$w_num = 0;
head->fh2$w_fid.fid$b_rvn = 0;
head->fh2$w_fid.fid$b_nmx = 0;
head->fh2$w_checksum = 0;
memcpy(&extfid,&fcb->head->fh2$w_ext_fid,sizeof(struct fiddef));
sts = deaccesshead(headvioc,head,modmask);
if ((sts & 1) == 0) break;
if (extfid.fid$b_rvn == 0) {
extfid.fid$b_rvn = rvn;
} else {
rvn = extfid.fid$b_rvn;
}
if (extfid.fid$w_num != 0 || extfid.fid$b_nmx != 0) {
sts = accesshead(fcb->vcb,&extfid,&headvioc,&head,&modmask,1);
if ((sts & 1) == 0) break;
} else {
break;
}
} while (1);
if (sts & 1) {
fcb->headvioc = NULL;
cacheuntouch(&fcb->cache,0,1);
cachedelete(&fcb->cache);
}
}
return sts;
}
/* deaccessfile: finish accessing a file.... */
unsigned deaccessfile(struct FCB *fcb)
{
#ifdef DEBUG
printf("Deaccessing file (%x) reference %d\n",fcb->cache.keyval,fcb->cache.refcount);
#endif
if (fcb->cache.refcount == 1) {
register unsigned refcount;
refcount = cacherefcount((struct CACHE *) fcb->wcb) +
cacherefcount((struct CACHE *) fcb->vioc);
if (refcount != 0) {
printf("File reference counts non-zero %d\n",refcount);
#ifdef DEBUG
printf("File reference counts non-zero %d %d\n",
cacherefcount((struct CACHE *) fcb->wcb),cacherefcount((struct CACHE *) fcb->vioc));
#endif
return SS$_BUGCHECK;
}
if (fcb->cache.status & CACHE_WRITE) {
if (fcb->head->fh2$l_filechar & FH2$M_MARKDEL) {
return deallocfile(fcb);
}
}
}
cacheuntouch(&fcb->cache,1,fcb->cache.status & CACHE_WRITE);
return SS$_NORMAL;
}
/* Object manager for FCB objects:- we point to one of our
sub-objects (vioc or wcb) in preference to letting the
cache routines get us! But we when run out of excuses
it is time to clean up the file header... :-( */
struct CACHE *fcbmanager(struct CACHE *cacheobj)
{
register struct FCB *fcb = (struct FCB *) cacheobj;
if (fcb->cache.refcount == 0) {
if (fcb->vioc != NULL) {
if (fcb->vioc->cache.refcount == 0) {
cacheobj = &fcb->vioc->cache;
} else {
cacheobj = NULL;
}
} else {
if (fcb->wcb != NULL) {
if (fcb->wcb->cache.refcount == 0) {
cacheobj = &fcb->wcb->cache;
} else {
cacheobj = NULL;
}
} else {
#ifdef DEBUG
printf("Cleaning up file (%x)\n",fcb->cache.keyval);
#endif
if (fcb->headvioc != NULL) {
#ifdef DEBUG
printf("File header deaccess (%x) %x\n",fcb->cache.keyval,fcb->cache.status);
#endif
deaccesshead(fcb->headvioc,fcb->head,fcb->modmask);
fcb->headvioc = NULL;
}
}
}
} else {
cacheobj = NULL;
}
return cacheobj;
}
/* accessfile: open up file for access... */
unsigned accessfile(struct VCB * vcb,struct fiddef * fid,struct FCB **fcbadd,
unsigned wrtflg)
{
register struct FCB *fcb;
unsigned create = sizeof(struct FCB);
register unsigned fileno = (fid->fid$b_nmx << 16) + fid->fid$w_num;
#ifdef DEBUG
printf("Accessing file (%d,%d,%d)\n",(fid->fid$b_nmx << 16) +
fid->fid$w_num,fid->fid$w_seq,fid->fid$b_rvn);
#endif
if (fileno < 1) return SS$_BADPARAM;
if (wrtflg && ((vcb->status & VCB_WRITE) == 0)) return SS$_WRITLCK;
if (fid->fid$b_rvn > 1) fileno |= ((fid->fid$b_rvn - 1) << 24);
fcb = cachesearch((void *) &vcb->fcb,fileno,0,NULL,NULL,&create);
if (fcb == NULL) return SS$_INSFMEM;
/* If not found make one... */
if (create == 0) {
fcb->cache.status |= 0x100; /* For debugging! */
fcb->rvn = fid->fid$b_rvn;
if (fcb->rvn == 0 && vcb->devices > 1) fcb->rvn = 1;
fcb->vcb = vcb;
fcb->wcb = NULL;
fcb->headvioc = NULL;
fcb->vioc = NULL;
fcb->cache.objmanager = fcbmanager;
}
if (wrtflg) {
if (fcb->headvioc != NULL && (fcb->cache.status & CACHE_WRITE) == 0) {
deaccesshead(fcb->headvioc,NULL,0);
fcb->headvioc = NULL;
}
fcb->cache.status |= CACHE_WRITE;
}
if (fcb->headvioc == NULL) {
register unsigned sts;
if (vcb->idxboot != NULL) {
*fcbadd = fcb;
fcb->hiblock = 32767; /* guess at indexf.sys file size */
fcb->highwater = 0;
fcb->head = vcb->idxboot; /* Load bootup header */
}
sts = accesshead(vcb,fid,&fcb->headvioc,&fcb->head,&fcb->modmask,wrtflg);
if (sts & 1) {
fcb->hiblock = swapw(fcb->head->fh2$w_recattr.fat$l_hiblk);
if (fcb->head->fh2$b_idoffset > 39) {
fcb->highwater = fcb->head->fh2$l_highwater;
} else {
fcb->highwater = 0;
}
} else {
fcb->cache.objmanager = NULL;
cacheuntouch(&fcb->cache,0,0);
cachefree(&fcb->cache);
return sts;
}
}
*fcbadd = fcb;
return SS$_NORMAL;
}
/* accesserase: delete a file... */
unsigned accesserase(struct VCB * vcb,struct fiddef * fid)
{
struct FCB *fcb;
register int sts;
sts = accessfile(vcb,fid,&fcb,1);
if (sts & 1) {
if (fcb->cache.refcount == 1) {
fcb->head->fh2$l_filechar |= FH2$M_MARKDEL;
sts = deaccessfile(fcb);
} else {
sts = deaccessfile(fcb);
sts = SS$_FILELOCKED;
}
}
return sts;
}
/* dismount: finish processing on a volume */
unsigned dismount(struct VCB * vcb)
{
register unsigned sts,device;
struct VCBDEV *vcbdev;
int expectfiles = vcb->devices;
int openfiles = cacherefcount(&vcb->fcb->cache);
if (vcb->status & VCB_WRITE) expectfiles *= 2;
#ifdef DEBUG
printf("Dismounting disk %d\n",openfiles);
#endif
sts = SS$_NORMAL;
if (openfiles != expectfiles) {
sts = SS$_DEVNOTDISM;
} else {
vcbdev = vcb->vcbdev;
for (device = 0; device < vcb->devices; device++) {
if (vcbdev->dev != NULL) {
if (vcb->status & VCB_WRITE) {
sts = deaccessfile(vcbdev->mapfcb);
vcbdev->idxfcb->headvioc->cache.status |= CACHE_MODIFIED;
vcbdev->idxfcb->cache.status &= ~CACHE_WRITE;
cacheflush();
}
cachedeltree(&vcb->fcb->cache);
sts = deaccesshead(vcbdev->idxfcb->headvioc,NULL,0);
vcbdev->idxfcb->headvioc = NULL;
sts = cacheuntouch(&vcbdev->idxfcb->cache,0,0);
cachedeltree(&vcb->fcb->cache);
}
vcbdev++;
}
while (vcb->dircache) cachedelete((struct CACHE *) vcb->dircache);
#ifdef DEBUG
printf("Post close\n");
cachedump();
#endif
free(vcb);
}
return sts;
}
/* mount: make disk volume available for processing... */
unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],struct VCB **retvcb)
{
register unsigned device,sts;
struct VCB *vcb;
struct VCBDEV *vcbdev;
if (sizeof(struct HOME) != 512 || sizeof(struct HEAD) != 512) return SS$_NOTINSTALL;
vcb = (struct VCB *) malloc(sizeof(struct VCB) + (devices - 1) * sizeof(struct VCBDEV));
if (vcb == NULL) return SS$_INSFMEM;
vcb->status = 0;
if (flags & 1) vcb->status |= VCB_WRITE;
vcb->fcb = NULL;
vcb->dircache = NULL;
vcbdev = vcb->vcbdev;
for (device = 0; device < devices; device++) {
sts = SS$_NOSUCHVOL;
vcbdev->dev = NULL;
if (strlen(devnam[device])) {
sts = device_lookup(strlen(devnam[device]),devnam[device],1,&vcbdev->dev);
if (sts & 1) {
int hba = 1; /* Header block address... */
do {
if ((sts = phyio_read(vcbdev->dev->handle,hba,sizeof(struct HOME),(char *) &vcbdev->home)) & 1) {
if (memcmp(vcbdev->home.hm2$t_format,"DECFILE11B ",12) != 0) sts = SS$_BADPARAM;
}
} while ((sts & 1) == 0 && (hba += 1) < 100);
if (sts & 1) {
if (vcbdev->home.hm2$w_checksum2 != checksum((unsigned short *) &vcbdev->home)) {
sts = SS$_DATACHECK;
} else {
struct HEAD idxboot; /* Local for bootstrapping volume */
struct fiddef idxfid = {1,1,0,0};
idxfid.fid$b_rvn = device + 1;
if ((sts = phyio_read(vcbdev->dev->handle,vcbdev->home.hm2$l_ibmaplbn +
vcbdev->home.hm2$w_ibmapsize,sizeof(struct HEAD),(char *) &idxboot)) & 1) {
if (idxboot.fh2$w_fid.fid$w_num != idxfid.fid$w_num ||
idxboot.fh2$w_fid.fid$b_nmx != idxfid.fid$b_nmx ||
idxboot.fh2$w_fid.fid$w_seq != idxfid.fid$w_seq ||
(idxboot.fh2$w_fid.fid$b_rvn != 0 &&
idxboot.fh2$w_fid.fid$b_rvn != idxfid.fid$b_rvn))
sts = SS$_DATACHECK;
if (idxboot.fh2$w_checksum != checksum((unsigned short *) &idxboot)) sts = SS$_DATACHECK;
}
vcbdev->idxfcb = NULL;
if (sts & 1) {
vcb->devices = device + 1;
vcb->idxboot = &idxboot; /* For getwindow to find index file*/
sts = accessfile(vcb,&idxfid,&vcbdev->idxfcb,flags & 1);
vcbdev->mapfcb = NULL;
if (sts & 1) {
vcbdev->dev->vcb = vcb;
if (flags & 1) {
struct fiddef mapfid = {2,2,0,0};
mapfid.fid$b_rvn = device + 1;
sts = accessfile(vcb,&mapfid,&vcbdev->mapfcb,1);
}
}
}
}
}
}
if ((sts & 1) == 0) vcbdev->dev = NULL;
}
if (device == 0 && vcbdev->dev == NULL) {
free(vcb);
return sts;
}
vcbdev++;
}
vcb->idxboot = NULL;
if (retvcb != NULL) *retvcb = vcb;
return sts;
}
/* wincmp: compare two windows routine - return -1 for less, 0 for match... */
/* as a by product keep highest previous entry so that if a new window
is required we don't have to go right back to the initial file header */
int wincmp(unsigned keylen,void *key,void *node)
{
register struct WCB *wcb = (struct WCB *) node;
if (keylen < wcb->loblk) {
return -1;
} else {
if (keylen <= wcb->hiblk) {
return 0;
} else {
register struct WCB **prev_wcb = (struct WCB **) key;
if (*prev_wcb == NULL) {
*prev_wcb = wcb;
} else {
if ((*prev_wcb)->hiblk < wcb->hiblk) *prev_wcb = wcb;
}
return 1;
}
}
}
/* getwindow: find a window to map VBN to LBN ... */
unsigned getwindow(struct FCB * fcb,unsigned vbn,unsigned *phyrvn,unsigned *phyblk,unsigned *phylen)
{
register struct WCB *wcb;
struct WCB *prev_wcb = NULL;
unsigned create = sizeof(struct WCB);
#ifdef DEBUG
printf("Accessing window for vbn %d, file (%x)\n",vbn,fcb->cache.keyval);
#endif
wcb = cachesearch((void *) &fcb->wcb,0,vbn,&prev_wcb,wincmp,&create);
if (wcb == NULL) return SS$_INSFMEM;
/* If not found make one... */
if (create == 0) {
register unsigned wd_base,wd_exts;
unsigned prev_hiblk,rvn;
struct VIOC *vioc;
struct HEAD *head;
wcb->cache.status |= 0x200; /* For debugging! */
vioc = NULL;
wd_base = 1;
rvn = fcb->rvn;
head = fcb->head;
prev_hiblk = 0;
if (prev_wcb != NULL) {
register unsigned sts;
register struct fiddef *fid = &prev_wcb->hd_fid;
register struct fiddef *filefid = &fcb->head->fh2$w_fid;
if (fid->fid$w_num != filefid->fid$w_num ||
fid->fid$b_nmx != filefid->fid$b_nmx ||
((fid->fid$b_rvn > 1 || fcb->rvn > 1) && fid->fid$b_rvn != fcb->rvn)) {
wd_base = prev_wcb->hd_base;
rvn = prev_wcb->hd_fid.fid$b_rvn;
sts = accesshead(fcb->vcb,fid,&vioc,&head,NULL,0);
if ((sts & 1) == 0) {
cacheuntouch(&wcb->cache,0,0);
cachefree(&wcb->cache);
return sts;
}
}
prev_hiblk = prev_wcb->hiblk;
}
wcb->hd_base = wd_base;
wd_exts = 0;
#ifdef DEBUG
printf("Making window %d %d\n",wd_base,prev_hiblk);
#endif
do {
register unsigned short *mp = (unsigned short *) head + head->fh2$b_mpoffset;
register unsigned short *me = mp + head->fh2$b_map_inuse;
while (mp < me) {
register unsigned phylen,phyblk;
switch ((*mp) >> 14) {
case 0:
phylen = 0;
mp++;
break;
case 1:
phylen = ((*mp) & 0377) + 1;
phyblk = (((*mp) & 037400) << 8) + mp[1];
mp += 2;
break;
case 2:
phylen = ((*mp) & 037777) + 1;
phyblk = (mp[2] << 16) + mp[1];
mp += 3;
break;
case 3:
phylen = (((*mp) & 037777) << 16) + mp[1] + 1;
phyblk = (mp[3] << 16) + mp[2];
mp += 4;
}
if (phylen > 0 && wd_base > prev_hiblk) {
register struct EXT *ext;
if (wd_exts == 0) wcb->loblk = wd_base;
ext = &wcb->ext[wd_exts++];
ext->phylen = phylen;
ext->phyblk = phyblk;
wd_base += phylen;
if (wd_exts >= EXTMAX) {
if (wd_base > vbn) {
break;
} else {
wd_exts = 0;
}
}
} else {
wd_base += phylen;
}
}
if (wd_base > vbn) {
break;
} else {
register unsigned sts;
struct fiddef extfid;
memcpy(&extfid,&head->fh2$w_ext_fid,sizeof(struct fiddef));
if (extfid.fid$b_rvn != 0 && extfid.fid$b_rvn != rvn) {
wd_exts = 0;/* Can't let window extend across devices */
rvn = extfid.fid$b_rvn;
} else {
extfid.fid$b_rvn = rvn;
}
if (vioc != NULL) deaccesshead(vioc,NULL,0);
sts = accesshead(fcb->vcb,&extfid,&vioc,&head,NULL,0);
if ((sts & 1) == 0) {
cacheuntouch(&wcb->cache,0,0);
cachefree(&wcb->cache);
return sts;
}
wcb->hd_base = wd_base;
}
} while (wd_base <= vbn);
memcpy(&wcb->hd_fid,&head->fh2$w_fid,sizeof(struct fiddef));
wcb->hd_fid.fid$b_rvn = rvn;
wcb->hiblk = wd_base - 1;
wcb->extcount = wd_exts;
if (vioc != NULL) deaccesshead(vioc,NULL,0);
} {
register struct EXT *ext = wcb->ext;
register unsigned extcnt = wcb->extcount;
register unsigned togo = vbn - wcb->loblk;
while (togo >= ext->phylen) {
togo -= (ext++)->phylen;
if (extcnt-- < 1) return SS$_BUGCHECK;
}
*phyrvn = wcb->hd_fid.fid$b_rvn;
*phyblk = ext->phyblk + togo;
*phylen = ext->phylen - togo;
#ifdef DEBUG
printf("Mapping vbn %d to %d (%d -> %d)[%d] file (%x)\n",
vbn,*phyblk,wcb->loblk,wcb->hiblk,wcb->hd_base,fcb->cache.keyval);
#endif
cacheuntouch(&wcb->cache,1,0);
}
return SS$_NORMAL;
}
/* Object manager for VIOC objects:- if the object has been
modified then we need to flush it to disk before we let
the cache routines do anything to it...
This version rewrites the whole chunk - but we really should
just rewrite the blocks modified as indicated by modmask! */
struct CACHE *viocmanager(struct CACHE * cacheobj)
{
register struct VIOC *vioc = (struct VIOC *) cacheobj;
if (vioc->cache.status & CACHE_MODIFIED) {
register int length = VIOC_CHUNKSIZE;
register struct FCB *fcb = vioc->fcb;
register unsigned base = vioc->cache.keyval;
register char *address = (char *) vioc->data;
printf("\nviocmanager writing vbn %d\n",base);
cachetouch(&fcb->cache);
do {
register unsigned sts;
unsigned rvn,mapblk,maplen;
register struct VCBDEV *vcbdev;
if (fcb->highwater > 0 && base >= fcb->highwater) break;
sts = getwindow(fcb,base,&rvn,&mapblk,&maplen);
if (sts & 1) {
if (maplen > (unsigned)length) maplen = length;
if (fcb->highwater > 0 && base + maplen > fcb->highwater) {
maplen = fcb->head->fh2$l_highwater - base;
}
if (rvn > fcb->vcb->devices) {
sts = SS$_NOSUCHFILE;
} else {
if (rvn < 2) {
vcbdev = fcb->vcb->vcbdev;
} else {
vcbdev = &fcb->vcb->vcbdev[rvn - 1];
}
if (vcbdev->dev == NULL) return NULL;
sts = phyio_write(vcbdev->dev->handle,mapblk,maplen * 512,address);
}
}
if ((sts & 1) == 0) {
return NULL;
}
length -= maplen;
base += maplen;
address += maplen * 512;
} while (length > 0);
cacheuntouch(&fcb->cache,1,0);
cacheobj->status &= ~CACHE_MODIFIED;
}
return cacheobj;
}
/* deaccess a VIOC (chunk of a file) */
unsigned deaccesschunk(struct VIOC *vioc,unsigned modmask,int reuse)
{
#ifdef DEBUG
printf("Deaccess chunk %8x\n",vioc->cache.keyval);
#endif
if ((vioc->wrtmask | modmask) == vioc->wrtmask) {
vioc->modmask |= modmask;
if (vioc->cache.refcount == 1) vioc->wrtmask = 0;
return cacheuntouch(&vioc->cache,reuse,modmask);
} else {
return SS$_WRITLCK;
}
}
/* accesschunk: return pointer to a 'chunk' of a file ... */
unsigned accesschunk(struct FCB *fcb,unsigned vbn,struct VIOC **retvioc,
char **retbuff,unsigned *retblocks,unsigned wrtblks,
unsigned *retmodmask)
{
/*
First find cache entry...
*/
register struct VIOC *vioc;
unsigned create = sizeof(struct VIOC);
register unsigned base = (vbn - 1) / VIOC_CHUNKSIZE * VIOC_CHUNKSIZE + 1;
#ifdef DEBUG
printf("Access chunk %8x %d (%x)\n",base,vbn,fcb->cache.keyval);
#endif
if (wrtblks && ((fcb->cache.status & CACHE_WRITE) == 0)) return SS$_WRITLCK;
if (vbn < 1 || vbn > fcb->hiblock) return SS$_ENDOFFILE;
vioc = cachesearch((void *) &fcb->vioc,base,0,NULL,NULL,&create);
if (vioc == NULL) return SS$_INSFMEM;
/*
If not found make one...
*/
if (create == 0) {
register unsigned length;
register char *address;
register unsigned mapbase = base;
vioc->cache.status |= 0x400; /* For debugging! */
vioc->fcb = fcb;
vioc->wrtmask = 0;
vioc->modmask = 0;
length = fcb->hiblock - mapbase + 1;
if (length > VIOC_CHUNKSIZE) length = VIOC_CHUNKSIZE;
address = (char *) vioc->data;
do {
if (fcb->highwater > 0 && mapbase >= fcb->highwater) {
memset(address,0,length * 512);
length = 0;
} else {
register unsigned sts;
unsigned rvn,mapblk,maplen;
register struct VCBDEV *vcbdev;
sts = getwindow(fcb,mapbase,&rvn,&mapblk,&maplen);
if (sts & 1) {
if (maplen > length) maplen = length;
if (fcb->highwater > 0 && mapbase + maplen > fcb->highwater) {
maplen = fcb->head->fh2$l_highwater - mapbase;
}
if (rvn > fcb->vcb->devices) {
sts = SS$_NOSUCHFILE;
} else {
if (rvn < 2) {
vcbdev = fcb->vcb->vcbdev;
} else {
vcbdev = &fcb->vcb->vcbdev[rvn - 1];
}
if (vcbdev->dev == NULL) return SS$_NOSUCHFILE;
sts = phyio_read(vcbdev->dev->handle,mapblk,maplen * 512,address);
}
}
if ((sts & 1) == 0) {
cacheuntouch(&vioc->cache,0,0);
cachefree(&vioc->cache);
return sts;
}
length -= maplen;
mapbase += maplen;
address += maplen * 512;
}
} while (length > 0);
}
if (wrtblks) {
vioc->cache.status |= CACHE_WRITE;
vioc->cache.objmanager = viocmanager;
}
/*
Return result to caller...
*/
*retvioc = vioc;
*retbuff = vioc->data[vbn - base];
if (wrtblks || retblocks != NULL || retmodmask != NULL) {
register unsigned modmask = 0;
register unsigned blocks = base + VIOC_CHUNKSIZE - vbn;
if (blocks > fcb->hiblock - vbn) blocks = fcb->hiblock - vbn + 1;
if (wrtblks) if (blocks > wrtblks) blocks = wrtblks;
if (retblocks != NULL) *retblocks = blocks;
if (wrtblks) {
modmask = 1 << (vbn - base);
if (blocks > 1) {
while (--blocks > 0) modmask |= modmask << 1;
}
vioc->wrtmask |= modmask;
}
if (retmodmask != NULL) *retmodmask = modmask;
}
return SS$_NORMAL;
}

237
extracters/ods2/access.h Normal file
View File

@@ -0,0 +1,237 @@
/* Access.h v1.2 Definitions for file access routines */
/*
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.
*/
#include "cache.h"
#include "vmstime.h"
#define swapw(w) ((((unsigned int)(w[0]))<<16) | (unsigned int)(w[1]))
#define FH2$M_NOBACKUP 0x2
#define FH2$M_CONTIG 0x80
#define FH2$M_DIRECTORY 0x2000
#define FH2$M_MARKDEL 0x8000
#define FH2$M_ERASE 0x20000
typedef unsigned char u_byte;
typedef unsigned short u_word;
typedef unsigned int u_long;
struct UIC {
u_word u_grp;
u_word u_mem;
};
struct fiddef {
u_word fid$w_num;
u_word fid$w_seq;
u_byte fid$b_rvn;
u_byte fid$b_nmx;
};
struct RECATTR {
u_byte fat$b_rtype;
u_byte fat$b_rattrib;
u_word fat$w_rsize;
u_word fat$l_hiblk[2];
u_word fat$l_efblk[2];
u_word fat$w_ffbyte;
u_byte fat$b_bktsize;
u_byte fat$b_vfcsize;
u_word fat$w_maxrec;
u_word fat$w_defext;
u_word fat$w_gbc;
u_byte fat$_UU0[8];
u_word fat$w_versions;
};
struct HOME {
u_long hm2$l_homelbn;
u_long hm2$l_alhomelbn;
u_long hm2$l_altidxlbn;
u_word hm2$w_struclev;
u_word hm2$w_cluster;
u_word hm2$w_homevbn;
u_word hm2$w_alhomevbn;
u_word hm2$w_altidxvbn;
u_word hm2$w_ibmapvbn;
u_long hm2$l_ibmaplbn;
u_long hm2$l_maxfiles;
u_word hm2$w_ibmapsize;
u_word hm2$w_resfiles;
u_word hm2$w_devtype;
u_word hm2$w_rvn;
u_word hm2$w_setcount;
u_word hm2$w_volchar;
struct UIC hm2$w_volowner;
u_long hm2$l_reserved1;
u_word hm2$w_protect;
u_word hm2$w_fileprot;
u_word hm2$w_reserved2;
u_word hm2$w_checksum1;
struct TIME hm2$q_credate;
u_byte hm2$b_window;
u_byte hm2$b_lru_lim;
u_word hm2$w_extend;
struct TIME hm2$q_retainmin;
struct TIME hm2$q_retainmax;
struct TIME hm2$q_revdate;
u_byte hm2$r_min_class[20];
u_byte hm2$r_max_class[20];
u_byte hm2$t_reserved3[320];
u_long hm2$l_serialnum;
char hm2$t_strucname[12];
char hm2$t_volname[12];
char hm2$t_ownername[12];
char hm2$t_format[12];
u_word hm2$w_reserved4;
u_word hm2$w_checksum2;
};
struct IDENT {
char fi2$t_filename[20];
u_word fi2$w_revision;
struct TIME fi2$q_credate;
struct TIME fi2$q_revdate;
struct TIME fi2$q_expdate;
struct TIME fi2$q_bakdate;
char fi2$t_filenamext[66];
};
struct HEAD {
u_byte fh2$b_idoffset;
u_byte fh2$b_mpoffset;
u_byte fh2$b_acoffset;
u_byte fh2$b_rsoffset;
u_word fh2$w_seg_num;
u_word fh2$w_struclev;
struct fiddef fh2$w_fid;
struct fiddef fh2$w_ext_fid;
struct RECATTR fh2$w_recattr;
u_long fh2$l_filechar;
u_word fh2$w_reserved1;
u_byte fh2$b_map_inuse;
u_byte fh2$b_acc_mode;
struct UIC fh2$l_fileowner;
u_word fh2$w_fileprot;
struct fiddef fh2$w_backlink;
u_byte fh2$b_journal;
u_byte fh2$b_ru_active;
u_word fh2$w_reserved2;
u_long fh2$l_highwater;
u_byte fh2$b_reserved3[8];
u_byte fh2$r_class_prot[20];
u_byte fh2$r_restofit[402];
u_word fh2$w_checksum;
};
struct EXT {
unsigned phylen;
unsigned phyblk;
}; /* Physical extent entry */
#define EXTMAX 20
struct WCB {
struct CACHE cache;
unsigned loblk,hiblk; /* Range of window */
unsigned hd_base; /* File blocks prior to header */
unsigned extcount; /* Extents in use */
struct EXT ext[EXTMAX]; /* Mapping extents */
struct fiddef hd_fid; /* Header info to create other WCBs */
}; /* Window control block */
#define VIOC_CHUNKSIZE 4
struct VIOC {
struct CACHE cache;
struct FCB *fcb; /* File this chunk is for */
unsigned wrtmask; /* Bit mask for writable blocks */
unsigned modmask; /* Bit mask for modified blocks */
char data[VIOC_CHUNKSIZE][512]; /* Chunk data */
}; /* Chunk of a file */
struct FCB {
struct CACHE cache;
struct VCB *vcb; /* Volume this file is for */
struct VIOC *headvioc; /* Index file chunk for file header */
struct HEAD *head; /* Pointer to header block */
struct WCB *wcb; /* Window control block tree */
struct VIOC *vioc; /* Virtual I/O chunk tree */
unsigned modmask; /* headvioc chunk modmask */
unsigned hiblock; /* Highest block mapped */
unsigned highwater; /* First high water block */
unsigned char rvn; /* Initial file relative volume */
}; /* File control block */
struct DIRCACHE {
struct CACHE cache;
int dirlen; /* Length of directory name */
struct fiddef dirid; /* File ID of directory */
char dirnam[1]; /* Directory name */
}; /* Directory cache entry */
#define VCB_WRITE 1
struct VCB {
unsigned status; /* Volume status */
unsigned devices; /* Number of volumes in set */
struct HEAD *idxboot; /* Pointer to index file boot header */
struct FCB *fcb; /* File control block tree */
struct DIRCACHE *dircache; /* Directory cache tree */
struct VCBDEV {
struct DEV *dev; /* Pointer to device info */
struct FCB *idxfcb; /* Index file control block */
struct FCB *mapfcb; /* Bitmap file control block */
struct HOME home; /* Volume home block */
} vcbdev[1]; /* List of volumes devices */
}; /* Volume control block */
struct DEV {
struct CACHE cache;
struct VCB *vcb; /* Pointer to volume (if mounted) */
unsigned handle; /* Device physical I/O handle */
unsigned status; /* Device physical status */
unsigned sectors; /* Device physical sectors */
unsigned sectorsize; /* Device physical sectorsize */
int devlen; /* Length of device name */
char devnam[1]; /* Device name */
}; /* Device information */
unsigned device_lookup(unsigned devlen,char *devnam,int create,struct DEV **retdev);
unsigned dismount(struct VCB *vcb);
unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],struct VCB **vcb);
unsigned accesserase(struct VCB *vcb,struct fiddef *fid);
unsigned deaccessfile(struct FCB *fcb);
unsigned accessfile(struct VCB *vcb,struct fiddef *fid,
struct FCB **fcb,unsigned wrtflg);
unsigned deaccesschunk(struct VIOC *vioc,unsigned modmask,int reuse);
unsigned accesschunk(struct FCB *fcb,unsigned vbn,struct VIOC **retvioc,
char **retbuff,unsigned *retblocks,unsigned wrtblks,
unsigned *retmodmask);

View File

@@ -0,0 +1,237 @@
/* Access.h v1.2 Definitions for file access routines */
/*
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.
*/
#include "cache.h"
#include "vmstime.h"
#define swapw(w) (w[0]<<16 | w[1])
#define FH2$M_NOBACKUP 0x2
#define FH2$M_CONTIG 0x80
#define FH2$M_DIRECTORY 0x2000
#define FH2$M_MARKDEL 0x8000
#define FH2$M_ERASE 0x20000
typedef unsigned char u_byte;
typedef unsigned short u_word;
typedef unsigned int u_long;
struct UIC {
u_word u_grp;
u_word u_mem;
};
struct fiddef {
u_word fid$w_num;
u_word fid$w_seq;
u_byte fid$b_rvn;
u_byte fid$b_nmx;
};
struct RECATTR {
u_byte fat$b_rtype;
u_byte fat$b_rattrib;
u_word fat$w_rsize;
u_word fat$l_hiblk[2];
u_word fat$l_efblk[2];
u_word fat$w_ffbyte;
u_byte fat$b_bktsize;
u_byte fat$b_vfcsize;
u_word fat$w_maxrec;
u_word fat$w_defext;
u_word fat$w_gbc;
u_byte fat$_UU0[8];
u_word fat$w_versions;
};
struct HOME {
u_long hm2$l_homelbn;
u_long hm2$l_alhomelbn;
u_long hm2$l_altidxlbn;
u_word hm2$w_struclev;
u_word hm2$w_cluster;
u_word hm2$w_homevbn;
u_word hm2$w_alhomevbn;
u_word hm2$w_altidxvbn;
u_word hm2$w_ibmapvbn;
u_long hm2$l_ibmaplbn;
u_long hm2$l_maxfiles;
u_word hm2$w_ibmapsize;
u_word hm2$w_resfiles;
u_word hm2$w_devtype;
u_word hm2$w_rvn;
u_word hm2$w_setcount;
u_word hm2$w_volchar;
struct UIC hm2$w_volowner;
u_long hm2$l_reserved1;
u_word hm2$w_protect;
u_word hm2$w_fileprot;
u_word hm2$w_reserved2;
u_word hm2$w_checksum1;
struct TIME hm2$q_credate;
u_byte hm2$b_window;
u_byte hm2$b_lru_lim;
u_word hm2$w_extend;
struct TIME hm2$q_retainmin;
struct TIME hm2$q_retainmax;
struct TIME hm2$q_revdate;
u_byte hm2$r_min_class[20];
u_byte hm2$r_max_class[20];
u_byte hm2$t_reserved3[320];
u_long hm2$l_serialnum;
char hm2$t_strucname[12];
char hm2$t_volname[12];
char hm2$t_ownername[12];
char hm2$t_format[12];
u_word hm2$w_reserved4;
u_word hm2$w_checksum2;
};
struct IDENT {
char fi2$t_filename[20];
u_word fi2$w_revision;
struct TIME fi2$q_credate;
struct TIME fi2$q_revdate;
struct TIME fi2$q_expdate;
struct TIME fi2$q_bakdate;
char fi2$t_filenamext[66];
};
struct HEAD {
u_byte fh2$b_idoffset;
u_byte fh2$b_mpoffset;
u_byte fh2$b_acoffset;
u_byte fh2$b_rsoffset;
u_word fh2$w_seg_num;
u_word fh2$w_struclev;
struct fiddef fh2$w_fid;
struct fiddef fh2$w_ext_fid;
struct RECATTR fh2$w_recattr;
u_long fh2$l_filechar;
u_word fh2$w_reserved1;
u_byte fh2$b_map_inuse;
u_byte fh2$b_acc_mode;
struct UIC fh2$l_fileowner;
u_word fh2$w_fileprot;
struct fiddef fh2$w_backlink;
u_byte fh2$b_journal;
u_byte fh2$b_ru_active;
u_word fh2$w_reserved2;
u_long fh2$l_highwater;
u_byte fh2$b_reserved3[8];
u_byte fh2$r_class_prot[20];
u_byte fh2$r_restofit[402];
u_word fh2$w_checksum;
};
struct EXT {
unsigned phylen;
unsigned phyblk;
}; /* Physical extent entry */
#define EXTMAX 20
struct WCB {
struct CACHE cache;
unsigned loblk,hiblk; /* Range of window */
unsigned hd_base; /* File blocks prior to header */
unsigned extcount; /* Extents in use */
struct EXT ext[EXTMAX]; /* Mapping extents */
struct fiddef hd_fid; /* Header info to create other WCBs */
}; /* Window control block */
#define VIOC_CHUNKSIZE 4
struct VIOC {
struct CACHE cache;
struct FCB *fcb; /* File this chunk is for */
unsigned wrtmask; /* Bit mask for writable blocks */
unsigned modmask; /* Bit mask for modified blocks */
char data[VIOC_CHUNKSIZE][512]; /* Chunk data */
}; /* Chunk of a file */
struct FCB {
struct CACHE cache;
struct VCB *vcb; /* Volume this file is for */
struct VIOC *headvioc; /* Index file chunk for file header */
struct HEAD *head; /* Pointer to header block */
struct WCB *wcb; /* Window control block tree */
struct VIOC *vioc; /* Virtual I/O chunk tree */
unsigned modmask; /* headvioc chunk modmask */
unsigned hiblock; /* Highest block mapped */
unsigned highwater; /* First high water block */
unsigned char rvn; /* Initial file relative volume */
}; /* File control block */
struct DIRCACHE {
struct CACHE cache;
int dirlen; /* Length of directory name */
struct fiddef dirid; /* File ID of directory */
char dirnam[1]; /* Directory name */
}; /* Directory cache entry */
#define VCB_WRITE 1
struct VCB {
unsigned status; /* Volume status */
unsigned devices; /* Number of volumes in set */
struct HEAD *idxboot; /* Pointer to index file boot header */
struct FCB *fcb; /* File control block tree */
struct DIRCACHE *dircache; /* Directory cache tree */
struct VCBDEV {
struct DEV *dev; /* Pointer to device info */
struct FCB *idxfcb; /* Index file control block */
struct FCB *mapfcb; /* Bitmap file control block */
struct HOME home; /* Volume home block */
} vcbdev[1]; /* List of volumes devices */
}; /* Volume control block */
struct DEV {
struct CACHE cache;
struct VCB *vcb; /* Pointer to volume (if mounted) */
unsigned handle; /* Device physical I/O handle */
unsigned status; /* Device physical status */
unsigned sectors; /* Device physical sectors */
unsigned sectorsize; /* Device physical sectorsize */
int devlen; /* Length of device name */
char devnam[1]; /* Device name */
}; /* Device information */
unsigned device_lookup(unsigned devlen,char *devnam,int create,struct DEV **retdev);
unsigned dismount(struct VCB *vcb);
unsigned mount(unsigned flags,unsigned devices,char *devnam[],char *label[],struct VCB **vcb);
unsigned accesserase(struct VCB *vcb,struct fiddef *fid);
unsigned deaccessfile(struct FCB *fcb);
unsigned accessfile(struct VCB *vcb,struct fiddef *fid,
struct FCB **fcb,unsigned wrtflg);
unsigned deaccesschunk(struct VIOC *vioc,unsigned modmask,int reuse);
unsigned accesschunk(struct FCB *fcb,unsigned vbn,struct VIOC **retvioc,
char **retbuff,unsigned *retblocks,unsigned wrtblks,
unsigned *retmodmask);

37
extracters/ods2/build.com Normal file
View File

@@ -0,0 +1,37 @@
$ gccflag := 'cc'
$ if f$extract(0,3,gccflag).nes."GCC" then gccflag=""
$
$ if gccflag.nes.""
$ then p1="/optim=level=3/warn=all"+p1
$ else p1="/warn=enabl=(defunct,obsolescent,questcode,uninit,unused)"+p1
$ endif
$
$ default=f$parse(f$environment("PROCEDURE"),,,"DEVICE","SYNTAX_ONLY")+ -
f$parse(f$environment("PROCEDURE"),,,"DIRECTORY","SYNTAX_ONLY")
$ set def 'default'
$
$ call cc ods2 'p1'
$ call cc rms 'p1'
$ call cc direct 'p1'
$ call cc access 'p1'
$ call cc device 'p1'
$ call cc cache 'p1'
$ call cc phyvms 'p1'
$ call cc vmstime 'p1'
$
$ write sys$error "''f$time()' Linking..."
$ if gccflag.nes.""
$ then library = ",vaxcrtl.tmp/option"
$ create vaxcrtl.tmp
sys$share:vaxcrtl/share
$ endif
$ link 'p2' ods2,rms,direct,access,device,cache,phyvms,vmstime 'library'
$ write sys$error "''f$time()' Done"
$ exit
$
$cc: subroutine
$ if f$search(p1+".obj;").nes."" then if f$cvtime(f$file(p1+".obj;","CDT")).ges.f$cvtime(f$file(p1+".c;","CDT")) then exit
$ write sys$error "''f$time()' Compiling ''p1'..."
$ cc 'p2' 'p1'
$ exit
$ endsubroutine

411
extracters/ods2/cache.c Normal file
View File

@@ -0,0 +1,411 @@
/* Cache.c v1.2 Caching control routines */
/*
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.
*/
/* Caching seems to have a big impact on performance!!!
This version based on number of objects - probably
should change it to use space occupied by objects.
Currently use vanilla binary trees - could either
use hashing or balanced trees for better performance. */
/* The theory is that all cachable objects share a common
cache pool. Any object with a reference count of zero
is a candidate for destruction. All cacheable objects
have a 'struct CACHE' as the first item of the object
so that cache pointers and object pointers are interchangeable.
All cache objects are also part of a binary tree so that
they can be located. There are many instances of these
binary trees: for files on a volume, for chunks (segments)
of files, etc. Also each object can have an object manager:
a routine to handle special object deletion requirements
(for example to remove all file chunks before removing a
file), or to flush objects (write modified chunks to disk). */
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "ssdef.h"
#include "cache.h"
#define DEBUG on
/* Set limits for number of unaccessed cache entries... */
#define CACHELIM 64
#define CACHEGOAL 25
int cachesearches = 0;
int cachecreated = 0;
int cachedeleted = 0;
int cachepeak = 0;
int cachecount = 0;
int cachefreecount = 0;
struct CACHE cachelist = {NULL,NULL,NULL,&cachelist,&cachelist,NULL,0,0,1};
/* cacheshow - to print cache statistics */
void cacheshow(void)
{
printf("CACHESHOW Searches: %d Created: %d Peak: %d Count: %d Free: %d\n",
cachesearches,cachecreated,cachepeak,cachecount,cachefreecount);
}
void cachedump(void)
{
register struct CACHE *cacheobj = cachelist.lstcache;
printf("%8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s cachelist\n","Object",
"Parent","Left","Right","Value","Status","Count");
while (cacheobj != &cachelist) {
printf("%8p %8p %8p %8p %8x %8x %8d\n",
cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right,
cacheobj->keyval,cacheobj->status,cacheobj->refcount);
cacheobj = cacheobj->lstcache;
}
}
/* cacheprint - debugging tool to print out a cache subtree... */
void cacheprint(struct CACHE *cacheobj,int level)
{
if (cacheobj != NULL) {
int i;
cacheprint(cacheobj->left,level + 1);
for (i = 0; i < level; i++) printf(" ");
printf("%8p %8x %8x %d\n",
cacheobj,cacheobj->keyval,cacheobj->status,cacheobj->refcount);
cacheprint(cacheobj->right,level + 1);
}
}
/* cacherefcount - compute reference count for cache subtree... */
int cacherefcount(struct CACHE *cacheobj)
{
register int refcount = 0;
if (cacheobj != NULL) {
if (cacheobj->left != NULL) refcount += cacherefcount(cacheobj->left);
if (cacheobj->right != NULL) refcount += cacherefcount(cacheobj->right);
refcount += cacheobj->refcount;
}
return refcount;
}
/* cachefree - blow away item from cache - allow item to select a proxy (!)
and adjust 'the tree' containing the item. */
int freeactive = 0; /* In case object managers re-call cachefree... :-( */
struct CACHE *cachefree(struct CACHE *cacheobj)
{
if (cacheobj->refcount != 0) {
char str[100];
printf("cachelist, object to delete still inuse?\n");
printf("%8p %8p %8p %8p %8x %8x %8d\n",
cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right,
cacheobj->keyval,cacheobj->status,cacheobj->refcount);
printf("Type RETURN: ");
fgets(str, sizeof(str)-1, stdin);
return NULL;
} else {
register struct CACHE *proxyobj;
while (cacheobj->objmanager != NULL) {
freeactive = 1;
proxyobj = (*cacheobj->objmanager) (cacheobj);
freeactive = 0;
if (proxyobj == NULL) return NULL;
if (proxyobj == cacheobj) break;
cacheobj = proxyobj;
}
if ((cacheobj->status & CACHE_MODIFIED) && cacheobj->objmanager == NULL)
printf("cachelist No manager to write modified cache\n");
cacheobj->lstcache->nxtcache = cacheobj->nxtcache;
cacheobj->nxtcache->lstcache = cacheobj->lstcache;
if (cacheobj->parent != NULL) { /* Check if in tree... */
if (cacheobj->left == NULL) {
if (cacheobj->right == NULL) {
*(cacheobj->parent) = NULL;
} else {
cacheobj->right->parent = cacheobj->parent;
*(cacheobj->parent) = cacheobj->right;
}
} else {
if (cacheobj->right == NULL) {
cacheobj->left->parent = cacheobj->parent;
*(cacheobj->parent) = cacheobj->left;
} else {
register struct CACHE *leftpath = cacheobj->left;
register struct CACHE *rightpath = cacheobj->right;
while (1) {
if (leftpath->right == NULL) {
leftpath->right = cacheobj->right;
cacheobj->right->parent = &leftpath->right;
cacheobj->left->parent = cacheobj->parent;
*(cacheobj->parent) = cacheobj->left;
break;
} else {
if (rightpath->left == NULL) {
rightpath->left = cacheobj->left;
cacheobj->left->parent = &rightpath->left;
cacheobj->right->parent = cacheobj->parent;
*(cacheobj->parent) = cacheobj->right;
break;
} else {
leftpath = leftpath->right;
rightpath = rightpath->left;
}
}
}
}
}
}
if (--cachecount < 0) printf("cachelist, cache current too small\n");
cachefreecount--;
cachedeleted--;
#ifdef DEBUG
cacheobj->parent = NULL;
cacheobj->left = NULL;
cacheobj->right = NULL;
cacheobj->nxtcache = NULL;
cacheobj->lstcache = NULL;
cacheobj->objmanager = NULL;
cacheobj->keyval = 0;
cacheobj->status = 0;
cacheobj->refcount = 0;
#endif
free(cacheobj);
return cacheobj;
}
}
/* cachepurge - trim size of free list */
void cachepurge()
{
register struct CACHE *cacheobj = cachelist.lstcache;
while (cachefreecount > CACHEGOAL && cacheobj != &cachelist) {
register struct CACHE *lastobj = cacheobj->lstcache;
#ifdef DEBUG
if (cacheobj->lstcache->nxtcache != cacheobj ||
cacheobj->nxtcache->lstcache != cacheobj ||
*(cacheobj->parent) != cacheobj) {
printf("CACHE pointers in bad shape! %p %p %p - %p\n",
cacheobj->lstcache->nxtcache,cacheobj,cacheobj->nxtcache->lstcache,*(cacheobj->parent));
}
#endif
if (cacheobj->refcount == 0) {
if (cachefree(cacheobj) != lastobj) cacheobj = lastobj;
} else {
cacheobj = lastobj;
}
}
}
/* cacheflush - flush modified entries in cache */
void cacheflush()
{
register struct CACHE *cacheobj = cachelist.lstcache;
while (cacheobj != &cachelist) {
if (cacheobj->status & CACHE_MODIFIED) {
if (cacheobj->objmanager != NULL) {
(*cacheobj->objmanager) (cacheobj);
} else {
printf("CACHEFLUSH No manager to write modified cache\n");
}
}
cacheobj = cacheobj->lstcache;
}
}
/* cachedelete - delete an object from cache */
struct CACHE *cachedelete(struct CACHE *cacheobj)
{
if (cacheobj != NULL) {
register struct CACHE *cachedel;
do {
cachedel = cachefree(cacheobj);
} while (cachedel != NULL && cachedel != cacheobj);
}
return cacheobj;
}
/* cachedeltree: delete cache subtree */
void cachedeltree(struct CACHE *cacheobj)
{
if (cacheobj != NULL) {
if (cacheobj->left != NULL) cachedeltree(cacheobj->left);
if (cacheobj->right != NULL) cachedeltree(cacheobj->right);
if (cacheobj->refcount == 0) cachedelete(cacheobj);
}
}
/* cacheuntouch - decrement object reference count */
unsigned cacheuntouch(struct CACHE *cacheobj,unsigned reuse,unsigned modflg)
{
if (cacheobj->refcount < 1) {
char str[100];
printf("%8p %8p %8p %8p %8x %8x %8d\n",
cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right,
cacheobj->keyval,cacheobj->status,cacheobj->refcount);
printf("CACHE untouch TOO FAR!\n");
printf("Type RETURN: ");
fgets(str, sizeof(str), stdin);
return 64;
} else {
if (modflg) {
if ((cacheobj->status & CACHE_WRITE) == 0) return SS$_WRITLCK;
cacheobj->status |= CACHE_MODIFIED;
}
if (--cacheobj->refcount == 0) {
/* Move to new list position... */
if (reuse == 0 && cacheobj != cachelist.lstcache) {
cacheobj->lstcache->nxtcache = cacheobj->nxtcache;
cacheobj->nxtcache->lstcache = cacheobj->lstcache;
cacheobj->nxtcache = &cachelist;
cacheobj->lstcache = cachelist.lstcache;
cachelist.lstcache->nxtcache = cacheobj;
cachelist.lstcache = cacheobj;
}
cacheobj->status &= ~CACHE_WRITE;
if (++cachefreecount > CACHELIM && freeactive == 0) cachepurge();
}
}
return 1;
}
/* cachetouch - add one to reference count */
void cachetouch(struct CACHE *cacheobj)
{
if (cacheobj->refcount++ < 1) {
#ifdef DEBUG
if (cacheobj->lstcache->nxtcache != cacheobj ||
cacheobj->nxtcache->lstcache != cacheobj ||
*(cacheobj->parent) != cacheobj) {
printf("CACHE pointers in bad shape! %p %p %p - %p\n",
cacheobj->lstcache->nxtcache,cacheobj,cacheobj->nxtcache->lstcache,*(cacheobj->parent));
}
#endif
cachefreecount--;
}
/* Move object to head of list... */
if (cacheobj != cachelist.nxtcache) {
cacheobj->lstcache->nxtcache = cacheobj->nxtcache;
cacheobj->nxtcache->lstcache = cacheobj->lstcache;
cacheobj->lstcache = &cachelist;
cacheobj->nxtcache = cachelist.nxtcache;
cachelist.nxtcache->lstcache = cacheobj;
cachelist.nxtcache = cacheobj;
}
}
/* cachesearch - to find or create cache entries...
The grand plan here was to use a hash code as a quick key
and call a compare function for duplicates. So far no data
type actually works like this - they either have a unique binary
key, or all records rely on the compare function - sigh!
Never mind, the potential is there! :-) */
void *cachesearch(void **root,unsigned keyval,unsigned keylen,void *key,
int (*cmpfunc) (unsigned keylen,void *key,void *node),
unsigned *createsize)
{
register struct CACHE *parentobj = NULL;
register struct CACHE *cacheobj,**parent = (struct CACHE **) root;
cachesearches++;
while ((cacheobj = *parent) != NULL) {
parentobj = cacheobj;
if (cacheobj->keyval == keyval) {
register int cmp = 0;
if (cmpfunc != NULL)
cmp = (*cmpfunc) (keylen,key,(void *) cacheobj);
if (cmp == 0) {
cachetouch(cacheobj);
return cacheobj;
} else {
if (cmp < 0) {
parent = &cacheobj->left;
} else {
parent = &cacheobj->right;
}
}
} else {
if (cacheobj->keyval < keyval) {
parent = &cacheobj->left;
} else {
parent = &cacheobj->right;
}
}
}
if (*createsize > sizeof(struct CACHE)) {
cacheobj = (struct CACHE *) malloc(*createsize);
if (cacheobj != NULL) {
cacheobj->parent = parent;
cacheobj->left = NULL;
cacheobj->right = NULL;
cacheobj->objmanager = NULL;
cacheobj->keyval = keyval;
cacheobj->status = 0;
cacheobj->refcount = 1;
*parent = cacheobj;
*createsize = 0;
cachecreated++;
/* Add to cache list... */
cacheobj->lstcache = &cachelist;
cacheobj->nxtcache = cachelist.nxtcache;
cachelist.nxtcache->lstcache = cacheobj;
cachelist.nxtcache = cacheobj;
if (parentobj != NULL) {
/* Attempt to mix up the tree a little... */
if (parentobj->left == NULL) {
*parentobj->parent = cacheobj;
cacheobj->parent = parentobj->parent;
parentobj->parent = &cacheobj->left;
cacheobj->left = parentobj;
parentobj->right = NULL;
} else {
if (parentobj->right == NULL) {
*parentobj->parent = cacheobj;
cacheobj->parent = parentobj->parent;
parentobj->parent = &cacheobj->right;
cacheobj->right = parentobj;
parentobj->left = NULL;
}
}
}
if (cachecount++ >= cachepeak) cachepeak = cachecount;
}
}
return cacheobj;
}

411
extracters/ods2/cache.c.bak Normal file
View File

@@ -0,0 +1,411 @@
/* Cache.c v1.2 Caching control routines */
/*
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.
*/
/* Caching seems to have a big impact on performance!!!
This version based on number of objects - probably
should change it to use space occupied by objects.
Currently use vanilla binary trees - could either
use hashing or balanced trees for better performance. */
/* The theory is that all cachable objects share a common
cache pool. Any object with a reference count of zero
is a candidate for destruction. All cacheable objects
have a 'struct CACHE' as the first item of the object
so that cache pointers and object pointers are interchangeable.
All cache objects are also part of a binary tree so that
they can be located. There are many instances of these
binary trees: for files on a volume, for chunks (segments)
of files, etc. Also each object can have an object manager:
a routine to handle special object deletion requirements
(for example to remove all file chunks before removing a
file), or to flush objects (write modified chunks to disk). */
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "ssdef.h"
#include "cache.h"
#define DEBUG on
/* Set limits for number of unaccessed cache entries... */
#define CACHELIM 64
#define CACHEGOAL 25
int cachesearches = 0;
int cachecreated = 0;
int cachedeleted = 0;
int cachepeak = 0;
int cachecount = 0;
int cachefreecount = 0;
struct CACHE cachelist = {NULL,NULL,NULL,&cachelist,&cachelist,NULL,0,0,1};
/* cacheshow - to print cache statistics */
void cacheshow(void)
{
printf("CACHESHOW Searches: %d Created: %d Peak: %d Count: %d Free: %d\n",
cachesearches,cachecreated,cachepeak,cachecount,cachefreecount);
}
void cachedump(void)
{
register struct CACHE *cacheobj = cachelist.lstcache;
printf("%8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s cachelist\n","Object",
"Parent","Left","Right","Value","Status","Count");
while (cacheobj != &cachelist) {
printf("%8p %8p %8p %8p %8x %8x %8d\n",
cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right,
cacheobj->keyval,cacheobj->status,cacheobj->refcount);
cacheobj = cacheobj->lstcache;
}
}
/* cacheprint - debugging tool to print out a cache subtree... */
void cacheprint(struct CACHE *cacheobj,int level)
{
if (cacheobj != NULL) {
int i;
cacheprint(cacheobj->left,level + 1);
for (i = 0; i < level; i++) printf(" ");
printf("%8x %8x %8x %d\n",
cacheobj,cacheobj->keyval,cacheobj->status,cacheobj->refcount);
cacheprint(cacheobj->right,level + 1);
}
}
/* cacherefcount - compute reference count for cache subtree... */
int cacherefcount(struct CACHE *cacheobj)
{
register int refcount = 0;
if (cacheobj != NULL) {
if (cacheobj->left != NULL) refcount += cacherefcount(cacheobj->left);
if (cacheobj->right != NULL) refcount += cacherefcount(cacheobj->right);
refcount += cacheobj->refcount;
}
return refcount;
}
/* cachefree - blow away item from cache - allow item to select a proxy (!)
and adjust 'the tree' containing the item. */
int freeactive = 0; /* In case object managers re-call cachefree... :-( */
struct CACHE *cachefree(struct CACHE *cacheobj)
{
if (cacheobj->refcount != 0) {
char str[100];
printf("cachelist, object to delete still inuse?\n");
printf("%8p %8p %8p %8p %8x %8x %8d\n",
cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right,
cacheobj->keyval,cacheobj->status,cacheobj->refcount);
printf("Type RETURN: ");
fgets(str, sizeof(str)-1, stdin);
return NULL;
} else {
register struct CACHE *proxyobj;
while (cacheobj->objmanager != NULL) {
freeactive = 1;
proxyobj = (*cacheobj->objmanager) (cacheobj);
freeactive = 0;
if (proxyobj == NULL) return NULL;
if (proxyobj == cacheobj) break;
cacheobj = proxyobj;
}
if ((cacheobj->status & CACHE_MODIFIED) && cacheobj->objmanager == NULL)
printf("cachelist No manager to write modified cache\n");
cacheobj->lstcache->nxtcache = cacheobj->nxtcache;
cacheobj->nxtcache->lstcache = cacheobj->lstcache;
if (cacheobj->parent != NULL) { /* Check if in tree... */
if (cacheobj->left == NULL) {
if (cacheobj->right == NULL) {
*(cacheobj->parent) = NULL;
} else {
cacheobj->right->parent = cacheobj->parent;
*(cacheobj->parent) = cacheobj->right;
}
} else {
if (cacheobj->right == NULL) {
cacheobj->left->parent = cacheobj->parent;
*(cacheobj->parent) = cacheobj->left;
} else {
register struct CACHE *leftpath = cacheobj->left;
register struct CACHE *rightpath = cacheobj->right;
while (1) {
if (leftpath->right == NULL) {
leftpath->right = cacheobj->right;
cacheobj->right->parent = &leftpath->right;
cacheobj->left->parent = cacheobj->parent;
*(cacheobj->parent) = cacheobj->left;
break;
} else {
if (rightpath->left == NULL) {
rightpath->left = cacheobj->left;
cacheobj->left->parent = &rightpath->left;
cacheobj->right->parent = cacheobj->parent;
*(cacheobj->parent) = cacheobj->right;
break;
} else {
leftpath = leftpath->right;
rightpath = rightpath->left;
}
}
}
}
}
}
if (--cachecount < 0) printf("cachelist, cache current too small\n");
cachefreecount--;
cachedeleted--;
#ifdef DEBUG
cacheobj->parent = NULL;
cacheobj->left = NULL;
cacheobj->right = NULL;
cacheobj->nxtcache = NULL;
cacheobj->lstcache = NULL;
cacheobj->objmanager = NULL;
cacheobj->keyval = 0;
cacheobj->status = 0;
cacheobj->refcount = 0;
#endif
free(cacheobj);
return cacheobj;
}
}
/* cachepurge - trim size of free list */
void cachepurge()
{
register struct CACHE *cacheobj = cachelist.lstcache;
while (cachefreecount > CACHEGOAL && cacheobj != &cachelist) {
register struct CACHE *lastobj = cacheobj->lstcache;
#ifdef DEBUG
if (cacheobj->lstcache->nxtcache != cacheobj ||
cacheobj->nxtcache->lstcache != cacheobj ||
*(cacheobj->parent) != cacheobj) {
printf("CACHE pointers in bad shape! %p %p %p - %p\n",
cacheobj->lstcache->nxtcache,cacheobj,cacheobj->nxtcache->lstcache,*(cacheobj->parent));
}
#endif
if (cacheobj->refcount == 0) {
if (cachefree(cacheobj) != lastobj) cacheobj = lastobj;
} else {
cacheobj = lastobj;
}
}
}
/* cacheflush - flush modified entries in cache */
void cacheflush()
{
register struct CACHE *cacheobj = cachelist.lstcache;
while (cacheobj != &cachelist) {
if (cacheobj->status & CACHE_MODIFIED) {
if (cacheobj->objmanager != NULL) {
(*cacheobj->objmanager) (cacheobj);
} else {
printf("CACHEFLUSH No manager to write modified cache\n");
}
}
cacheobj = cacheobj->lstcache;
}
}
/* cachedelete - delete an object from cache */
struct CACHE *cachedelete(struct CACHE *cacheobj)
{
if (cacheobj != NULL) {
register struct CACHE *cachedel;
do {
cachedel = cachefree(cacheobj);
} while (cachedel != NULL && cachedel != cacheobj);
}
return cacheobj;
}
/* cachedeltree: delete cache subtree */
void cachedeltree(struct CACHE *cacheobj)
{
if (cacheobj != NULL) {
if (cacheobj->left != NULL) cachedeltree(cacheobj->left);
if (cacheobj->right != NULL) cachedeltree(cacheobj->right);
if (cacheobj->refcount == 0) cachedelete(cacheobj);
}
}
/* cacheuntouch - decrement object reference count */
unsigned cacheuntouch(struct CACHE *cacheobj,unsigned reuse,unsigned modflg)
{
if (cacheobj->refcount < 1) {
char str[100];
printf("%8p %8p %8p %8p %8x %8x %8d\n",
cacheobj,cacheobj->parent,cacheobj->left,cacheobj->right,
cacheobj->keyval,cacheobj->status,cacheobj->refcount);
printf("CACHE untouch TOO FAR!\n");
printf("Type RETURN: ");
fgets(str, sizeof(str), stdin);
return 64;
} else {
if (modflg) {
if ((cacheobj->status & CACHE_WRITE) == 0) return SS$_WRITLCK;
cacheobj->status |= CACHE_MODIFIED;
}
if (--cacheobj->refcount == 0) {
/* Move to new list position... */
if (reuse == 0 && cacheobj != cachelist.lstcache) {
cacheobj->lstcache->nxtcache = cacheobj->nxtcache;
cacheobj->nxtcache->lstcache = cacheobj->lstcache;
cacheobj->nxtcache = &cachelist;
cacheobj->lstcache = cachelist.lstcache;
cachelist.lstcache->nxtcache = cacheobj;
cachelist.lstcache = cacheobj;
}
cacheobj->status &= ~CACHE_WRITE;
if (++cachefreecount > CACHELIM && freeactive == 0) cachepurge();
}
}
return 1;
}
/* cachetouch - add one to reference count */
void cachetouch(struct CACHE *cacheobj)
{
if (cacheobj->refcount++ < 1) {
#ifdef DEBUG
if (cacheobj->lstcache->nxtcache != cacheobj ||
cacheobj->nxtcache->lstcache != cacheobj ||
*(cacheobj->parent) != cacheobj) {
printf("CACHE pointers in bad shape! %p %p %p - %p\n",
cacheobj->lstcache->nxtcache,cacheobj,cacheobj->nxtcache->lstcache,*(cacheobj->parent));
}
#endif
cachefreecount--;
}
/* Move object to head of list... */
if (cacheobj != cachelist.nxtcache) {
cacheobj->lstcache->nxtcache = cacheobj->nxtcache;
cacheobj->nxtcache->lstcache = cacheobj->lstcache;
cacheobj->lstcache = &cachelist;
cacheobj->nxtcache = cachelist.nxtcache;
cachelist.nxtcache->lstcache = cacheobj;
cachelist.nxtcache = cacheobj;
}
}
/* cachesearch - to find or create cache entries...
The grand plan here was to use a hash code as a quick key
and call a compare function for duplicates. So far no data
type actually works like this - they either have a unique binary
key, or all records rely on the compare function - sigh!
Never mind, the potential is there! :-) */
void *cachesearch(void **root,unsigned keyval,unsigned keylen,void *key,
int (*cmpfunc) (unsigned keylen,void *key,void *node),
unsigned *createsize)
{
register struct CACHE *parentobj = NULL;
register struct CACHE *cacheobj,**parent = (struct CACHE **) root;
cachesearches++;
while ((cacheobj = *parent) != NULL) {
parentobj = cacheobj;
if (cacheobj->keyval == keyval) {
register int cmp = 0;
if (cmpfunc != NULL)
cmp = (*cmpfunc) (keylen,key,(void *) cacheobj);
if (cmp == 0) {
cachetouch(cacheobj);
return cacheobj;
} else {
if (cmp < 0) {
parent = &cacheobj->left;
} else {
parent = &cacheobj->right;
}
}
} else {
if (cacheobj->keyval < keyval) {
parent = &cacheobj->left;
} else {
parent = &cacheobj->right;
}
}
}
if (*createsize > sizeof(struct CACHE)) {
cacheobj = (struct CACHE *) malloc(*createsize);
if (cacheobj != NULL) {
cacheobj->parent = parent;
cacheobj->left = NULL;
cacheobj->right = NULL;
cacheobj->objmanager = NULL;
cacheobj->keyval = keyval;
cacheobj->status = 0;
cacheobj->refcount = 1;
*parent = cacheobj;
*createsize = 0;
cachecreated++;
/* Add to cache list... */
cacheobj->lstcache = &cachelist;
cacheobj->nxtcache = cachelist.nxtcache;
cachelist.nxtcache->lstcache = cacheobj;
cachelist.nxtcache = cacheobj;
if (parentobj != NULL) {
/* Attempt to mix up the tree a little... */
if (parentobj->left == NULL) {
*parentobj->parent = cacheobj;
cacheobj->parent = parentobj->parent;
parentobj->parent = &cacheobj->left;
cacheobj->left = parentobj;
parentobj->right = NULL;
} else {
if (parentobj->right == NULL) {
*parentobj->parent = cacheobj;
cacheobj->parent = parentobj->parent;
parentobj->parent = &cacheobj->right;
cacheobj->right = parentobj;
parentobj->left = NULL;
}
}
}
if (cachecount++ >= cachepeak) cachepeak = cachecount;
}
}
return cacheobj;
}

44
extracters/ods2/cache.h Normal file
View File

@@ -0,0 +1,44 @@
/* Cache.h v1.2 Definitions for cache routines */
/*
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.
*/
#ifndef CACHE_WRITE
#define CACHE_WRITE 1
#define CACHE_MODIFIED 2
struct CACHE {
struct CACHE **parent;
struct CACHE *left;
struct CACHE *right;
struct CACHE *nxtcache;
struct CACHE *lstcache;
struct CACHE *(*objmanager) (struct CACHE * cacheobj);
unsigned keyval;
unsigned status;
int refcount;
};
void cacheshow(void);
void cachedump(void);
void cacheprint(struct CACHE *cacheobj,int level);
void cacheflush(void);
int cacherefcount(struct CACHE *cacheobj);
void cachedeltree(struct CACHE *cacheobj);
void cachetouch(struct CACHE *cacheobj);
unsigned cacheuntouch(struct CACHE *cacheobj,unsigned reuse,unsigned modflg);
struct CACHE *cachefree(struct CACHE *cacheobj);
struct CACHE *cachedelete(struct CACHE *cacheobj);
struct CACHE *cachemake(struct CACHE **parent,unsigned length);
void *cachesearch(void **root,unsigned keyval,unsigned keylen,void *key,
int (*cmpfunc) (unsigned keylen,void *key,void *node),
unsigned *createsize);
#endif

34
extracters/ods2/descrip.h Normal file
View File

@@ -0,0 +1,34 @@
/* Descrip.h v1.2 Definitions for descriptors */
/*
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.
*/
#if defined(VMS) && !defined(__GNUC__)
#include <descrip.h>
#else
#ifndef DSC$K_DTYPE_T
#define DSC$K_DTYPE_T 0
#define DSC$K_CLASS_S 0
struct dsc$descriptor {
unsigned short dsc$w_length;
unsigned char dsc$w_type;
unsigned char dsc$w_class;
char *dsc$a_pointer;
};
#define $DESCRIPTOR(string,name) struct dsc$descriptor name = {sizeof(sring)-1,0,0,string};
#endif
#endif

85
extracters/ods2/device.c Normal file
View File

@@ -0,0 +1,85 @@
/* Device.c v1.2 Module to remember and find devices...*/
/*
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.
*/
/* Should have mechanism to return actual device name... */
/* This module is simple enough - it just keeps track of
device names and initialization... */
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <ctype.h>
#include "ssdef.h"
#include "access.h"
#include "phyio.h"
int devcmp(unsigned keylen,void *key,void *node)
{
register struct DEV *devnode = (struct DEV *) node;
register int cmp = keylen - devnode->devlen;
if (cmp == 0) {
register unsigned len = keylen;
register char *keynam = (char *) key;
register char *devnam = devnode->devnam;
while (len-- > 0) {
cmp = toupper(*keynam++) - toupper(*devnam++);
if (cmp != 0) break;
}
}
return cmp;
}
struct DEV *dev_root = NULL;
unsigned device_lookup(unsigned devlen,char *devnam,
int create,struct DEV **retdev)
{
register struct DEV *dev;
register unsigned sts,devsiz = 0;
unsigned devcreate = 0;
while (devsiz < devlen) {
if (devnam[devsiz] == ':') break;
devsiz++;
}
if (create) devcreate = sizeof(struct DEV) + devsiz + 2;
dev = (struct DEV *) cachesearch((void **) &dev_root,0,devsiz,
(void *) devnam,devcmp,&devcreate);
if (dev == NULL) {
if (create) {
sts = SS$_INSFMEM;
} else {
sts = SS$_NOSUCHDEV;
}
} else {
struct phyio_info info;
*retdev = dev;
if (create && (devcreate == 0)) {
memcpy(dev->devnam,devnam,devsiz);
memcpy(dev->devnam + devsiz,":",2);
dev->devlen = devsiz;
sts = phyio_init(devsiz + 1,dev->devnam,&dev->handle,&info);
if (sts & 1) {
dev->status = info.status;
dev->sectors = info.sectors;
dev->sectorsize = info.sectorsize;
} else {
cacheuntouch((struct CACHE *) dev,0,0);
cachefree((struct CACHE *) dev);
}
} else {
sts = 1;
}
}
return sts;
}

550
extracters/ods2/direct.c Normal file
View File

@@ -0,0 +1,550 @@
/* Direct.c v1.2 */
/*
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.
*/
/* This module does all directory file handling - mostly
lookups of filenames in directory files... */
/* This version takes relative version from last seen directory record
- this is no good if there are multiple directory records for a file! */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <memory.h>
#include "ssdef.h"
#include "descrip.h"
#include "fibdef.h"
#include "access.h"
#include "direct.h"
#define DEBUGx on
int directlookups = 0;
int directsearches = 0;
int directdels = 0;
int directchecks = 0;
int directmatches = 0;
/* directshow - to print directory statistics */
void directshow(void)
{
printf("DIRECTSHOW Lookups: %d Searches: %d Deletes: %d Checks: %d Matches: %d\n",
directlookups,directsearches,directdels,directchecks,directmatches);
}
/* namecheck - take a name specification and return name length without
the version number, an integer version number, and a wildcard flag */
unsigned namecheck(char *str,int len,int *retlen,int *retver,int *wildflag)
{
int wildcard = 0;
char *spcbeg = str;
register int dots = 0;
register char *spc = spcbeg;
register char *spcend = spc + len;
directchecks++;
while (spc < spcend) {
register char ch = *spc++;
if (ch == '.') {
if ((spc - spcbeg) > 40) return SS$_BADFILENAME;
spcbeg = spc;
if (dots++ > 1) break;
} else {
if (ch == ';') {
break;
} else {
if (ch == '*' || ch == '%') {
wildcard = 1;
} else {
if (ch == '[' || ch == ']' || ch == ':' ||
!isprint(ch)) return SS$_BADFILENAME;
}
}
}
}
if ((spc - spcbeg) > 40) return SS$_BADFILENAME;
*retlen = spc - str - 1;
dots = 0;
if (spc < spcend) {
register char ch = *spc;
if (ch == '*') {
if (++spc < spcend) return SS$_BADFILENAME;
dots = 32768;
wildcard = 1;
} else {
register int sign = 1;
if (ch == '-') {
spc++;
sign = -1;
}
while (spc < spcend) {
ch = *spc++;
if (!isdigit(ch)) return SS$_BADFILENAME;
dots = dots * 10 + (ch - '0');
}
dots *= sign;
}
}
*retver = dots;
*wildflag = wildcard;
#ifdef DEBUG
printf("Namecheck %d %d %d\n",*retlen,*retver,*wildflag);
#endif
return SS$_NORMAL;
}
#define MAT_LT 0
#define MAT_EQ 1
#define MAT_GT 2
#define MAT_NE 3
/* namematch - compare a name specification with a directory entry
and determine if there is a match, too big, too small... */
int namematch(char *spec,int speclen,char *entry,int entrylen)
{
int percent = 0;
register char *spc = spec,*ent = entry;
register char *spcend = spc + speclen,*entend = ent + entrylen;
directmatches++;
/* See how much matches without wildcards... */
if (spc < spcend && ent < entend) {
register int count = speclen;
if (entrylen < count) count = entrylen;
do {
register char sch = *spc,ech = *ent;
if (sch != ech) if (toupper(sch) != toupper(ech))
if (sch == '%') {
percent = 1;
} else {
break;
}
spc++;
ent++;
} while (--count > 0);
}
#ifdef DEBUG
printf("Namematch %3s %d %3s %d\n",spec,speclen,entry,entrylen);
#endif
/* Mismatch - return result unless wildcard... */
if (spc >= spcend) {
if (ent >= entend) {
return MAT_EQ;
} else {
if (percent) {
return MAT_NE;
} else {
return MAT_GT; /* Entry longer than search spec */
}
}
} else {
register int offset = 0;
if (*spc != '*') {
if (percent) return MAT_NE;
if (ent < entend)
if (toupper(*ent) > toupper(*spc)) return MAT_GT;
return MAT_LT;
}
/* See if we can find a match with wildcards */
spc++;
if (spc < spcend) {
do {
if (spc >= spcend) {
if (ent >= entend) break;
spc -= offset;
ent -= offset - 1;
offset = 0;
} else {
register char sch = toupper(*spc);
if (sch == '*') {
offset = 0;
spc++;
if (spc >= spcend) break;
} else {
if (ent < entend) {
register char ech = toupper(*ent);
if (sch == ech || sch == '%') {
offset++;
spc++;
ent++;
} else {
spc -= offset;
ent -= offset - 1;
offset = 0;
}
} else {
return MAT_NE;
}
}
}
} while (1);
}
}
return MAT_EQ;
}
unsigned freesize(char *buffer)
{
struct dir$rec *dr = (struct dir$rec *) buffer;
do {
register char *nr = (char *) dr + dr->dir$size + 2;
if (nr >= buffer + 512) break;
dr = (struct dir$rec *) nr;
} while (1);
return (char *) dr - buffer - 2;
}
unsigned insrec(void)
{
printf("Insert directory record\n");
return 0;
}
unsigned insent(struct FCB *fcb,struct VIOC *vioc,unsigned curblk,
struct dir$rec *dr,struct dir$ent *de,
char *buffer,unsigned eofblk)
{
printf("Insert directory entry\n");
if (freesize(buffer) >= sizeof(struct dir$ent)) {
char *ne = (char *) de + sizeof(struct dir$ent);
memcpy(de,ne,512 - (ne - buffer));
dr->dir$size -= sizeof(struct dir$ent);
}
return 0;
}
/* delent - delete a directory entry */
unsigned delent(struct FCB *fcb,struct VIOC *vioc,unsigned curblk,
struct dir$rec *dr,struct dir$ent *de,
char *buffer,unsigned modmask,unsigned eofblk)
{
unsigned sts = 1;
unsigned ent;
directdels++;
ent = (dr->dir$size - sizeof(struct dir$rec)
- dr->dir$namecount + 3) / sizeof(struct dir$ent);
printf("DELENT ent = %d %d %d\n",ent,curblk,eofblk);
if (ent > 1) {
char *ne = (char *) de + sizeof(struct dir$ent);
memcpy(de,ne,512 - (ne - buffer));
dr->dir$size -= sizeof(struct dir$ent);
} else {
char *nr = (char *) dr + dr->dir$size + 2;
if (eofblk == 1 || (char *) dr > buffer ||
(nr <= buffer + 510 && (unsigned short) *nr < 512)) {
memcpy(dr,nr,512 - (nr - buffer));
} else {
printf("DELENT shrinking file size %d %d\n",curblk,eofblk);
while (curblk < eofblk) {
char *nxtbuffer;
struct VIOC *nxtvioc;
unsigned nxtmodmask;
sts = accesschunk(fcb,++curblk,&nxtvioc,&nxtbuffer,NULL,1,&nxtmodmask);
if ((sts & 1) == 0) break;
memcpy(buffer,nxtbuffer,512);
sts = deaccesschunk(vioc,modmask,1);
if ((sts & 1) == 0) break;
buffer = nxtbuffer;
vioc = nxtvioc;
modmask = nxtmodmask;
}
if (sts & 1) {
fcb->head->fh2$w_recattr.fat$l_efblk[0] = eofblk >> 16;
fcb->head->fh2$w_recattr.fat$l_efblk[1] = (eofblk & 0xffff);
eofblk--;
}
}
}
{
unsigned retsts = deaccesschunk(vioc,modmask,1);
if (sts & 1) sts = retsts;
return sts;
}
}
/* retent - return information about a directory entry */
unsigned retent(struct FCB *fcb,struct VIOC *vioc,unsigned curblk,
struct dir$rec *dr,struct dir$ent *de,struct fibdef *fib,
unsigned short *reslen,struct dsc$descriptor *resdsc,
int wildcard)
{
register int scale = 10;
register int version = de->dir$version;
register int length = dr->dir$namecount;
register char *ptr = resdsc->dsc$a_pointer;
memcpy(ptr,dr->dir$name,length);
while (version >= scale) scale *= 10;
ptr += length++;
*ptr++ = ';';
do {
scale /= 10;
*ptr++ = version / scale + '0';
version %= scale;
length++;
} while (scale > 1);
*reslen = length;
memcpy(&fib->fib$w_fid_num,&de->dir$fid,sizeof(struct fiddef));
if (fib->fib$b_fid_rvn == 0) fib->fib$b_fid_rvn = fcb->rvn;
if (wildcard || (fib->fib$w_nmctl & FIB$M_WILD)) {
fib->fib$l_wcc = curblk;
} else {
fib->fib$l_wcc = 0;
}
return deaccesschunk(vioc,0,1);
}
/* searchent - search for a directory entry */
unsigned searchent(struct FCB * fcb,
struct dsc$descriptor * fibdsc,struct dsc$descriptor * filedsc,
unsigned short *reslen,struct dsc$descriptor * resdsc,unsigned eofblk,unsigned action)
{
register unsigned sts,curblk;
struct VIOC *vioc = NULL;
unsigned modmask;
char *searchspec,*buffer;
int searchlen,version,wildcard,wcc_flag;
struct fibdef *fib = (struct fibdef *) fibdsc->dsc$a_pointer;
directlookups++;
/* 1) Generate start block (wcc gives start point)
2) Search for start
3) Scan until found or too big or end */
curblk = fib->fib$l_wcc;
if (curblk != 0) {
searchspec = resdsc->dsc$a_pointer;
sts = namecheck(searchspec,*reslen,&searchlen,&version,&wildcard);
if (action || wildcard) return SS$_BADFILENAME;
wcc_flag = 1;
} else {
searchspec = filedsc->dsc$a_pointer;
sts = namecheck(searchspec,filedsc->dsc$w_length,&searchlen,&version,&wildcard);
if ((action && wildcard) || (action > 1 && version < 0)) return SS$_BADFILENAME;
wcc_flag = 0;
}
if ((sts & 1) == 0) return sts;
/* Identify starting block...*/
if (*searchspec == '*' || *searchspec == '%') {
curblk = 1;
} else {
register unsigned loblk = 1,hiblk = eofblk;
if (curblk < 1 || curblk > eofblk) curblk = (eofblk + 1) / 2;
while (loblk < hiblk) {
register int cmp;
register unsigned newblk;
register struct dir$rec *dr;
directsearches++;
sts = accesschunk(fcb,curblk,&vioc,&buffer,NULL,action ? 1 : 0,&modmask);
if ((sts & 1) == 0) return sts;
dr = (struct dir$rec *) buffer;
if (dr->dir$size > 510) {
cmp = MAT_GT;
} else {
cmp = namematch(searchspec,searchlen,dr->dir$name,dr->dir$namecount);
if (cmp == MAT_EQ) {
if (wildcard || version < 1 || version > 32767) {
cmp = MAT_NE; /* no match - want to find start */
} else {
register struct dir$ent *de =
(struct dir$ent *) (dr->dir$name + ((dr->dir$namecount + 1) & ~1));
if (de->dir$version < version) {
cmp = MAT_GT; /* too far... */
} else {
if (de->dir$version > version) {
cmp = MAT_LT; /* further ahead... */
}
}
}
}
}
#ifdef DEBUG
printf("Direct %6.6s %d %6.6s %d (%d<%d<%d)-> %d\n",
searchspec,searchlen,dr->dir$name,dr->dir$namecount,
loblk,curblk,hiblk,cmp);
#endif
switch (cmp) {
case MAT_LT:
if (curblk == fib->fib$l_wcc) {
newblk = hiblk = loblk = curblk;
} else {
loblk = curblk;
newblk = (loblk + hiblk + 1) / 2;
}
break;
case MAT_GT:
case MAT_NE:
newblk = (loblk + curblk) / 2;
hiblk = curblk - 1;
break;
default:
newblk = hiblk = loblk = curblk;
}
if (newblk != curblk) {
sts = deaccesschunk(vioc,0,1);
if ((sts & 1) == 0) return sts;
vioc = NULL;
curblk = newblk;
}
}
}
/* Now to read sequentially to find entry... */
while ((sts & 1) && curblk <= eofblk) {
register struct dir$rec *dr;
if (vioc == NULL) {
sts = accesschunk(fcb,curblk,&vioc,&buffer,NULL,action ? 1 : 0,&modmask);
if ((sts & 1) == 0) return sts;
}
dr = (struct dir$rec *) buffer;
do {
register int cmp;
register char *nr = (char *) dr + dr->dir$size + 2;
if (nr >= buffer + 512) break;
cmp = namematch(searchspec,searchlen,dr->dir$name,dr->dir$namecount);
#ifdef DEBUF
printf("Direct %6.6s %d %6.6s %d -> %d\n",
searchspec,searchlen,dr->dir$name,dr->dir$namecount,cmp);
#endif
if (cmp == MAT_GT) {
if (wcc_flag) {
wcc_flag = 0;
searchspec = filedsc->dsc$a_pointer;
sts = namecheck(searchspec,filedsc->dsc$w_length,&searchlen,&version,&wildcard);
if ((sts & 1) == 0) break;
} else {
curblk = eofblk; /* give up */
break;
}
} else {
if (cmp == MAT_EQ) {
register int relver = 0;
register struct dir$ent *de = (struct dir$ent *) (dr->dir$name +
((dr->dir$namecount + 1) & ~1));
while ((char *) de < nr) {
if (version >= de->dir$version || (version < 1 && version >= relver)) {
cmp = MAT_GT;
if (version > 32767 || version == relver ||
version == de->dir$version) cmp = MAT_EQ;
if (wcc_flag) {
wcc_flag = 0;
searchspec = filedsc->dsc$a_pointer;
sts = namecheck(searchspec,filedsc->dsc$w_length,&searchlen,&version,&wildcard);
if ((sts & 1) == 0) break;
if (namematch(searchspec,searchlen,dr->dir$name,
dr->dir$namecount) != MAT_EQ) {
break;
}
if (cmp == MAT_EQ) {
cmp = MAT_LT;
} else {
cmp = MAT_LT;
if (version >= de->dir$version || (version < 1 && version >= relver)) {
cmp = MAT_GT;
if (version > 32767 || version == relver ||
version == de->dir$version) cmp = MAT_EQ;
}
}
}
if (cmp == MAT_EQ) {
switch (action) {
case 0:
return
retent(fcb,vioc,curblk,dr,de,fib,reslen,resdsc,wildcard);
case 1:
return
delent(fcb,vioc,curblk,dr,de,buffer,modmask,eofblk);
default:
sts = SS$_DUPFILENAME;
de = (struct dir$ent *) nr;
}
} else {
if (cmp == MAT_GT) break;
}
}
relver--;
de++;
}
if ((sts & 1) == 0) break;
if (action == 2) {
return insent(fcb,vioc,curblk,dr,de,buffer,eofblk);
}
}
dr = (struct dir$rec *) nr;
}
} while (1);
{
register unsigned dests = deaccesschunk(vioc,0,1);
vioc = NULL;
if (sts & 1) sts = dests;
}
curblk++;
}
if (action == 2) {
return insrec();
}
if (sts & 1) {
fib->fib$l_wcc = 0;
if (wcc_flag || wildcard) {
sts = SS$_NOMOREFILES;
} else {
sts = SS$_NOSUCHFILE;
}
}
return sts;
}
/* direct - this routine handles all directory manipulations:-
action 0 - find directory entry
1 - delete entry
2 - create an entry */
unsigned direct(struct VCB *vcb,struct dsc$descriptor * fibdsc,
struct dsc$descriptor *filedsc,unsigned short *reslen,
struct dsc$descriptor *resdsc,unsigned action)
{
struct FCB *fcb;
register unsigned sts,eofblk;
register struct fibdef *fib = (struct fibdef *) fibdsc->dsc$a_pointer;
sts = accessfile(vcb,(struct fiddef *) & fib->fib$w_did_num,&fcb,action);
if (sts & 1) {
if (fcb->head->fh2$l_filechar & FH2$M_DIRECTORY) {
eofblk = swapw(fcb->head->fh2$w_recattr.fat$l_efblk);
if (fcb->head->fh2$w_recattr.fat$w_ffbyte == 0) --eofblk;
sts = searchent(fcb,fibdsc,filedsc,reslen,resdsc,eofblk,action);
} else {
sts = SS$_BADIRECTORY;
}
{
register unsigned dests = deaccessfile(fcb);
if (sts & 1) sts = dests;
}
}
return sts;
}

31
extracters/ods2/direct.h Normal file
View File

@@ -0,0 +1,31 @@
/* Direct.h v1.2 Definitions for directory access routines */
/*
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.
*/
struct dir$rec {
u_word dir$size;
u_word dir$verlimit;
u_byte dir$flags;
u_byte dir$namecount;
char dir$name[1];
};
struct dir$ent {
u_word dir$version;
struct fiddef dir$fid;
};
unsigned direct(struct VCB *vcb,struct dsc$descriptor * fibdsc,
struct dsc$descriptor *filedsc,unsigned short *reslen,
struct dsc$descriptor *resdsc,unsigned action);

37
extracters/ods2/fibdef.h Normal file
View File

@@ -0,0 +1,37 @@
/* Fibdef.h v1.2 Definition of 'struct fibdef' */
/*
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.
*/
#if defined(VMS) && !defined(__GNUC__)
#include <fibdef.h>
#else
#define FIB$M_WILD 0x100
struct fibdef {
unsigned fib$l_acctl;
unsigned short fib$w_fid_num;
unsigned short fib$w_fid_seq;
unsigned char fib$b_fid_rvn;
unsigned char fib$b_fid_nmx;
unsigned short fib$w_did_num;
unsigned short fib$w_did_seq;
unsigned char fib$b_did_rvn;
unsigned char fib$b_did_nmx;
unsigned fib$l_wcc;
unsigned fib$w_nmctl;
unsigned fib$l_exsz;
unsigned fib$w_exctl;
};
#endif

896
extracters/ods2/ods2.c Normal file
View File

@@ -0,0 +1,896 @@
/* ODS2.C v1.2 Mainline ODS2 program */
/*
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.
The modules in ODS2 are:-
ACCESS.C Routines for accessing ODS2 disks
CACHE.C Routines for managing memory cache
DEVICE.C Routines to maintain device information
DIRECT.C Routines for handling directories
ODS2.C The mainline program
PHYVMS.C Routine to perform physical I/O
RMS.C Routines to handle RMS structures
VMSTIME.C Routines to handle VMS times
On non-VMS platforms PHYVMS.C should be replaced as follows:-
OS/2 PHYOS2.C
Windows 95/NT PHYNT.C
For example under OS/2 the program is compiled using the GCC
compiler with the single command:-
gcc -fdollars-in-identifiers ods2.c,rms.c,direct.c,
access.c,device.c,cache.c,phyos2.c,vmstime.c
*/
/* This version will compile and run using normal VMS I/O by
defining VMSIO
*/
/* This is the top level set of routines. It is fairly
simple minded asking the user for a command, doing some
primitive command parsing, and then calling a set of routines
to perform whatever function is required (for example COPY).
Some routines are implemented in different ways to test the
underlying routines - for example TYPE is implemented without
a NAM block meaning that it cannot support wildcards...
(sorry! - could be easily fixed though!)
*/
#define DEBUGx on
#define VMSIOx on
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "descrip.h"
#include "ssdef.h"
#ifdef VMSIO
#include <starlet.h>
#include <rms.h>
unsigned sys$setddir();
#else
#include "rms.h"
#include "access.h"
#endif
#define PRINT_ATTR (FAB$M_CR | FAB$M_PRN | FAB$M_FTN)
/* keycomp: routine to compare parameter to a keyword - case insensitive! */
int keycomp(char *param,char *keywrd)
{
while (*param != '\0') {
if (tolower(*param++) != *keywrd++) return 0;
}
return 1;
}
/* checkquals: routine to find a qualifer in a list of possible values */
int checkquals(char *qualset[],int qualc,char *qualv[])
{
int result = 0;
while (qualc-- > 0) {
int i = 0;
while (qualset[i] != NULL) {
if (keycomp(qualv[qualc],qualset[i])) {
result |= 1 << i;
i = -1;
break;
}
i++;
}
if (i >= 0) printf("%%ODS2-W-ILLQUAL, Unknown qualifer '%s' ignored\n",qualv[qualc]);
}
return result;
}
/* dir: a directory routine */
char *dirquals[] = {"date","file","size",NULL};
unsigned dir(int argc,char *argv[],int qualc,char *qualv[])
{
char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
int sts,options;
int filecount = 0;
struct NAM nam = cc$rms_nam;
struct FAB fab = cc$rms_fab;
struct XABDAT dat = cc$rms_xabdat;
struct XABFHC fhc = cc$rms_xabfhc;
nam.nam$l_esa = res;
nam.nam$b_ess = NAM$C_MAXRSS;
fab.fab$l_nam = &nam;
fab.fab$l_xab = &dat;
dat.xab$l_nxt = &fhc;
fab.fab$l_fna = argv[1];
fab.fab$b_fns = strlen(fab.fab$l_fna);
fab.fab$l_dna = "*.*;*";
fab.fab$b_dns = strlen(fab.fab$l_dna);
options = checkquals(dirquals,qualc,qualv);
sts = sys$parse(&fab);
if (sts & 1) {
char dir[NAM$C_MAXRSS + 1];
int namelen;
int dirlen = 0;
int dirfiles = 0,dircount = 0;
int dirblocks = 0,totblocks = 0;
int printcol = 0;
#ifdef DEBUG
res[nam.nam$b_esl] = '\0';
printf("Parse: %s\n",res);
#endif
nam.nam$l_rsa = rsa;
nam.nam$b_rss = NAM$C_MAXRSS;
fab.fab$l_fop = FAB$M_NAM;
while ((sts = sys$search(&fab)) & 1) {
if (dirlen != nam.nam$b_dev + nam.nam$b_dir ||
memcmp(rsa,dir,nam.nam$b_dev + nam.nam$b_dir) != 0) {
if (dirfiles > 0) {
if (printcol > 0) printf("\n");
printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s"));
if (options & 4) {
printf(", %d block%s.\n",dirblocks,(dirblocks == 1 ? "" : "s"));
} else {
fputs(".\n",stdout);
}
}
dirlen = nam.nam$b_dev + nam.nam$b_dir;
memcpy(dir,rsa,dirlen);
dir[dirlen] = '\0';
printf("\nDirectory %s\n\n",dir);
filecount += dirfiles;
totblocks += dirblocks;
dircount++;
dirfiles = 0;
dirblocks = 0;
printcol = 0;
}
rsa[nam.nam$b_rsl] = '\0';
namelen = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
if (options == 0) {
if (printcol > 0) {
int newcol = (printcol + 20) / 20 * 20;
if (newcol + namelen >= 80) {
fputs("\n",stdout);
printcol = 0;
} else {
printf("%*s",newcol - printcol," ");
printcol = newcol;
}
}
fputs(rsa + dirlen,stdout);
printcol += namelen;
} else {
if (namelen > 18) {
printf("%s\n ",rsa + dirlen);
} else {
printf("%-19s",rsa + dirlen);
}
sts = sys$open(&fab);
if ((sts & 1) == 0) {
printf("Open error: %d\n",sts);
} else {
sts = sys$close(&fab);
if (options & 2) {
char fileid[100];
sprintf(fileid,"(%d,%d,%d)",
(nam.nam$b_fid_nmx << 16) | nam.nam$w_fid_num,
nam.nam$w_fid_seq,nam.nam$b_fid_rvn);
printf(" %-22s",fileid);
}
if (options & 4) {
unsigned filesize = fhc.xab$l_ebk;
if (fhc.xab$w_ffb == 0) filesize--;
printf("%9d",filesize);
dirblocks += filesize;
}
if (options & 1) {
char tim[24];
struct dsc$descriptor timdsc;
timdsc.dsc$w_length = 23;
timdsc.dsc$a_pointer = tim;
sts = sys$asctim(0,&timdsc,&dat.xab$q_cdt,0);
if ((sts & 1) == 0) printf("Asctim error: %d\n",sts);
tim[23] = '\0';
printf(" %s",tim);
}
printf("\n");
}
}
dirfiles++;
}
if (sts == RMS$_NMF) sts = 1;
if (printcol > 0) printf("\n");
if (dirfiles > 0) {
printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s"));
if (options & 4) {
printf(", %d block%s.\n",dirblocks,(dirblocks == 1 ? "" : "s"));
} else {
fputs(".\n",stdout);
}
filecount += dirfiles;
totblocks += dirblocks;
if (dircount > 1) {
printf("\nGrand total of %d director%s, %d file%s",
dircount,(dircount == 1 ? "y" : "ies"),
filecount,(filecount == 1 ? "" : "s"));
if (options & 4) {
printf(", %d block%s.\n",totblocks,(totblocks == 1 ? "" : "s"));
} else {
fputs(".\n",stdout);
}
}
}
}
if (sts & 1) {
if (filecount < 1) printf("%%DIRECT-W-NOFILES, no files found\n");
} else {
printf("%%DIR-E-ERROR Status: %d\n",sts);
}
return sts;
}
/* copy: a file copy routine */
#define MAXREC 32767
unsigned copy(int argc,char *argv[],int qualc,char *qualv[])
{
int sts;
struct NAM nam = cc$rms_nam;
struct FAB fab = cc$rms_fab;
char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
int filecount = 0;
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 = strlen(fab.fab$l_fna);
sts = sys$parse(&fab);
if (sts & 1) {
nam.nam$l_rsa = rsa;
nam.nam$b_rss = NAM$C_MAXRSS;
fab.fab$l_fop = FAB$M_NAM;
while ((sts = sys$search(&fab)) & 1) {
sts = sys$open(&fab);
if ((sts & 1) == 0) {
printf("%%COPY-F-OPENFAIL, Open error: %d\n",sts);
perror("-COPY-F-ERR ");
} else {
struct RAB rab = cc$rms_rab;
rab.rab$l_fab = &fab;
if ((sts = sys$connect(&rab)) & 1) {
FILE *tof;
char name[NAM$C_MAXRSS + 1];
unsigned records = 0;
{
char *out = name,*inp = argv[2];
int dot = 0;
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 {
unsigned length = nam.nam$b_name;
if (*inp == '\0') length += nam.nam$b_type;
memcpy(out,nam.nam$l_name,length);
out += length;
}
} else {
if (*inp == '.') {
dot = 1;
} else {
if (strchr(":]\\/",*inp)) dot = 0;
}
*out++ = *inp++;
}
}
*out++ = '\0';
}
tof = fopen(name,"w");
if (tof == NULL) {
printf("%%COPY-F-OPENOUT, Could not open %s\n",name);
perror("-COPY-F-ERR ");
} else {
char rec[MAXREC + 2];
filecount++;
rab.rab$l_ubf = rec;
rab.rab$w_usz = MAXREC;
while ((sts = sys$get(&rab)) & 1) {
unsigned rsz = rab.rab$w_rsz;
if (fab.fab$b_rat & PRINT_ATTR) rec[rsz++] = '\n';
if (fwrite(rec,rsz,1,tof) == 1) {
records++;
} else {
printf("%%COPY-F- fwrite error!!\n");
perror("-COPY-F-ERR ");
break;
}
}
if (fclose(tof)) {
printf("%%COPY-F- fclose error!!\n");
perror("-COPY-F-ERR ");
}
}
sys$disconnect(&rab);
if (sts == RMS$_EOF) {
rsa[nam.nam$b_rsl] = '\0';
printf("%%COPY-S-COPIED, %s copied to %s (%d record%s)\n",
rsa,name,records,(records == 1 ? "" : "s"));
sts = 1;
}
}
sys$close(&fab);
}
}
if (sts == RMS$_NMF) sts = 1;
}
if (sts & 1) {
if (filecount > 0) printf("%%COPY-S-NEWFILES, %d file%s created\n",
filecount,(filecount == 1 ? "" : "s"));
} else {
printf("%%COPY-F-ERROR Status: %d\n",sts);
}
return sts;
}
/* diff: a simple file difference routine */
unsigned diff(int argc,char *argv[],int qualc,char *qualv[])
{
int sts;
struct FAB fab = cc$rms_fab;
FILE *tof;
int records = 0;
fab.fab$l_fna = argv[1];
fab.fab$b_fns = strlen(fab.fab$l_fna);
tof = fopen(argv[2],"r");
if (tof == NULL) {
printf("Could not open file %s\n",argv[1]);
sts = 0;
} else {
if ((sts = sys$open(&fab)) & 1) {
struct RAB rab = cc$rms_rab;
rab.rab$l_fab = &fab;
if ((sts = sys$connect(&rab)) & 1) {
char rec[MAXREC + 2],cpy[MAXREC + 1];
rab.rab$l_ubf = rec;
rab.rab$w_usz = MAXREC;
while ((sts = sys$get(&rab)) & 1) {
strcpy(rec + rab.rab$w_rsz,"\n");
fgets(cpy,MAXREC,tof);
if (strcmp(rec,cpy) != 0) {
printf("%%DIFF-F-DIFFERENT Files are different!\n");
sts = 4;
break;
} else {
records++;
}
}
sys$disconnect(&rab);
}
sys$close(&fab);
}
fclose(tof);
if (sts == RMS$_EOF) sts = 1;
}
if (sts & 1) {
printf("%%DIFF-I-Compared %d records\n",records);
} else {
printf("%%DIFF-F-Error %d in difference\n",sts);
}
return sts;
}
/* typ: a file TYPE routine */
unsigned typ(int argc,char *argv[],int qualc,char *qualv[])
{
int sts;
int records = 0;
struct FAB fab = cc$rms_fab;
fab.fab$l_fna = argv[1];
fab.fab$b_fns = strlen(fab.fab$l_fna);
if ((sts = sys$open(&fab)) & 1) {
struct RAB rab = cc$rms_rab;
rab.rab$l_fab = &fab;
if ((sts = sys$connect(&rab)) & 1) {
char rec[MAXREC + 2];
rab.rab$l_ubf = rec;
rab.rab$w_usz = MAXREC;
while ((sts = sys$get(&rab)) & 1) {
unsigned rsz = rab.rab$w_rsz;
if (fab.fab$b_rat & PRINT_ATTR) rec[rsz++] = '\n';
rec[rsz++] = '\0';
fputs(rec,stdout);
records++;
}
sys$disconnect(&rab);
}
sys$close(&fab);
if (sts == RMS$_EOF) sts = 1;
}
if ((sts & 1) == 0) {
printf("%%TYPE-F-ERROR Status: %d\n",sts);
}
return sts;
}
/* search: a simple file search routine */
unsigned search(int argc,char *argv[],int qualc,char *qualv[])
{
int sts = 0;
int filecount = 0;
int findcount = 0;
char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
struct NAM nam = cc$rms_nam;
struct FAB fab = cc$rms_fab;
register char *searstr = argv[2];
register char firstch = tolower(*searstr++);
register char *searend = searstr + strlen(searstr);
{
char *str = searstr;
while (str < searend) {
*str = tolower(*str);
str++;
}
}
nam = cc$rms_nam;
fab = cc$rms_fab;
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 = strlen(fab.fab$l_fna);
fab.fab$l_dna = "";
fab.fab$b_dns = strlen(fab.fab$l_dna);
sts = sys$parse(&fab);
if (sts & 1) {
nam.nam$l_rsa = rsa;
nam.nam$b_rss = NAM$C_MAXRSS;
fab.fab$l_fop = FAB$M_NAM;
while ((sts = sys$search(&fab)) & 1) {
sts = sys$open(&fab);
if ((sts & 1) == 0) {
printf("%%SEARCH-F-OPENFAIL, Open error: %d\n",sts);
} else {
struct RAB rab = cc$rms_rab;
rab.rab$l_fab = &fab;
if ((sts = sys$connect(&rab)) & 1) {
int printname = 1;
char rec[MAXREC + 2];
filecount++;
rab.rab$l_ubf = rec;
rab.rab$w_usz = MAXREC;
while ((sts = sys$get(&rab)) & 1) {
register char *strng = rec;
register char *strngend = strng + (rab.rab$w_rsz - (searend - searstr));
while (strng < strngend) {
register char ch = *strng++;
if (ch == firstch || (ch >= 'A' && ch <= 'Z' && ch + 32 == firstch)) {
register char *str = strng;
register char *cmp = searstr;
while (cmp < searend) {
register char ch2 = *str++;
ch = *cmp;
if (ch2 != ch && (ch2 < 'A' || ch2 > 'Z' || ch2 + 32 != ch)) break;
cmp++;
}
if (cmp >= searend) {
findcount++;
rec[rab.rab$w_rsz] = '\0';
if (printname) {
rsa[nam.nam$b_rsl] = '\0';
printf("\n******************************\n%s\n\n",rsa);
printname = 0;
}
fputs(rec,stdout);
if (fab.fab$b_rat & PRINT_ATTR) fputc('\n',stdout);
break;
}
}
}
}
sys$disconnect(&rab);
}
if (sts == SS$_NOTINSTALL) {
printf("%%SEARCH-W-NOIMPLEM, file operation not implemented\n");
sts = 1;
}
sys$close(&fab);
}
}
if (sts == RMS$_NMF || sts == RMS$_FNF) sts = 1;
}
if (sts & 1) {
if (filecount < 1) {
printf("%%SEARCH-W-NOFILES, no files found\n");
} else {
if (findcount < 1) printf("%%SEARCH-I-NOMATCHES, no strings matched\n");
}
} else {
printf("%%SEARCH-F-ERROR Status: %d\n",sts);
}
return sts;
}
/* del: you don't want to know! */
unsigned del(int argc,char *argv[],int qualc,char *qualv[])
{
int sts = 0;
struct NAM nam = cc$rms_nam;
struct FAB fab = cc$rms_fab;
char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
int filecount = 0;
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 = strlen(fab.fab$l_fna);
printf("WARNING! This bit is broken - volume corruption VERY likely!\n");
sts = sys$parse(&fab);
if (sts & 1) {
if (nam.nam$b_ver < 2) {
printf("%%DELETE-F-NOVER, you must specify a version!!\n");
} else {
nam.nam$l_rsa = rsa;
nam.nam$b_rss = NAM$C_MAXRSS;
fab.fab$l_fop = FAB$M_NAM;
while ((sts = sys$search(&fab)) & 1) {
sts = sys$erase(&fab);
if ((sts & 1) == 0) {
printf("%%DELETE-F-DELERR, Delete error: %d\n",sts);
} else {
filecount++;
rsa[nam.nam$b_rsl] = '\0';
printf("%%DELETE-I-DELETED, Deleted %s\n",rsa);
}
}
if (sts == RMS$_NMF) sts = 1;
}
if (sts & 1) {
if (filecount < 1) {
printf("%%DELETE-W-NOFILES, no files deleted\n");
}
} else {
printf("%%DELETE-F-ERROR Status: %d\n",sts);
}
}
return sts;
}
/* show: the show command */
unsigned show(int argc,char *argv[],int qualc,char *qualv[])
{
unsigned sts = 1;
if (keycomp(argv[1],"default")) {
unsigned short curlen;
char curdir[NAM$C_MAXRSS + 1];
struct dsc$descriptor curdsc;
curdsc.dsc$w_length = NAM$C_MAXRSS;
curdsc.dsc$a_pointer = curdir;
if ((sts = sys$setddir(NULL,&curlen,&curdsc)) & 1) {
curdir[curlen] = '\0';
printf(" %s\n",curdir);
} else {
printf("Error %d getting default\n",sts);
}
} else {
if (keycomp(argv[1],"time")) {
char timstr[24];
unsigned short timlen;
struct dsc$descriptor timdsc;
timdsc.dsc$w_length = 23;
timdsc.dsc$a_pointer = timstr;
sys$asctim(&timlen,&timdsc,NULL,0);
timstr[timlen] = '\0';
printf(" %s\n",timstr);
} else {
printf("%%SHOW-W-WHAT '%s'?\n",argv[1]);
}
}
return sts;
}
/* set: the set command */
unsigned set(int argc,char *argv[],int qualc,char *qualv[])
{
unsigned sts = 1;
if (keycomp(argv[1],"default")) {
struct dsc$descriptor defdsc;
defdsc.dsc$a_pointer = argv[2];
defdsc.dsc$w_length = strlen(defdsc.dsc$a_pointer);
if (((sts = sys$setddir(&defdsc,NULL,NULL)) & 1) == 0) {
printf("Error %d setting default to %s\n",sts,argv[2]);
}
} else {
printf("%%SET-W-WHAT '%s'?\n",argv[1]);
}
return sts;
}
#ifndef VMSIO
/* The bits we need when we don't have real VMS routines underneath... */
unsigned dodismount(int argc,char *argv[],int qualc,char *qualv[])
{
struct DEV *dev;
register int sts = device_lookup(strlen(argv[1]),argv[1],0,&dev);
if (sts & 1) {
if (dev->vcb != NULL) {
sts = dismount(dev->vcb);
} else {
sts = SS$_DEVNOTMOUNT;
}
}
if ((sts & 1) == 0) printf("%%DISMOUNT-E-STATUS Error: %d\n",sts);
return sts;
}
char *mouquals[] = {"write",NULL};
unsigned domount(int argc,char *argv[],int qualc,char *qualv[])
{
char *dev = argv[1];
char *lab = argv[2];
int sts = 1,devices = 0;
char *devs[100],*labs[100];
int options = checkquals(mouquals,qualc,qualv);
while (*lab != '\0') {
labs[devices++] = lab;
while (*lab != ',' && *lab != '\0') lab++;
if (*lab != '\0') {
*lab++ = '\0';
} else {
break;
}
}
devices = 0;
while (*dev != '\0') {
devs[devices++] = dev;
while (*dev != ',' && *dev != '\0') dev++;
if (*dev != '\0') {
*dev++ = '\0';
} else {
break;
}
}
if (devices > 0) {
unsigned i;
struct VCB *vcb;
sts = mount(options,devices,devs,labs,&vcb);
if (sts & 1) {
for (i = 0; i < vcb->devices; i++)
if (vcb->vcbdev[i].dev != NULL)
printf("%%MOUNT-I-MOUNTED, Volume %12.12s mounted on %s\n",
vcb->vcbdev[i].home.hm2$t_volname,vcb->vcbdev[i].dev->devnam);
} else {
printf("Mount failed with %d\n",sts);
}
}
return sts;
}
void directshow(void);
void phyio_show(void);
/* statis: print some simple statistics */
unsigned statis(int argc,char *argv[],int qualc,char *qualv[])
{
printf("Statistics:-\n");
directshow();
cacheshow();
phyio_show();
return 1;
}
/* dump: a simple debugging aid */
unsigned dump(int argc,char *argv[],int qualc,char *qualv[])
{
printf("Cache Dump:-\n");
cachedump();
return 1;
}
#endif
/* help: a routine to print a pre-prepared help text... */
unsigned help(int argc,char *argv[],int qualc,char *qualv[])
{
printf("\nODS2 v1.2\n");
printf(" Please send problems/comments to Paulnank@au1.ibm.com\n");
printf(" Commands are:\n");
printf(" copy difference directory exit\n");
printf(" mount show_default show_time search\n");
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;
}
/* informaion about the commands we know... */
struct CMDSET {
char *name;
unsigned (*proc) (int argc,char *argv[],int qualc,char *qualv[]);
unsigned int minlen;
unsigned int minargs;
unsigned int maxargs;
unsigned int maxquals;
} cmdset[] = {
{
"copy",copy,3,3,3,0
},
{
"delete",del,3,2,2,0
},
{
"difference",diff,3,3,3,0
},
{
"directory",dir,3,1,2,6
},
{
"exit",NULL,2,0,0,0
},
{
"help",help,2,1,1,0
},
{
"show",show,2,2,2,0
},
{
"search",search,3,3,3,0
},
{
"set",set,3,2,3,0
},
#ifndef VMSIO
{
"dismount",dodismount,3,2,2,0
},
{
"mount",domount,3,2,3,2
},
{
"statistics",statis,3,1,1,0
},
{
"dump",dump,3,1,1,0
},
#endif
{
"type",typ,3,2,2,0
},
{
NULL,NULL,0,0,0,0
}
};
/* cmdexecute: identify and execute a command */
int cmdexecute(unsigned int argc,char *argv[],unsigned int qualc,char *qualv[])
{
char *ptr = argv[0];
struct CMDSET *cmd = cmdset;
unsigned cmdsiz = strlen(ptr);
while (*ptr != '\0') {
*ptr = tolower(*ptr);
ptr++;
}
while (cmd->name != NULL) {
if (cmdsiz >= cmd->minlen && cmdsiz <= strlen(cmd->name)) {
if (keycomp(argv[0],cmd->name)) {
if (cmd->proc == NULL) {
return 0;
} else {
if (argc < cmd->minargs || argc > cmd->maxargs) {
printf("%%ODS2-E-PARAMS, Incorrect number of command parameters\n");
} else {
if (qualc > cmd->maxquals) {
printf("%%ODS2-E-QUALS, Too many command qualifiers\n");
} else {
(*cmd->proc) (argc,argv,qualc,qualv);
#ifndef VMSIO
cacheflush();
#endif
}
}
return 1;
}
}
}
cmd++;
}
printf("%%ODS2-E-ILLCMD, Illegal or ambiguous command '%s'\n",argv[0]);
return 1;
}
/* cmdsplit: break a command line into its components */
int cmdsplit(char *str)
{
int argc = 0,qualc = 0;
char *argv[32],*qualv[32];
char *sp = str;
int i;
for (i = 0; i < 32; i++) argv[i] = qualv[i] = "";
while (*sp != '\0') {
while (*sp == ' ') sp++;
if (*sp != '\0') {
if (*sp == '/') {
*sp++ = '\0';
qualv[qualc++] = sp;
} else {
argv[argc++] = sp;
}
while (*sp != ' ' && *sp != '/' && *sp != '\0') sp++;
if (*sp == '\0') {
break;
} else {
if (*sp != '/') *sp++ = '\0';
}
}
}
if (argc > 0) return cmdexecute(argc,argv,qualc,qualv);
return 1;
}
/* main: the simple mainline of this puppy... */
int main(int argc,char *argv[])
{
char str[2048];
str[sizeof(str)-1] = 0;
printf(" ODS2 v1.2\n");
while (1) {
printf("$> ");
if (fgets(str, sizeof(str)-1, stdin) == NULL) break;
if (strlen(str)) if ((cmdsplit(str) & 1) == 0) break;
}
return 1;
}

895
extracters/ods2/ods2.c.bak Normal file
View File

@@ -0,0 +1,895 @@
/* ODS2.C v1.2 Mainline ODS2 program */
/*
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.
The modules in ODS2 are:-
ACCESS.C Routines for accessing ODS2 disks
CACHE.C Routines for managing memory cache
DEVICE.C Routines to maintain device information
DIRECT.C Routines for handling directories
ODS2.C The mainline program
PHYVMS.C Routine to perform physical I/O
RMS.C Routines to handle RMS structures
VMSTIME.C Routines to handle VMS times
On non-VMS platforms PHYVMS.C should be replaced as follows:-
OS/2 PHYOS2.C
Windows 95/NT PHYNT.C
For example under OS/2 the program is compiled using the GCC
compiler with the single command:-
gcc -fdollars-in-identifiers ods2.c,rms.c,direct.c,
access.c,device.c,cache.c,phyos2.c,vmstime.c
*/
/* This version will compile and run using normal VMS I/O by
defining VMSIO
*/
/* This is the top level set of routines. It is fairly
simple minded asking the user for a command, doing some
primitive command parsing, and then calling a set of routines
to perform whatever function is required (for example COPY).
Some routines are implemented in different ways to test the
underlying routines - for example TYPE is implemented without
a NAM block meaning that it cannot support wildcards...
(sorry! - could be easily fixed though!)
*/
#define DEBUGx on
#define VMSIOx on
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "descrip.h"
#include "ssdef.h"
#ifdef VMSIO
#include <starlet.h>
#include <rms.h>
unsigned sys$setddir();
#else
#include "rms.h"
#include "access.h"
#endif
#define PRINT_ATTR (FAB$M_CR | FAB$M_PRN | FAB$M_FTN)
/* keycomp: routine to compare parameter to a keyword - case insensitive! */
int keycomp(char *param,char *keywrd)
{
while (*param != '\0') {
if (tolower(*param++) != *keywrd++) return 0;
}
return 1;
}
/* checkquals: routine to find a qualifer in a list of possible values */
int checkquals(char *qualset[],int qualc,char *qualv[])
{
int result = 0;
while (qualc-- > 0) {
int i = 0;
while (qualset[i] != NULL) {
if (keycomp(qualv[qualc],qualset[i])) {
result |= 1 << i;
i = -1;
break;
}
i++;
}
if (i >= 0) printf("%%ODS2-W-ILLQUAL, Unknown qualifer '%s' ignored\n",qualv[qualc]);
}
return result;
}
/* dir: a directory routine */
char *dirquals[] = {"date","file","size",NULL};
unsigned dir(int argc,char *argv[],int qualc,char *qualv[])
{
char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
int sts,options;
int filecount = 0;
struct NAM nam = cc$rms_nam;
struct FAB fab = cc$rms_fab;
struct XABDAT dat = cc$rms_xabdat;
struct XABFHC fhc = cc$rms_xabfhc;
nam.nam$l_esa = res;
nam.nam$b_ess = NAM$C_MAXRSS;
fab.fab$l_nam = &nam;
fab.fab$l_xab = &dat;
dat.xab$l_nxt = &fhc;
fab.fab$l_fna = argv[1];
fab.fab$b_fns = strlen(fab.fab$l_fna);
fab.fab$l_dna = "*.*;*";
fab.fab$b_dns = strlen(fab.fab$l_dna);
options = checkquals(dirquals,qualc,qualv);
sts = sys$parse(&fab);
if (sts & 1) {
char dir[NAM$C_MAXRSS + 1];
int namelen;
int dirlen = 0;
int dirfiles = 0,dircount = 0;
int dirblocks = 0,totblocks = 0;
int printcol = 0;
#ifdef DEBUG
res[nam.nam$b_esl] = '\0';
printf("Parse: %s\n",res);
#endif
nam.nam$l_rsa = rsa;
nam.nam$b_rss = NAM$C_MAXRSS;
fab.fab$l_fop = FAB$M_NAM;
while ((sts = sys$search(&fab)) & 1) {
if (dirlen != nam.nam$b_dev + nam.nam$b_dir ||
memcmp(rsa,dir,nam.nam$b_dev + nam.nam$b_dir) != 0) {
if (dirfiles > 0) {
if (printcol > 0) printf("\n");
printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s"));
if (options & 4) {
printf(", %d block%s.\n",dirblocks,(dirblocks == 1 ? "" : "s"));
} else {
fputs(".\n",stdout);
}
}
dirlen = nam.nam$b_dev + nam.nam$b_dir;
memcpy(dir,rsa,dirlen);
dir[dirlen] = '\0';
printf("\nDirectory %s\n\n",dir);
filecount += dirfiles;
totblocks += dirblocks;
dircount++;
dirfiles = 0;
dirblocks = 0;
printcol = 0;
}
rsa[nam.nam$b_rsl] = '\0';
namelen = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
if (options == 0) {
if (printcol > 0) {
int newcol = (printcol + 20) / 20 * 20;
if (newcol + namelen >= 80) {
fputs("\n",stdout);
printcol = 0;
} else {
printf("%*s",newcol - printcol," ");
printcol = newcol;
}
}
fputs(rsa + dirlen,stdout);
printcol += namelen;
} else {
if (namelen > 18) {
printf("%s\n ",rsa + dirlen);
} else {
printf("%-19s",rsa + dirlen);
}
sts = sys$open(&fab);
if ((sts & 1) == 0) {
printf("Open error: %d\n",sts);
} else {
sts = sys$close(&fab);
if (options & 2) {
char fileid[100];
sprintf(fileid,"(%d,%d,%d)",
(nam.nam$b_fid_nmx << 16) | nam.nam$w_fid_num,
nam.nam$w_fid_seq,nam.nam$b_fid_rvn);
printf(" %-22s",fileid);
}
if (options & 4) {
unsigned filesize = fhc.xab$l_ebk;
if (fhc.xab$w_ffb == 0) filesize--;
printf("%9d",filesize);
dirblocks += filesize;
}
if (options & 1) {
char tim[24];
struct dsc$descriptor timdsc;
timdsc.dsc$w_length = 23;
timdsc.dsc$a_pointer = tim;
sts = sys$asctim(0,&timdsc,&dat.xab$q_cdt,0);
if ((sts & 1) == 0) printf("Asctim error: %d\n",sts);
tim[23] = '\0';
printf(" %s",tim);
}
printf("\n");
}
}
dirfiles++;
}
if (sts == RMS$_NMF) sts = 1;
if (printcol > 0) printf("\n");
if (dirfiles > 0) {
printf("\nTotal of %d file%s",dirfiles,(dirfiles == 1 ? "" : "s"));
if (options & 4) {
printf(", %d block%s.\n",dirblocks,(dirblocks == 1 ? "" : "s"));
} else {
fputs(".\n",stdout);
}
filecount += dirfiles;
totblocks += dirblocks;
if (dircount > 1) {
printf("\nGrand total of %d director%s, %d file%s",
dircount,(dircount == 1 ? "y" : "ies"),
filecount,(filecount == 1 ? "" : "s"));
if (options & 4) {
printf(", %d block%s.\n",totblocks,(totblocks == 1 ? "" : "s"));
} else {
fputs(".\n",stdout);
}
}
}
}
if (sts & 1) {
if (filecount < 1) printf("%%DIRECT-W-NOFILES, no files found\n");
} else {
printf("%%DIR-E-ERROR Status: %d\n",sts);
}
return sts;
}
/* copy: a file copy routine */
#define MAXREC 32767
unsigned copy(int argc,char *argv[],int qualc,char *qualv[])
{
int sts;
struct NAM nam = cc$rms_nam;
struct FAB fab = cc$rms_fab;
char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
int filecount = 0;
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 = strlen(fab.fab$l_fna);
sts = sys$parse(&fab);
if (sts & 1) {
nam.nam$l_rsa = rsa;
nam.nam$b_rss = NAM$C_MAXRSS;
fab.fab$l_fop = FAB$M_NAM;
while ((sts = sys$search(&fab)) & 1) {
sts = sys$open(&fab);
if ((sts & 1) == 0) {
printf("%%COPY-F-OPENFAIL, Open error: %d\n",sts);
perror("-COPY-F-ERR ");
} else {
struct RAB rab = cc$rms_rab;
rab.rab$l_fab = &fab;
if ((sts = sys$connect(&rab)) & 1) {
FILE *tof;
char name[NAM$C_MAXRSS + 1];
unsigned records = 0;
{
char *out = name,*inp = argv[2];
int dot = 0;
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 {
unsigned length = nam.nam$b_name;
if (*inp == '\0') length += nam.nam$b_type;
memcpy(out,nam.nam$l_name,length);
out += length;
}
} else {
if (*inp == '.') {
dot = 1;
} else {
if (strchr(":]\\/",*inp)) dot = 0;
}
*out++ = *inp++;
}
}
*out++ = '\0';
}
tof = fopen(name,"w");
if (tof == NULL) {
printf("%%COPY-F-OPENOUT, Could not open %s\n",name);
perror("-COPY-F-ERR ");
} else {
char rec[MAXREC + 2];
filecount++;
rab.rab$l_ubf = rec;
rab.rab$w_usz = MAXREC;
while ((sts = sys$get(&rab)) & 1) {
unsigned rsz = rab.rab$w_rsz;
if (fab.fab$b_rat & PRINT_ATTR) rec[rsz++] = '\n';
if (fwrite(rec,rsz,1,tof) == 1) {
records++;
} else {
printf("%%COPY-F- fwrite error!!\n");
perror("-COPY-F-ERR ");
break;
}
}
if (fclose(tof)) {
printf("%%COPY-F- fclose error!!\n");
perror("-COPY-F-ERR ");
}
}
sys$disconnect(&rab);
if (sts == RMS$_EOF) {
rsa[nam.nam$b_rsl] = '\0';
printf("%%COPY-S-COPIED, %s copied to %s (%d record%s)\n",
rsa,name,records,(records == 1 ? "" : "s"));
sts = 1;
}
}
sys$close(&fab);
}
}
if (sts == RMS$_NMF) sts = 1;
}
if (sts & 1) {
if (filecount > 0) printf("%%COPY-S-NEWFILES, %d file%s created\n",
filecount,(filecount == 1 ? "" : "s"));
} else {
printf("%%COPY-F-ERROR Status: %d\n",sts);
}
return sts;
}
/* diff: a simple file difference routine */
unsigned diff(int argc,char *argv[],int qualc,char *qualv[])
{
int sts;
struct FAB fab = cc$rms_fab;
FILE *tof;
int records = 0;
fab.fab$l_fna = argv[1];
fab.fab$b_fns = strlen(fab.fab$l_fna);
tof = fopen(argv[2],"r");
if (tof == NULL) {
printf("Could not open file %s\n",argv[1]);
sts = 0;
} else {
if ((sts = sys$open(&fab)) & 1) {
struct RAB rab = cc$rms_rab;
rab.rab$l_fab = &fab;
if ((sts = sys$connect(&rab)) & 1) {
char rec[MAXREC + 2],cpy[MAXREC + 1];
rab.rab$l_ubf = rec;
rab.rab$w_usz = MAXREC;
while ((sts = sys$get(&rab)) & 1) {
strcpy(rec + rab.rab$w_rsz,"\n");
fgets(cpy,MAXREC,tof);
if (strcmp(rec,cpy) != 0) {
printf("%%DIFF-F-DIFFERENT Files are different!\n");
sts = 4;
break;
} else {
records++;
}
}
sys$disconnect(&rab);
}
sys$close(&fab);
}
fclose(tof);
if (sts == RMS$_EOF) sts = 1;
}
if (sts & 1) {
printf("%%DIFF-I-Compared %d records\n",records);
} else {
printf("%%DIFF-F-Error %d in difference\n",sts);
}
return sts;
}
/* typ: a file TYPE routine */
unsigned typ(int argc,char *argv[],int qualc,char *qualv[])
{
int sts;
int records = 0;
struct FAB fab = cc$rms_fab;
fab.fab$l_fna = argv[1];
fab.fab$b_fns = strlen(fab.fab$l_fna);
if ((sts = sys$open(&fab)) & 1) {
struct RAB rab = cc$rms_rab;
rab.rab$l_fab = &fab;
if ((sts = sys$connect(&rab)) & 1) {
char rec[MAXREC + 2];
rab.rab$l_ubf = rec;
rab.rab$w_usz = MAXREC;
while ((sts = sys$get(&rab)) & 1) {
unsigned rsz = rab.rab$w_rsz;
if (fab.fab$b_rat & PRINT_ATTR) rec[rsz++] = '\n';
rec[rsz++] = '\0';
fputs(rec,stdout);
records++;
}
sys$disconnect(&rab);
}
sys$close(&fab);
if (sts == RMS$_EOF) sts = 1;
}
if ((sts & 1) == 0) {
printf("%%TYPE-F-ERROR Status: %d\n",sts);
}
return sts;
}
/* search: a simple file search routine */
unsigned search(int argc,char *argv[],int qualc,char *qualv[])
{
int sts = 0;
int filecount = 0;
int findcount = 0;
char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
struct NAM nam = cc$rms_nam;
struct FAB fab = cc$rms_fab;
register char *searstr = argv[2];
register char firstch = tolower(*searstr++);
register char *searend = searstr + strlen(searstr);
{
char *str = searstr;
while (str < searend) {
*str = tolower(*str);
str++;
}
}
nam = cc$rms_nam;
fab = cc$rms_fab;
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 = strlen(fab.fab$l_fna);
fab.fab$l_dna = "";
fab.fab$b_dns = strlen(fab.fab$l_dna);
sts = sys$parse(&fab);
if (sts & 1) {
nam.nam$l_rsa = rsa;
nam.nam$b_rss = NAM$C_MAXRSS;
fab.fab$l_fop = FAB$M_NAM;
while ((sts = sys$search(&fab)) & 1) {
sts = sys$open(&fab);
if ((sts & 1) == 0) {
printf("%%SEARCH-F-OPENFAIL, Open error: %d\n",sts);
} else {
struct RAB rab = cc$rms_rab;
rab.rab$l_fab = &fab;
if ((sts = sys$connect(&rab)) & 1) {
int printname = 1;
char rec[MAXREC + 2];
filecount++;
rab.rab$l_ubf = rec;
rab.rab$w_usz = MAXREC;
while ((sts = sys$get(&rab)) & 1) {
register char *strng = rec;
register char *strngend = strng + (rab.rab$w_rsz - (searend - searstr));
while (strng < strngend) {
register char ch = *strng++;
if (ch == firstch || (ch >= 'A' && ch <= 'Z' && ch + 32 == firstch)) {
register char *str = strng;
register char *cmp = searstr;
while (cmp < searend) {
register char ch2 = *str++;
ch = *cmp;
if (ch2 != ch && (ch2 < 'A' || ch2 > 'Z' || ch2 + 32 != ch)) break;
cmp++;
}
if (cmp >= searend) {
findcount++;
rec[rab.rab$w_rsz] = '\0';
if (printname) {
rsa[nam.nam$b_rsl] = '\0';
printf("\n******************************\n%s\n\n",rsa);
printname = 0;
}
fputs(rec,stdout);
if (fab.fab$b_rat & PRINT_ATTR) fputc('\n',stdout);
break;
}
}
}
}
sys$disconnect(&rab);
}
if (sts == SS$_NOTINSTALL) {
printf("%%SEARCH-W-NOIMPLEM, file operation not implemented\n");
sts = 1;
}
sys$close(&fab);
}
}
if (sts == RMS$_NMF || sts == RMS$_FNF) sts = 1;
}
if (sts & 1) {
if (filecount < 1) {
printf("%%SEARCH-W-NOFILES, no files found\n");
} else {
if (findcount < 1) printf("%%SEARCH-I-NOMATCHES, no strings matched\n");
}
} else {
printf("%%SEARCH-F-ERROR Status: %d\n",sts);
}
return sts;
}
/* del: you don't want to know! */
unsigned del(int argc,char *argv[],int qualc,char *qualv[])
{
int sts = 0;
struct NAM nam = cc$rms_nam;
struct FAB fab = cc$rms_fab;
char res[NAM$C_MAXRSS + 1],rsa[NAM$C_MAXRSS + 1];
int filecount = 0;
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 = strlen(fab.fab$l_fna);
printf("WARNING! This bit is broken - volume corruption VERY likely!\n");
sts = sys$parse(&fab);
if (sts & 1) {
if (nam.nam$b_ver < 2) {
printf("%%DELETE-F-NOVER, you must specify a version!!\n");
} else {
nam.nam$l_rsa = rsa;
nam.nam$b_rss = NAM$C_MAXRSS;
fab.fab$l_fop = FAB$M_NAM;
while ((sts = sys$search(&fab)) & 1) {
sts = sys$erase(&fab);
if ((sts & 1) == 0) {
printf("%%DELETE-F-DELERR, Delete error: %d\n",sts);
} else {
filecount++;
rsa[nam.nam$b_rsl] = '\0';
printf("%%DELETE-I-DELETED, Deleted %s\n",rsa);
}
}
if (sts == RMS$_NMF) sts = 1;
}
if (sts & 1) {
if (filecount < 1) {
printf("%%DELETE-W-NOFILES, no files deleted\n");
}
} else {
printf("%%DELETE-F-ERROR Status: %d\n",sts);
}
}
return sts;
}
/* show: the show command */
unsigned show(int argc,char *argv[],int qualc,char *qualv[])
{
unsigned sts = 1;
if (keycomp(argv[1],"default")) {
unsigned short curlen;
char curdir[NAM$C_MAXRSS + 1];
struct dsc$descriptor curdsc;
curdsc.dsc$w_length = NAM$C_MAXRSS;
curdsc.dsc$a_pointer = curdir;
if ((sts = sys$setddir(NULL,&curlen,&curdsc)) & 1) {
curdir[curlen] = '\0';
printf(" %s\n",curdir);
} else {
printf("Error %d getting default\n",sts);
}
} else {
if (keycomp(argv[1],"time")) {
char timstr[24];
unsigned short timlen;
struct dsc$descriptor timdsc;
timdsc.dsc$w_length = 23;
timdsc.dsc$a_pointer = timstr;
sys$asctim(&timlen,&timdsc,NULL,0);
timstr[timlen] = '\0';
printf(" %s\n",timstr);
} else {
printf("%%SHOW-W-WHAT '%s'?\n",argv[1]);
}
}
return sts;
}
/* set: the set command */
unsigned set(int argc,char *argv[],int qualc,char *qualv[])
{
unsigned sts = 1;
if (keycomp(argv[1],"default")) {
struct dsc$descriptor defdsc;
defdsc.dsc$a_pointer = argv[2];
defdsc.dsc$w_length = strlen(defdsc.dsc$a_pointer);
if (((sts = sys$setddir(&defdsc,NULL,NULL)) & 1) == 0) {
printf("Error %d setting default to %s\n",sts,argv[2]);
}
} else {
printf("%%SET-W-WHAT '%s'?\n",argv[1]);
}
return sts;
}
#ifndef VMSIO
/* The bits we need when we don't have real VMS routines underneath... */
unsigned dodismount(int argc,char *argv[],int qualc,char *qualv[])
{
struct DEV *dev;
register int sts = device_lookup(strlen(argv[1]),argv[1],0,&dev);
if (sts & 1) {
if (dev->vcb != NULL) {
sts = dismount(dev->vcb);
} else {
sts = SS$_DEVNOTMOUNT;
}
}
if ((sts & 1) == 0) printf("%%DISMOUNT-E-STATUS Error: %d\n",sts);
return sts;
}
char *mouquals[] = {"write",NULL};
unsigned domount(int argc,char *argv[],int qualc,char *qualv[])
{
char *dev = argv[1];
char *lab = argv[2];
int sts = 1,devices = 0;
char *devs[100],*labs[100];
int options = checkquals(mouquals,qualc,qualv);
while (*lab != '\0') {
labs[devices++] = lab;
while (*lab != ',' && *lab != '\0') lab++;
if (*lab != '\0') {
*lab++ = '\0';
} else {
break;
}
}
devices = 0;
while (*dev != '\0') {
devs[devices++] = dev;
while (*dev != ',' && *dev != '\0') dev++;
if (*dev != '\0') {
*dev++ = '\0';
} else {
break;
}
}
if (devices > 0) {
unsigned i;
struct VCB *vcb;
sts = mount(options,devices,devs,labs,&vcb);
if (sts & 1) {
for (i = 0; i < vcb->devices; i++)
if (vcb->vcbdev[i].dev != NULL)
printf("%%MOUNT-I-MOUNTED, Volume %12.12s mounted on %s\n",
vcb->vcbdev[i].home.hm2$t_volname,vcb->vcbdev[i].dev->devnam);
} else {
printf("Mount failed with %d\n",sts);
}
}
return sts;
}
void directshow(void);
void phyio_show(void);
/* statis: print some simple statistics */
unsigned statis(int argc,char *argv[],int qualc,char *qualv[])
{
printf("Statistics:-\n");
directshow();
cacheshow();
phyio_show();
return 1;
}
/* dump: a simple debugging aid */
unsigned dump(int argc,char *argv[],int qualc,char *qualv[])
{
printf("Cache Dump:-\n");
cachedump();
return 1;
}
#endif
/* help: a routine to print a pre-prepared help text... */
unsigned help(int argc,char *argv[],int qualc,char *qualv[])
{
printf("\nODS2 v1.2\n");
printf(" Please send problems/comments to Paulnank@au1.ibm.com\n");
printf(" Commands are:\n");
printf(" copy difference directory exit\n");
printf(" mount show_default show_time search\n");
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;
}
/* informaion about the commands we know... */
struct CMDSET {
char *name;
unsigned (*proc) (int argc,char *argv[],int qualc,char *qualv[]);
int minlen;
int minargs;
int maxargs;
int maxquals;
} cmdset[] = {
{
"copy",copy,3,3,3,0
},
{
"delete",del,3,2,2,0
},
{
"difference",diff,3,3,3,0
},
{
"directory",dir,3,1,2,6
},
{
"exit",NULL,2,0,0,0
},
{
"help",help,2,1,1,0
},
{
"show",show,2,2,2,0
},
{
"search",search,3,3,3,0
},
{
"set",set,3,2,3,0
},
#ifndef VMSIO
{
"dismount",dodismount,3,2,2,0
},
{
"mount",domount,3,2,3,2
},
{
"statistics",statis,3,1,1,0
},
{
"dump",dump,3,1,1,0
},
#endif
{
"type",typ,3,2,2,0
},
{
NULL,NULL,0,0,0,0
}
};
/* cmdexecute: identify and execute a command */
int cmdexecute(int argc,char *argv[],int qualc,char *qualv[])
{
char *ptr = argv[0];
struct CMDSET *cmd = cmdset;
unsigned cmdsiz = strlen(ptr);
while (*ptr != '\0') {
*ptr = tolower(*ptr);
ptr++;
}
while (cmd->name != NULL) {
if (cmdsiz >= cmd->minlen && cmdsiz <= strlen(cmd->name)) {
if (keycomp(argv[0],cmd->name)) {
if (cmd->proc == NULL) {
return 0;
} else {
if (argc < cmd->minargs || argc > cmd->maxargs) {
printf("%%ODS2-E-PARAMS, Incorrect number of command parameters\n");
} else {
if (qualc > cmd->maxquals) {
printf("%%ODS2-E-QUALS, Too many command qualifiers\n");
} else {
(*cmd->proc) (argc,argv,qualc,qualv);
#ifndef VMSIO
cacheflush();
#endif
}
}
return 1;
}
}
}
cmd++;
}
printf("%%ODS2-E-ILLCMD, Illegal or ambiguous command '%s'\n",argv[0]);
return 1;
}
/* cmdsplit: break a command line into its components */
int cmdsplit(char *str)
{
int argc = 0,qualc = 0;
char *argv[32],*qualv[32];
char *sp = str;
int i;
for (i = 0; i < 32; i++) argv[i] = qualv[i] = "";
while (*sp != '\0') {
while (*sp == ' ') sp++;
if (*sp != '\0') {
if (*sp == '/') {
*sp++ = '\0';
qualv[qualc++] = sp;
} else {
argv[argc++] = sp;
}
while (*sp != ' ' && *sp != '/' && *sp != '\0') sp++;
if (*sp == '\0') {
break;
} else {
if (*sp != '/') *sp++ = '\0';
}
}
}
if (argc > 0) return cmdexecute(argc,argv,qualc,qualv);
return 1;
}
/* main: the simple mainline of this puppy... */
int main(int argc,char *argv[])
{
char str[2048];
printf(" ODS2 v1.2\n");
while (1) {
printf("$> ");
if (gets(str) == NULL) break;
if (strlen(str)) if ((cmdsplit(str) & 1) == 0) break;
}
return 1;
}

44
extracters/ods2/phyio.h Normal file
View File

@@ -0,0 +1,44 @@
/* Phy.h v1.2 Definition of Physical I/O routines */
/*
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.
*/
/* To set up physical I/O for a new system a group of phyio
routines need to be set up. They are:-
phyio_show() which doesn't need to do anything - but
it would generally print some statistics
about the other phyio calls.
phyio_init() to prepare a device for use by future
read/write calls. The device name would usually
map to a local device - for example rra: to /dev/rra
on a Unix system. The call needs to return a handle
(channel, file handle, reference number...) for
future reference, and optionally some device
information.
phyio_read() will return a specified number of bytes into a
buffer from the start of a 512 byte block on the
device referred to by the handle.
phyio_write() will write a number of bytes out to a 512 byte block
address on a device.
*/
#define PHYIO_READONLY 1
struct phyio_info {
unsigned status;
unsigned sectors;
unsigned sectorsize;
};
void phyio_show(void);
unsigned phyio_init(int devlen,char *devnam,unsigned *handle,struct phyio_info *info);
unsigned phyio_read(unsigned handle,unsigned block,unsigned length,char *buffer);
unsigned phyio_write(unsigned handle,unsigned block,unsigned length,char *buffer);

517
extracters/ods2/phynt.c Normal file
View File

@@ -0,0 +1,517 @@
/* PHYNT.C v1.2 Physical I/O module for Windows NT */
/* W95 code now included with code to automatically determine
if we are running under NT...
W98 seems to have a performance problem where the
INT25 call are VERY slow!!! */
/* This version built and tested under Visual C++. To support
CD drives this version requires ASPI run-time support. For
SCSI drives probably any old ASPI library will do. But for
ATAPI drives on NT there are 'ASPI libraries and there are
ASPI libraries'. I have had success with an older version of
Adaptec's APSI (version 2,4,0,0) and with Symbios Logic
libraries. But I have NOT been able to make the latest
Adaptec routines work on NT!
Note: Windows 95 comes with APSI by default! */
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winioctl.h>
#include <string.h>
#include <ctype.h>
#include <memory.h>
#include "phyio.h"
#include "ssdef.h"
unsigned init_count = 0; /* Some counters so we can report */
unsigned read_count = 0; /* How often we get called */
unsigned write_count = 0;
void phyio_show(void)
{
printf("PHYIO_SHOW Initializations: %d Reads: %d Writes: %d\n",
init_count,read_count,write_count);
}
unsigned phyio_write(unsigned handle,unsigned block,unsigned length,char *buffer)
{
write_count++;
return SS$_WRITLCK; /* Not implemented yet!! */
}
/* This routine figures out whether this is an NT system or not... */
unsigned is_NT = 2;
OSVERSIONINFO sysver;
void getsysversion()
{
memset(&sysver,0,sizeof(OSVERSIONINFO));
sysver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&sysver);
if (sysver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
is_NT = 1;
} else {
is_NT = 0;
}
}
/*
To read from CD APSI run-time support is required (wnaspi32.dll).
NT does not come with APSI support so you need to install it first.
(ASPI is also required for things like Digital Audio Extraction
and was origionally loaded on my machine to make MP3 audio files.)
One downside is that ASPI on NT does not have a way to match SCSI
adapters and units to a system device. So this program works by
finding the first CD like unit on the system and using it - that
may NOT be what you want if you have several CD drives! And finally
there are CD drives and there are CD drives. From what I can tell
many simply won't work with this (or other!) code. Naturally if
you find a better way please let me know... Paulnank@au1.ibm.com
*/
#if defined (USE_WNASPI)
#include "wnaspi32.h"
unsigned cd_initialized = 0; /* Flag for CD read to go... */
unsigned cd_adaptor,cd_target; /* Adaptor & SCSI #'s */
HANDLE ASPICompletion; /* Windows event for ASPI wait */
/* Get ASPI ready and locate the first CD drive... */
unsigned cd_initialize()
{
if (cd_initialized) {
printf("Can only support one (first) ASPI device\n");
return 8;
} else {
DWORD ASPIStatus;
ASPIStatus = GetASPI32SupportInfo();
if (HIBYTE(LOWORD(ASPIStatus)) == SS_COMP) {
BYTE NumAdapters;
SRB_GDEVBlock Ssrb;
Ssrb.SRB_Cmd = SC_GET_DEV_TYPE;
Ssrb.SRB_HaId = 0;
Ssrb.SRB_Flags = SRB_EVENT_NOTIFY;
Ssrb.SRB_Hdr_Rsvd = 0;
Ssrb.SRB_Target = 0;
Ssrb.SRB_Lun = 0;
NumAdapters = LOWORD(LOBYTE(ASPIStatus));
for (cd_adaptor = 0; cd_adaptor < NumAdapters; cd_adaptor++) {
for (cd_target = 0; cd_target <= 7; cd_target++) {
Ssrb.SRB_HaId = cd_adaptor;
Ssrb.SRB_Target = cd_target;
ASPIStatus = SendASPI32Command(&Ssrb);
if (ASPIStatus == SS_COMP && Ssrb.SRB_DeviceType == 5) break;
}
if (cd_target <= 7) break;
}
if (cd_adaptor < NumAdapters) {
if ((ASPICompletion = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL) return 8;
cd_initialized = 1;
return 1;
} else {
printf("Could not find ASPI CD device\n");
return 8;
}
} else {
printf("Could not initialize ASPI (%x)\n",ASPIStatus);
return 8;
}
}
}
/* Read a sector from CD using ASPI... */
unsigned cd_read(unsigned sector,char *buffer)
{
DWORD ASPIEventStatus;
SRB_ExecSCSICmd Esrb;
Esrb.SRB_Cmd = SC_EXEC_SCSI_CMD;
Esrb.SRB_HaId = cd_adaptor;
Esrb.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
Esrb.SRB_Hdr_Rsvd = 0;
Esrb.SRB_Target = cd_target;
Esrb.SRB_Lun = 0;
Esrb.SRB_BufLen = 2352;
Esrb.SRB_BufPointer = buffer;
Esrb.SRB_SenseLen = 0;
Esrb.SRB_CDBLen = 10;
Esrb.SRB_PostProc = ASPICompletion;
Esrb.CDBByte[0] = 0x28; /* Build SCSI read command packet... */
Esrb.CDBByte[1] = 0;
Esrb.CDBByte[2] = (sector >> 24);
Esrb.CDBByte[3] = (sector >> 16) & 0xff;
Esrb.CDBByte[4] = (sector >> 8) & 0xff;
Esrb.CDBByte[5] = sector & 0xff;
Esrb.CDBByte[6] = 0;
Esrb.CDBByte[7] = 0;
Esrb.CDBByte[8] = 1;
Esrb.CDBByte[9] = 0;
Esrb.CDBByte[10] = 0;
SendASPI32Command(&Esrb); /* Perform the read... */
while (Esrb.SRB_Status == SS_PENDING)
ASPIEventStatus = WaitForSingleObject(ASPICompletion,INFINITE);
/* if (ASPIEventStatus == WAIT_OBJECT_0) */ResetEvent(ASPICompletion);
if (Esrb.SRB_Status != SS_COMP) return SS$_PARITY;
return 1;
}
#else /* !defined(USE_WNASPI) */
unsigned cd_initialize()
{
return 1;
}
unsigned cd_read(unsigned sector,char *buffer)
{
return 0;
}
#endif /* defined(USE_WNASPI) */
/* Some NT definitions... */
/* #include "Ntddcdrm.h" */
#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS)
/* NT Get disk or CD geometry... */
BOOL
GetDiskGeometry(
HANDLE hDisk,
DISK_GEOMETRY *dGeometry
)
{
DWORD ReturnedByteCount;
BOOL results = DeviceIoControl(
hDisk,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
dGeometry,
sizeof(*dGeometry),
&ReturnedByteCount,
NULL
);
if (!results) results = DeviceIoControl(
hDisk,
IOCTL_CDROM_GET_DRIVE_GEOMETRY,
NULL,
0,
dGeometry,
sizeof(*dGeometry),
&ReturnedByteCount,
NULL
);
return results;
}
/* NT drive lock - we don't want any interference... */
BOOL
LockVolume(
HANDLE hDisk
)
{
DWORD ReturnedByteCount;
return DeviceIoControl(
hDisk,
FSCTL_LOCK_VOLUME,
NULL,
0,
NULL,
0,
&ReturnedByteCount,
NULL
);
}
/* Windows 95 I/O definitions... */
#define VWIN32_DIOC_DOS_IOCTL 1
#define VWIN32_DIOC_DOS_INT25 2
#define VWIN32_DIOC_DOS_INT26 3
#pragma pack(1)
typedef struct _DIOC_REGISTERS {
DWORD reg_EBX;
DWORD reg_EDX;
DWORD reg_ECX;
DWORD reg_EAX;
DWORD reg_EDI;
DWORD reg_ESI;
DWORD reg_Flags;
} DIOC_REGISTERS;
typedef struct _DPB {
unsigned int dpb_sector;
unsigned short dpb_count;
char *dpb_buffer;
} DPB;
typedef struct _DEVICEPARAM {
char junk1[7];
unsigned short sec_size;
char junk2[23];
} DEVICEPARAM;
#pragma pack()
/* Each device we talk to has a channel entry so that we can
remember its details... */
#define CHAN_MAX 32
unsigned chan_count = 0;
struct CHANTAB {
HANDLE handle; /* File handle for device */
char *IoBuffer; /* Pointer to a buffer for the device */
unsigned sectorsize; /* Device sector size */
unsigned last_sector; /* Last sector no read (still in buffer) */
short device_type; /* Flag for 'normal' or ASPI I/O */
short device_name; /* Drive letter (A, B, C, ...) */
} chantab[CHAN_MAX];
/* Initialize device by opening it, locking it and getting it ready.. */
unsigned phyio_init(int devlen,char *devnam,unsigned *chanptr,struct phyio_info *info)
{
unsigned sts = 1;
unsigned chan = chan_count;
if (is_NT > 1) getsysversion();
if (chan < CHAN_MAX - 1 && devlen == 2 &&
toupper(*devnam) >= 'A' && *(devnam + 1) == ':') {
HANDLE hDrive;
chantab[chan].device_name = toupper(*devnam);
chantab[chan].device_type = 0;
/* NT stuff */
if (is_NT) {
char ntname[32];
DISK_GEOMETRY Geometry;
sprintf(ntname,"\\\\.\\%s",devnam);
chantab[chan].handle = hDrive = CreateFileA(
ntname,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
NULL
);
if (hDrive == INVALID_HANDLE_VALUE) {
printf("Open %s failed %d\n",devnam,GetLastError());
return SS$_NOSUCHDEV;
}
if (LockVolume(hDrive) == FALSE) {
printf("LockVolume %s failed %d\n",devnam,GetLastError());
return 72;
}
if (!GetDiskGeometry(hDrive,&Geometry)) {
printf("GetDiskGeometry %s failed %d\n",devnam,GetLastError());
return 80;
}
/* If this is a 2048 byte sector device past C treat it as a CD... */
chantab[chan].device_type = 0;
if (Geometry.BytesPerSector == 2048 && toupper(*devnam) > 'C') {
sts = cd_initialize();
if ((sts & 1) == 0) return sts;
chantab[chan].device_type = 1;
}
chantab[chan].sectorsize = Geometry.BytesPerSector;
info->sectors = (unsigned)(Geometry.Cylinders.QuadPart * Geometry.TracksPerCylinder *
Geometry.SectorsPerTrack);
} else {
#if defined(USE_WIN95)
/* W95 stuff */
if (chantab[chan].device_name > 'C') { /* Assume above C are CDs.. */
sts = cd_initialize();
if ((sts & 1) == 0) return sts;
chantab[chan].device_type = 1;
chantab[chan].sectorsize = 2048;
} else {
DIOC_REGISTERS reg;
DEVICEPARAM deviceparam;
BOOL fResult;
DWORD cb;
chantab[chan].handle = hDrive = CreateFileA(
"\\\\.\\vwin32",
0,0,
NULL,
0,
FILE_FLAG_DELETE_ON_CLOSE,
NULL);
if (hDrive == INVALID_HANDLE_VALUE) {
printf("Open %s failed %d\n",devnam,GetLastError());
return SS$_NOSUCHDEV;
}
reg.reg_EAX = 0x440d;
reg.reg_EBX = chantab[chan].device_name - 'A' + 1;
reg.reg_ECX = 0x084a; /* Lock volume */
reg.reg_EDX = 0;
reg.reg_Flags = 0x0000; /* Permission */
fResult = DeviceIoControl(hDrive,
VWIN32_DIOC_DOS_IOCTL,
&reg,sizeof(reg),
&reg,sizeof(reg),
&cb,0);
if (!fResult || (reg.reg_Flags & 0x0001)) {
printf("Volume lock failed (%d)\n",GetLastError());
return SS$_DEVNOTALLOC;
}
reg.reg_EAX = 0x440d;
reg.reg_EBX = chantab[chan].device_name - 'A' + 1;
reg.reg_ECX = 0x0860; /* Get device parameters */
reg.reg_EDX = (DWORD) & deviceparam;
reg.reg_Flags = 0x0001; /* set carry flag */
fResult = DeviceIoControl(hDrive,
VWIN32_DIOC_DOS_IOCTL,
&reg,sizeof(reg),
&reg,sizeof(reg),
&cb,0);
if (!fResult || (reg.reg_Flags & 0x0001)) {
printf("Volume get parameters failed (%d)\n",GetLastError());
return 8;
}
chantab[chan].sectorsize = deviceparam.sec_size;
}
info->sectors = 0;
#endif /* defined(USE_WIN95) */
}
chantab[chan].IoBuffer = VirtualAlloc(NULL,
chantab[chan].sectorsize + 304,MEM_COMMIT,PAGE_READWRITE);
chantab[chan].last_sector = 1000;
*chanptr = chan_count++;
info->status = 0;
info->sectorsize = chantab[chan].sectorsize;
init_count++;
return 1;
} else {
return SS$_IVCHAN;
}
}
/* Read a physical sector... */
unsigned phy_getsect(unsigned chan,unsigned sector,char **buffptr)
{
register unsigned sts = 1;
if (sector != chantab[chan].last_sector) {
if (chantab[chan].device_type) {
sts = cd_read(sector,chantab[chan].IoBuffer);
} else {
if (is_NT) {
DWORD BytesRead = -1; /* NT Bytes read */
SetFilePointer(chantab[chan].handle,
sector * chantab[chan].sectorsize,0,FILE_BEGIN);
if (!ReadFile(chantab[chan].handle,chantab[chan].IoBuffer,
chantab[chan].sectorsize,&BytesRead,NULL)) sts = SS$_PARITY;
} else {
DIOC_REGISTERS reg; /* W95 DIOC registers */
DPB dpb;
BOOL fResult;
DWORD cb = 0;
dpb.dpb_sector = sector; /* sector number */
dpb.dpb_count = 1; /* sector count */
dpb.dpb_buffer = chantab[chan].IoBuffer; /* sector buffer */
reg.reg_EAX = chantab[chan].device_name - 'A'; /* drive */
reg.reg_EBX = (DWORD) & dpb; /* parameter block */
reg.reg_ECX = -1; /* use dpb */
reg.reg_EDX = 0;/* sector num */
reg.reg_EDI = 0;
reg.reg_ESI = 0;
reg.reg_Flags = 0x0001; /* set carry flag */
fResult = DeviceIoControl(chantab[chan].handle,
VWIN32_DIOC_DOS_INT25,
&reg,sizeof(reg),
&reg,sizeof(reg),
&cb,0);
if (!fResult || (reg.reg_Flags & 0x0001)) {
printf("Sector %d read failed %d\n",sector,GetLastError());
sts = SS$_PARITY;
}
}
}
}
if (sts & 1) {
chantab[chan].last_sector = sector;
*buffptr = chantab[chan].IoBuffer;
}
return sts;
}
/* Handle an I/O request ... need to read the approriate sectors to
complete the request... */
unsigned phyio_read(unsigned chan,unsigned block,unsigned length,char *buffer)
{
register unsigned sts = 1;
if (chan < chan_count) {
register unsigned sectorsize = chantab[chan].sectorsize;
register unsigned sectno = block / (sectorsize / 512);
register unsigned offset = (block - sectno * (sectorsize / 512)) * 512;
while (length > 0) {
register unsigned transfer;
char *sectbuff;
if (((sts = phy_getsect(chan,sectno,&sectbuff)) & 1) == 0) break;
transfer = sectorsize - offset;
if (transfer > length) transfer = length;
memcpy(buffer,sectbuff + offset,transfer);
buffer += transfer;
length -= transfer;
sectno++;
offset = 0;
}
} else {
sts = SS$_IVCHAN;
}
if (sts & 1) {
read_count++;
} else {
printf("PHYIO Error %d Block %d Length %d\n",sts,block,length);
}
return sts;
}

210
extracters/ods2/phyos2.c Normal file
View File

@@ -0,0 +1,210 @@
/* PHYOS2.C v1.2 Physical I/O module for OS2 */
/* This version implemented to read from Floppy or CD by
guessing that A: or B: will be a floppy and anything
else is probably a CD? */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define INCL_DOS
#define INCL_DOSDEVIOCTL
#define INCL_NOPMAPI
#include <os2.h>
#include "phyio.h"
#include "ssdef.h"
unsigned init_count = 0;
unsigned read_count = 0;
unsigned write_count = 0;
void phyio_show(void)
{
printf("PHYIO_SHOW Initializations: %d Reads: %d Writes: %d\n",
init_count,read_count,write_count);
}
#pragma pack(1)
/*------------------------------------------------*
* Cat 0x80, Func 0x72: Read Long *
*------------------------------------------------*/
struct ReadLong {
ULONG ID_code;
UCHAR address_mode;
USHORT transfer_count;
ULONG start_sector;
UCHAR reserved;
UCHAR interleave_size;
UCHAR interleave_skip_factor;
};
#pragma pack()
#define SECTORSIZE 2048
struct ReadLong rl = {
0x31304443L, /* "CD01" */
0, /* Address mode */
1, /* Transfer count */
0, /* Start Sector */
0, /* Reserved */
0, /* Interleave size */
0/* Skip factor */
};
#define HANDLE_MAX 32
int hand_count = 0;
struct HANDLE {
HFILE hand_hfile;
int hand_drive;
} handle[HANDLE_MAX];
unsigned phyio_init(int devlen,char *devnam,unsigned *hand,struct phyio_info *info)
{
if (hand_count < HANDLE_MAX - 1) {
ULONG usAction;
ULONG open_mode;
ULONG bCmd;
ULONG stat;
char device[40];
memcpy(device,devnam,devlen);
device[devlen] = '\0';
handle[hand_count].hand_drive = toupper(*device);
open_mode = OPEN_FLAGS_DASD | OPEN_SHARE_DENYREADWRITE
| OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR
| OPEN_FLAGS_NOINHERIT | OPEN_ACCESS_READWRITE;
stat = DosOpen(device, /* filename to open */
&handle[hand_count].hand_hfile,
/* address of file handle */
&usAction,
/* address to store action taken */
0L,
/* size of new file */
FILE_NORMAL,
/* file's attribute */
FILE_OPEN,
/* action to take if file exists */
open_mode,
/* file's open mode */
0L);
/* Reserved */
if (stat) {
switch (stat) {
case 15:
printf("Drive %s is invalid.\n",device);
break;
case 21:
printf("Drive %s is not ready.\n",device);
break;
case 32:
printf("Drive %s is currently locked by another process.\n",device);
break;
case 65:
printf("Drive %s is a network drive.\n",device);
break;
default:
printf("error %d opening drive %s\n",stat,device);
}
return SS$_PARITY;
}
bCmd = 0;
stat = DosDevIOCtl(handle[hand_count].hand_hfile,IOCTL_DISK,DSK_LOCKDRIVE,&bCmd,1,NULL,NULL,0,NULL);
if (stat) {
printf("Error %d locking drive\n",stat);
return SS$_DEVNOTALLOC;
}
if (handle[hand_count].hand_drive > 'C') {
info->status = PHYIO_READONLY;
} else {
info->status = 0;
}
*hand = hand_count++;
init_count++;
return 1;
} else {
return SS$_IVCHAN;
}
}
unsigned phy_getsect(HFILE hfile,unsigned sector,char *buffer)
{
ULONG ulPinout,ulDinout;
ULONG stat;
char rawsect[SECTORSIZE + 304];
ulPinout = sizeof(rl);
ulDinout = sizeof(rawsect);
rl.start_sector = sector;
stat = DosDevIOCtl(hfile,
IOCTL_CDROMDISK,
CDROMDISK_READLONG,
&rl,sizeof(rl),&ulPinout,
rawsect,sizeof(rawsect),&ulDinout);
if (stat) {
printf("sys%04u: CDROMDISK_READLONG error\n",stat);
return SS$_PARITY;
}
memcpy(buffer,rawsect + 16,SECTORSIZE);
return 1;
}
unsigned phyio_read(unsigned handno,unsigned block,unsigned length,char *buffer)
{
register unsigned sts = 1;
#ifdef DEBUG
printf("PHYIO_READ block %d length %d\n",block,length);
#endif
if (handno >= hand_count) {
sts = SS$_IVCHAN;
} else {
if (handle[handno].hand_drive > 'C') {
register unsigned sect = block * 512 / SECTORSIZE;
register unsigned offset = (block - sect * SECTORSIZE / 512) * 512;
while (length > 0) {
register unsigned transfer;
if (offset == 0 && length >= SECTORSIZE) {
transfer = SECTORSIZE;
if (((sts = phy_getsect(handle[handno].hand_hfile,sect,buffer)) & 1) == 0) break;
} else {
char sector[SECTORSIZE];
if (((sts = phy_getsect(handle[handno].hand_hfile,sect,sector)) & 1) == 0) break;
transfer = SECTORSIZE - offset;
if (transfer > length) transfer = length;
memcpy(buffer,sector + offset,transfer);
}
buffer += transfer;
length -= transfer;
sect++;
offset = 0;
}
} else {
USHORT rc;
ULONG oldpos,lenread;
sts = SS$_PARITY;
rc = DosSetFilePtr(handle[handno].hand_hfile,block * 512,0,&oldpos);
if (rc == 0) {
rc = DosRead(handle[handno].hand_hfile,buffer,length,&lenread);
if (rc == 0 && lenread == length) sts = 1;
}
}
}
if (sts & 1) {
read_count++;
} else {
printf("PHYOS2 Error %d Block %d Length %d\n",sts,block,length);
}
return sts;
}
unsigned phyio_write(unsigned handle,unsigned block,unsigned length,char *buffer)
{
write_count++;
return SS$_WRITLCK;
}

87
extracters/ods2/phyvms.c Normal file
View File

@@ -0,0 +1,87 @@
/* PHYVMS.C v1.2 Physical I/O module for VMS */
/*
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.
*/
/* How come VMS is so much easier to do physical I/O on than
those other ^%$@*! systems? I can't believe that they have
different command sets for different device types, and can
even have different command sets depending on what mode they
are called from! Sigh. */
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <iodef.h>
#include <descrip.h>
#ifdef __GNUC__
unsigned sys$assign();
unsigned sys$qiow();
unsigned sys$dassgn();
#else
#include <starlet.h>
#endif
#include "phyio.h"
#define chk(sts) {register chksts; if (((chksts = sts) & 1) == 0) lib$stop(chksts);}
unsigned init_count = 0;
unsigned read_count = 0;
unsigned write_count = 0;
void phyio_show(void)
{
printf("PHYIO_SHOW Initializations: %d Reads: %d Writes: %d\n",
init_count,read_count,write_count);
}
unsigned phyio_init(int devlen,char *devnam,unsigned *handle,struct phyio_info *info)
{
struct dsc$descriptor devdsc;
devdsc.dsc$w_length = devlen;
devdsc.dsc$a_pointer = devnam;
init_count++;
info->status = 0; /* We don't know anything about this device! */
info->sectors = 0;
info->sectorsize = 0;
*handle = 0;
return sys$assign(&devdsc,handle,0,0,0,0);
}
unsigned phyio_close(unsigned handle)
{
return sys$dassgn(handle);
}
unsigned phyio_read(unsigned handle,unsigned block,unsigned length,char *buffer)
{
#ifdef DEBUG
printf("Phyio read block: %d into %x (%d bytes)\n",block,buffer,length);
#endif
read_count++;
return sys$qiow(1,handle,IO$_READLBLK,NULL,0,0,buffer,length,block,0,0,0);
}
unsigned phyio_write(unsigned handle,unsigned block,unsigned length,char *buffer)
{
#ifdef DEBUG
printf("Phyio write block: %d from %x (%d bytes)\n",block,buffer,length);
#endif
write_count++;
printf("Phyio write block: %d from %x (%d bytes)\n",block,buffer,length);
return sys$qiow(1,handle,IO$_WRITELBLK,NULL,0,0,buffer,length,block,0,0,0);
}

1049
extracters/ods2/rms.c Normal file

File diff suppressed because it is too large Load Diff

229
extracters/ods2/rms.h Normal file
View File

@@ -0,0 +1,229 @@
/* RMS.H v1.2 RMS routine definitions */
/*
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.
*/
/* If not using GNU C on VMS use real RMS structures :-)...
otherwise define minimum subset to meet our requirements */
#if defined(VMS) && !defined(__GNUC__)
#include <rms.h>
#else
#include "vmstime.h"
#define RMS$_RTB 98728
#define RMS$_EOF 98938
#define RMS$_FNF 98962
#define RMS$_NMF 99018
#define RMS$_WCC 99050
#define RMS$_BUG 99380
#define RMS$_DIR 99532
#define RMS$_ESS 99588
#define RMS$_FNM 99628
#define RMS$_IFI 99684
#define RMS$_NAM 99804
#define RMS$_RSS 99988
#define RMS$_WLD 100164
#define RMS$_DNF 114762
#define NAM$C_MAXRSS 255
#define NAM$M_SYNCHK 1
#define FAB$M_NAM 0x1000000
#define XAB$C_DAT 18
#define XAB$C_FHC 29
#define XAB$C_PRO 19
struct XABDAT {
void *xab$l_nxt;
int xab$b_cod;
int xab$w_rvn;
struct TIME xab$q_bdt;
struct TIME xab$q_cdt;
struct TIME xab$q_edt;
struct TIME xab$q_rdt;
};
#ifdef RMS_INITIALIZE
struct XABDAT cc$rms_xabdat = {NULL,XAB$C_DAT,0,
{{0,0,0,0,0,0,0,0}}, {{0,0,0,0,0,0,0,0}},
{{0,0,0,0,0,0,0,0}}, {{0,0,0,0,0,0,0,0}}};
#else
extern struct XABDAT cc$rms_xabdat;
#endif
struct XABFHC {
void *xab$l_nxt;
int xab$b_cod;
int xab$b_atr;
int xab$b_bkz;
int xab$w_dxq;
int xab$l_ebk;
int xab$w_ffb;
int xab$w_gbc;
int xab$l_hbk;
int xab$b_hsz;
int xab$w_lrl;
int xab$w_verlimit;
};
#ifdef RMS_INITIALIZE
struct XABFHC cc$rms_xabfhc = {NULL,XAB$C_FHC,0,0,0,0,0,0,0,0,0,0};
#else
extern struct XABFHC cc$rms_xabfhc;
#endif
struct XABPRO {
void *xab$l_nxt;
int xab$b_cod;
int xab$w_pro;
int xab$l_uic;
};
#ifdef RMS_INITIALIZE
struct XABPRO cc$rms_xabpro = {NULL,XAB$C_PRO,0,0};
#else
extern struct XABPRO cc$rms_xabpro;
#endif
#define NAM$M_WILDCARD 0x100
struct NAM {
unsigned short nam$w_did_num;
unsigned short nam$w_did_seq;
unsigned char nam$b_did_rvn;
unsigned char nam$b_did_nmx;
unsigned short nam$w_fid_num;
unsigned short nam$w_fid_seq;
unsigned char nam$b_fid_rvn;
unsigned char nam$b_fid_nmx;
int nam$b_ess;
int nam$b_rss;
int nam$b_esl;
char *nam$l_esa;
int nam$b_rsl;
char *nam$l_rsa;
int nam$b_dev;
char *nam$l_dev;
int nam$b_dir;
char *nam$l_dir;
int nam$b_name;
char *nam$l_name;
int nam$b_type;
char *nam$l_type;
int nam$b_ver;
char *nam$l_ver;
int nam$l_wcc;
int nam$b_nop;
int nam$l_fnb;
};
#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};
#else
extern struct NAM cc$rms_nam;
#endif
#define RAB$C_SEQ 0
#define RAB$C_RFA 2
struct RAB {
struct FAB *rab$l_fab;
char *rab$l_ubf;
char *rab$l_rhb;
unsigned rab$w_usz;
unsigned rab$w_rsz;
int rab$b_rac;
unsigned short rab$w_rfa[3];
};
#ifdef RMS_INITIALIZE
struct RAB cc$rms_rab = {NULL,NULL,NULL,0,0,0,{0,0,0}};
#else
extern struct RAB cc$rms_rab;
#endif
#define FAB$C_SEQ 0
#define FAB$C_REL 16
#define FAB$C_IDX 32
#define FAB$C_HSH 48
#define FAB$M_FTN 1
#define FAB$M_CR 2
#define FAB$M_PRN 4
#define FAB$M_BLK 8
#define FAB$C_UDF 0
#define FAB$C_FIX 1
#define FAB$C_VAR 2
#define FAB$C_VFC 3
#define FAB$C_STM 4
#define FAB$C_STMLF 5
#define FAB$C_STMCR 6
struct FAB {
struct NAM *fab$l_nam;
int fab$w_ifi;
char *fab$l_fna;
char *fab$l_dna;
int fab$b_fns;
int fab$b_dns;
int fab$l_alq;
int fab$b_bks;
int fab$w_deq;
int fab$b_fsz;
int fab$w_gbc;
int fab$w_mrs;
int fab$l_fop;
int fab$b_org;
int fab$b_rat;
int fab$b_rfm;
void *fab$l_xab;
};
#ifdef RMS_INITIALIZE
struct FAB cc$rms_fab = {NULL,0,NULL,NULL,0,0,0,0,0,0,0,0,0,0,0,0,NULL};
#else
extern struct FAB cc$rms_fab;
#endif
#endif
#define sys$search sys_search
#define sys$parse sys_parse
#define sys$setddir sys_setddir
#define sys$connect sys_connect
#define sys$disconnect sys_disconnect
#define sys$get sys_get
#define sys$display sys_display
#define sys$close sys_close
#define sys$open sys_open
#define sys$erase sys_erase
unsigned sys_search(struct FAB *fab);
unsigned sys_parse(struct FAB *fab);
unsigned sys_connect(struct RAB *rab);
unsigned sys_disconnect(struct RAB *rab);
unsigned sys_get(struct RAB *rab);
unsigned sys_display(struct FAB *fab);
unsigned sys_close(struct FAB *fab);
unsigned sys_open(struct FAB *fab);
unsigned sys_erase(struct FAB *fab);
unsigned sys_setddir(struct dsc$descriptor *newdir,unsigned short *oldlen,
struct dsc$descriptor *olddir);

48
extracters/ods2/ssdef.h Normal file
View File

@@ -0,0 +1,48 @@
/* Ssdef.h v1.2 System status definitions */
/*
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.
*/
#ifdef VMS
#include <ssdef.h>
#else
#define SS$_NORMAL 1
#define SS$_WASCLR 1
#define SS$_WASSET 9
#define SS$_ABORT 44
#define SS$_DEVNOTMOUNT 124
#define SS$_ILLEFC 236
#define SS$_INSFMEM 292
#define SS$_DATACHECK 92
#define SS$_BUGCHECK 676
#define SS$_DUPLICATE 148
#define SS$_BADPARAM 20
#define SS$_IVCHAN 316
#define SS$_NOIOCHAN 436
#define SS$_PARITY 500
#define SS$_WRITLCK 604
#define SS$_DEVNOTALLOC 2136
#define SS$_DUPFILENAME 2152
#define SS$_NOSUCHDEV 2312
#define SS$_NOSUCHFILE 2320
#define SS$_BADFILENAME 2072
#define SS$_BADIRECTORY 2088
#define SS$_ENDOFFILE 2160
#define SS$_FILELOCKED 2216
#define SS$_NOMOREFILES 2352
#define SS$_NOSUCHVOL 3882
#define SS$_NOTINSTALL 8212
#define SS$_DEVNOTDISM 8628
#endif

754
extracters/ods2/vmstime.c Normal file
View File

@@ -0,0 +1,754 @@
/*
VMSTIME.C v1.2
Author: Paul Nankervis
V1.2 - cleanup to stop compiler warnings
Please send bug reports or requests for enhancement
or improvement via email to: PaulNank@au1.ibm.com
This module contains versions of the VMS time routines
sys$numtim(), sys$asctim() and friends... They are
intended to be compatible with the routines of the same
name on a VMS system (so descriptors feature regularly!)
This code relies on being able to manipluate day numbers
and times using 32 bit arithmetic to crack a VMS quadword
byte by byte. If your C compiler doesn't have 32 bit int
fields give up now! On a 64 bit systems this code could
be modified to do 64 bit operations directly....
One advantage of doing arihmetic byte by byte is that
the code does not depend on what 'endian' the target
machine is - it will always treat bytes in the same order!
(Hopefully VMS time bytes will always be in the same order!)
A couple of stupid questions to go on with:-
o OK, I give up! What is the difference between a zero
date and a zero delta time?
o Anyone notice that the use of 16 bit words in
sys$numtim restricts delta times to 65535 days?
Paul Nankervis
*/
#include <stdio.h>
#include <memory.h>
#include "vmstime.h" /* Our header file! */
#include <time.h> /* C header for $GETTIM to find time */
#ifndef SS$_NORMAL
#define SS$_NORMAL 1
#define SS$_IVTIME 388
#define LIB$_ONEDELTIM 1410020
#endif
#define TIMEBASE 100000 /* 10 millisecond units in quadword */
#define TIMESIZE 8640000 /* Factor between dates & times */
#define QUAD_CENTURY_DAYS 146097
/* (400*365) + (400/4) - (400/100) + (400/400) */
#define CENTURY_DAYS 36524
/* (100*365) + (100/4) - (100/100) */
#define QUAD_YEAR_DAYS 1461
/* (4*365) + (4/4) */
#define YEAR_DAYS 365
/* 365 */
#define OFFSET_DAYS 94187
/* ((1858_1601)*365) + ((1858_1601)/4) - ((1858_1601)/100)
+ ((1858_1601)/400) + 320
OFFSET FROM 1/1/1601 TO 17/11/1858 */
#define BASE_YEAR 1601
/* combine_date_time() is an internal routine to put date and time into a
quadword - basically the opposite of lib_day() .... */
unsigned combine_date_time(int days,struct TIME *timadr,int day_time)
{
if (day_time >= TIMESIZE) {
return SS$_IVTIME;
} else {
/* Put days into quad timbuf... */
register unsigned count,time;
register unsigned char *ptr;
count = 8;
ptr = timadr->time;
time = days;
do {
*ptr++ = time;
time = (time >> 8);
} while (--count > 0);
/* Factor in the time... */
count = 8;
ptr = timadr->time;
time = day_time;
do {
time += *ptr * TIMESIZE;
*ptr++ = time;
time = (time >> 8);
} while (--count > 0);
/* Factor by time base... */
count = 8;
ptr = timadr->time;
time = 0;
do {
time += *ptr * TIMEBASE;
*ptr++ = time;
time = (time >> 8);
} while (--count > 0);
return SS$_NORMAL;
}
}
/* sys_gettim() implemented here by getting UNIX time in seconds since
1-Jan-1970 using time() and munging into a quadword... Some run time
systems don't seem to do this properly!!! Note that time() has a
resolution of only one second. */
unsigned sys_gettim(struct TIME *timadr)
{
time_t curtim = time(NULL);
return combine_date_time(40587 + curtim / 86400,timadr,
(curtim % 86400) * 100);
}
/* lib_cvt_vectim() takes individual time fields in seven word buffer and
munges into a quadword... */
unsigned short month_end[] = {0,31,59,90,120,151,181,212,243,273,304,334,365};
unsigned lib_cvt_vectim(unsigned short timbuf[7],struct TIME *timadr)
{
int delta = 0;
register unsigned sts,days,day_time;
sts = SS$_NORMAL;
/* lib_cvt_vectim packs the seven date/time components into a quadword... */
if (timbuf[0] == 0 && timbuf[1] == 0) {
delta = 1;
days = timbuf[2];
} else {
register int leap = 0,year = timbuf[0],month = timbuf[1];
if (month >= 2) {
if ((year % 4) == 0) {
if ((year % 100) == 0) {
if ((year % 400) == 0) {
leap = 1;
}
} else {
leap = 1;
}
}
}
days = timbuf[2];
if (year >= 1858 && year <= 9999 && month >= 1 &&
month <= 12 && days >= 1) {
days += month_end[month - 1];
if (month > 2) days += leap;
if (days <= month_end[month] + leap) {
year -= BASE_YEAR;
days += year * 365 + year / 4 - year / 100 + year / 400
- OFFSET_DAYS - 1;
} else {
sts = SS$_IVTIME;
}
} else {
sts = SS$_IVTIME;
}
}
if (timbuf[3] > 23 || timbuf[4] > 59 ||
timbuf[5] > 59 || timbuf[6] > 99) {
sts = SS$_IVTIME;
}
if (sts & 1) {
day_time = timbuf[3] * 360000 + timbuf[4] * 6000 +
timbuf[5] * 100 + timbuf[6];
sts = combine_date_time(days,timadr,day_time);
if (delta) {
/* We have to 2's complement delta times - sigh!! */
register unsigned count,time;
register unsigned char *ptr;
count = 8;
ptr = timadr->time;
time = 1;
do {
time = time + ((~*ptr) & 0xFF);
*ptr++ = time;
time = (time >> 8);
} while (--count > 0);
}
}
return sts;
}
/* lib_day() is a routine to crack quadword into day number and time */
unsigned lib_day(int *days,struct TIME *timadr,int *day_time)
{
register unsigned date,time,count;
register unsigned char *dstptr,*srcptr;
struct TIME wrktim;
int delta;
/* If no time specified get current using gettim() */
if (timadr == NULL) {
register unsigned sts;
sts = sys_gettim(&wrktim);
if ((sts & 1) == 0) {
return sts;
}
delta = 0;
srcptr = wrktim.time + 7;
} else {
/* Check specified time for delta... */
srcptr = timadr->time + 7;
if ((delta = (*srcptr & 0x80))) {
/* We have to 2's complement delta times - sigh!! */
count = 8;
srcptr = timadr->time;
dstptr = wrktim.time;
time = 1;
do {
time = time + ((~*srcptr++) & 0xFF);
*dstptr++ = time;
time = (time >> 8);
} while (--count > 0);
srcptr = wrktim.time + 7;
}
}
/* Throw away the unrequired time precision */
count = 8;
dstptr = wrktim.time + 7;
time = 0;
do {
time = (time << 8) | *srcptr--;
*dstptr-- = time / TIMEBASE;
time %= TIMEBASE;
} while (--count > 0);
/* Seperate the date and time */
date = time = 0;
srcptr = wrktim.time + 7;
count = 8;
do {
time = (time << 8) | *srcptr--;
date = (date << 8) | (time / TIMESIZE);
time %= TIMESIZE;
} while (--count > 0);
/* Return results... */
if (delta) {
*days = -(int) date;
if (day_time != NULL) *day_time = -(int) time;
} else {
*days = date;
if (day_time != NULL) *day_time = time;
}
return SS$_NORMAL;
}
/* sys_numtim() takes quadword and breaks it into a seven word time buffer */
unsigned char month_days[] = {31,29,31,30,31,30,31,31,30,31,30,31};
unsigned sys_numtim(unsigned short timbuf[7],struct TIME *timadr)
{
register int date,time;
/* Use lib_day to crack time into date/time... */
{
int days,day_time;
register unsigned sts;
sts = lib_day(&days,timadr,&day_time);
if ((sts & 1) == 0) {
return sts;
}
date = days;
time = day_time;
}
/* Delta or date... */
if (date < 0 || time < 0) {
timbuf[2] = -date; /* Days */
timbuf[1] = 0; /* Month */
timbuf[0] = 0; /* Year */
time = -time;
} else {
/* Date... */
register int year,month;
date += OFFSET_DAYS;
year = BASE_YEAR + (date / QUAD_CENTURY_DAYS) * 400;
date %= QUAD_CENTURY_DAYS;
/* Kludge century division - last century in quad is longer!! */
if ((month = date / CENTURY_DAYS) == 4) month = 3;
date -= month * CENTURY_DAYS;
year += month * 100;
/* Use the same technique to find out the quad year and year -
last year in quad is longer!! */
year += (date / QUAD_YEAR_DAYS) * 4;
date %= QUAD_YEAR_DAYS;
if ((month = date / YEAR_DAYS) == 4) month = 3;
date -= month * YEAR_DAYS;
year += month;
/* Adjust for years which have no Feb 29th */
if (date++ > 58) {
if (month != 3) {
date++;
} else {
if ((year % 100) == 0 && (year % 400) != 0) date++;
}
}
/* Figure out what month it is... */
{
unsigned char *mthptr = month_days;
month = 1;
while (date > *mthptr) {
date -= *mthptr++;
month++;
}
}
/* Return date results... */
timbuf[2] = date; /* Days */
timbuf[1] = month; /* Month */
timbuf[0] = year; /* Year */
}
/* Return time... */
timbuf[6] = time % 100; /* Hundredths */
time /= 100;
timbuf[5] = time % 60; /* Seconds */
time /= 60;
timbuf[4] = time % 60; /* Minutes */
timbuf[3] = time / 60; /* Hours */
return SS$_NORMAL;
}
/* sys_bintim() takes ascii time and convert it to a quadword */
char month_names[] = "-JAN-FEB-MAR-APR-MAY-JUN-JUL-AUG-SEP-OCT-NOV-DEC-";
char time_sep[] = "::.";
unsigned sys_bintim(struct dsc$descriptor *timbuf,struct TIME *timadr)
{
register int length = timbuf->dsc$w_length;
register char *chrptr = timbuf->dsc$a_pointer;
unsigned short wrktim[7];
int num,tf;
/* Skip leading spaces... */
while (length > 0 && *chrptr == ' ') {
length--;
chrptr++;
}
/* Get the day number... */
num = -1;
if (length > 0 && *chrptr >= '0' && *chrptr <= '9') {
num = 0;
do {
num = num * 10 + (*chrptr++ - '0');
} while (--length > 0 && *chrptr >= '0' && *chrptr <= '9');
}
/* Check for month separator "-" - if none delta time... */
if (length > 0 && *chrptr == '-') {
chrptr++;
/* Get current time for defaults... */
sys_numtim(wrktim,NULL);
if (num >= 0) wrktim[2] = num;
num = 0;
if (--length >= 3 && *chrptr != '-') {
char *mn = month_names + 1;
num = 1;
while (num <= 12) {
if (memcmp(chrptr,mn,3) == 0) break;
mn += 4;
num++;
}
chrptr += 3;
length -= 3;
wrktim[1] = num;
}
/* Now look for year... */
if (length > 0 && *chrptr == '-') {
length--;
chrptr++;
if (length > 0 && *chrptr >= '0' && *chrptr <= '9') {
num = 0;
do {
num = num * 10 + (*chrptr++ - '0');
} while (--length > 0 && *chrptr >= '0' && *chrptr <= '9');
wrktim[0] = num;
}
}
} else {
/* Delta time then... */
wrktim[0] = wrktim[1] = 0;
wrktim[2] = num;
wrktim[3] = wrktim[4] = wrktim[5] = wrktim[6] = 0;
}
/* Skip any spaces between date and time... */
while (length > 0 && *chrptr == ' ') {
length--;
chrptr++;
}
/* Now wrap up time fields... */
for (tf = 0; tf < 3; tf++) {
if (length > 0 && *chrptr >= '0' && *chrptr <= '9') {
num = 0;
do {
num = num * 10 + (*chrptr++ - '0');
} while (--length > 0 && *chrptr >= '0' && *chrptr <= '9');
wrktim[3 + tf] = num;
if (num > 59) wrktim[1] = 13;
}
if (length > 0 && *chrptr == time_sep[tf]) {
length--;
chrptr++;
} else {
break;
}
}
/* Hundredths of seconds need special handling... */
if (length > 0 && *chrptr >= '0' && *chrptr <= '9') {
tf = 10;
num = 0;
do {
num = num + tf * (*chrptr++ - '0');
tf = tf / 10;
} while (--length > 0 && *chrptr >= '0' && *chrptr <= '9');
wrktim[6] = num;
}
/* Now skip any trailing spaces... */
while (length > 0 && *chrptr == ' ') {
length--;
chrptr++;
}
/* If anything left then we have a problem... */
if (length == 0) {
return lib_cvt_vectim(wrktim,timadr);
} else {
return SS$_IVTIME;
}
}
/* sys_asctim() converts quadword to ascii... */
unsigned sys_asctim(unsigned short *timlen,struct dsc$descriptor *timbuf,
struct TIME *timadr,unsigned cvtflg)
{
register int count,timval;
unsigned short wrktim[7];
register int length = timbuf->dsc$w_length;
register char *chrptr = timbuf->dsc$a_pointer;
/* First use sys_numtim to get the date/time fields... */
{
register unsigned sts;
sts = sys_numtim(wrktim,timadr);
if ((sts & 1) == 0) {
return sts;
}
}
/* See if we want delta days or date... */
if (cvtflg == 0) {
/* Check if date or delta time... */
if (*wrktim) {
/* Put in days and month... */
if (length > 0) {
if ((timval = wrktim[2]) / 10 == 0) {
*chrptr++ = ' ';
} else {
*chrptr++ = '0' + timval / 10;
}
length--;
}
if (length > 0) {
*chrptr++ = '0' + (timval % 10);
length--;
}
if ((count = length) > 5) count = 5;
memcpy(chrptr,month_names + (wrktim[1] * 4 - 4),count);
length -= count;
chrptr += count;
timval = *wrktim;
} else {
/* Get delta days... */
timval = wrktim[2];
}
/* Common code for year number and delta days!! */
count = 10000;
if (timval < count) {
count = 1000;
while (length > 0 && timval < count && count > 1) {
length--;
*chrptr++ = ' ';
count /= 10;
}
}
while (length > 0 && count > 0) {
length--;
*chrptr++ = '0' + (timval / count);
timval = timval % count;
count /= 10;
}
/* Space between date and time... */
if (length > 0) {
*chrptr++ = ' ';
length--;
}
}
/* Do time... :-) */
count = 3;
do {
timval = wrktim[count];
if (length >= 1) *chrptr++ = '0' + (timval / 10);
if (length >= 2) {
*chrptr++ = '0' + (timval % 10);
length -= 2;
} else {
length = 0;
}
if (count < 6 && length > 0) {
length--;
if (count == 5) {
*chrptr++ = '.';
} else {
*chrptr++ = ':';
}
}
} while (++count < 7);
/* We've done it - time to return length... */
if (timlen != NULL) *timlen = timbuf->dsc$w_length - length;
return SS$_NORMAL;
}
/* lib_day_of_week() computes day of week from quadword... */
unsigned lib_day_of_week(struct TIME *timadr,unsigned *weekday)
{
int days;
register unsigned sts;
/* Use lib_day to crack quadword... */
sts = lib_day(&days,timadr,NULL);
if (sts & 1) {
*weekday = ((days + 2) % 7) + 1;
}
return sts;
}
/* addx & subx COULD use 32 bit arithmetic to do a word at a time. But
this only works on hardware which has the same endian as the VAX!
(Intel works fine!! :-) ) So this version works byte by byte which
should work on VMS dates regardless of system endian - but they
will NOT perform arithmetic correctly for other data types on
systems with opposite endian!!! */
unsigned lib_addx(void *addant,void *addee,void *result,int *lenadd)
{
register int count;
register unsigned carry = 0;
register unsigned char *ant = (unsigned char *) addant;
register unsigned char *ee = (unsigned char *) addee;
register unsigned char *res = (unsigned char *) result;
if (lenadd == NULL) {
count = 8;
} else {
count = *lenadd * 4;
}
while (count-- > 0) {
carry = *ant++ + (carry + *ee++);
*res++ = carry;
carry = carry >> 8;
}
return SS$_NORMAL;
}
unsigned lib_subx(void *subant,void *subee,void *result,int *lenadd)
{
register int count;
register unsigned carry = 0;
register unsigned char *ant = (unsigned char *) subant;
register unsigned char *ee = (unsigned char *) subee;
register unsigned char *res = (unsigned char *) result;
if (lenadd == NULL) {
count = 8;
} else {
count = *lenadd * 4;
}
while (count-- > 0) {
carry = *ant++ - (carry + *ee++);
*res++ = carry;
carry = (carry >> 8) & 1;
}
return SS$_NORMAL;
}
unsigned lib_add_times(struct TIME *time1,struct TIME *time2,
struct TIME *result)
{
if (time1->time[7] & 0x80) {
if (time2->time[7] & 0x80) {
return lib_addx(time1,time2,result,NULL);
} else {
return lib_subx(time2,time1,result,NULL);
}
} else {
if (time2->time[7] & 0x80) {
return lib_subx(time1,time2,result,NULL);
} else {
return LIB$_ONEDELTIM;
}
}
}
unsigned lib_sub_times(struct TIME *time1,struct TIME *time2,
struct TIME *result)
{
if ((time1->time[7] & 0x80) != (time2->time[7] & 0x80)) {
return lib_addx(time1,time2,result,NULL);
} else {
register int cmp,count = 7;
do {
if ((cmp = (time1->time[count] - time2->time[count]))) break;
} while (--count >= 0);
if (cmp < 0) {
return lib_subx(time1,time2,result,NULL);
} else {
return lib_subx(time2,time1,result,NULL);
}
}
}
unsigned lib_mult_delta_time(int *multiple,struct TIME *timadr)
{
register unsigned count = 8,carry = 0;
register int factor = *multiple;
register unsigned char *ptr = timadr->time;
/* Check for delta time... */
if (timadr->time[7] & 0x80) {
/* Use absolute factor... */
if (factor < 0) factor = -factor;
/* Multiply delta time... */
do {
carry += *ptr * factor;
*ptr++ = carry;
carry = (carry >> 8);
} while (--count > 0);
return SS$_NORMAL;
} else {
return SS$_IVTIME;
}
}

52
extracters/ods2/vmstime.h Normal file
View File

@@ -0,0 +1,52 @@
/*
VMSTIME.H v1.1
Author: Paul Nankervis
Please send bug reports to PaulNank@au1.ibm.com
*/
#ifndef __VMSTIME__
#define __VMSTIME__ loaded
#include "descrip.h"
struct TIME {
unsigned char time[8]; /* Structure of time */
}; /* Look out Einstein!! :-) */
#define lib$add_times lib_add_times
#define lib$addx lib_addx
#define lib$cvt_vectim lib_cvt_vectim
#define lib$day lib_day
#define lib$day_of_week lib_day_of_week
#define lib$mult_delta_time lib_mult_delta_time
#define lib$sub_times lib_sub_times
#define lib$subx lib_subx
#define sys$asctim sys_asctim
#define sys$bintim sys_bintim
#define sys$gettim sys_gettim
#define sys$numtim sys_numtim
unsigned sys_gettim(struct TIME *timadr);
unsigned lib_cvt_vectim(unsigned short timbuf[7],struct TIME *timadr);
unsigned lib_day(int *days,struct TIME *timadr,int *day_time);
unsigned sys_numtim(unsigned short timbuf[7],struct TIME *timadr);
unsigned sys_bintim(struct dsc$descriptor *timbuf,struct TIME *timadr);
unsigned sys_asctim(unsigned short *timlen,struct dsc$descriptor *timbuf,
struct TIME *timadr,unsigned cvtflg);
unsigned lib_day_of_week(struct TIME *timadr,unsigned *weekday);
unsigned lib_addx(void *addant,void *addee,void *result,int *lenadd);
unsigned lib_subx(void *subant,void *subee,void *result,int *lenadd);
unsigned lib_add_times(struct TIME *time1,struct TIME *time2,
struct TIME *result);
unsigned lib_sub_times(struct TIME *time1,struct TIME *time2,
struct TIME *result);
unsigned lib_mult_delta_time(int *multiple,struct TIME *timadr);
#endif

184
extracters/tpdump.c Normal file
View File

@@ -0,0 +1,184 @@
/* Dump tapes in the format of the simh 1401 simulator.
See "usage" function below.
*/
#include <stdio.h>
/* From i1401_dat.h: */
char bcd_to_ascii_old[64] = {
' ', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '0', '#', '@', ':', '>', '(',
'^', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '\'', ',', '%', '=', '\\', '+',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '!', '$', '*', ']', ';', '_',
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '?', '.', ')', '[', '<', '"'
};
char bcd_to_ascii_a[64] = {
' ', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '0', '#', '@', ':', '>', '{',
'^', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '|', ',', '%', '~', '\\', '"',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '!', '$', '*', ']', ';', '_',
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '?', '.', ')', '[', '<', '}'
};
char bcd_to_ascii_h[64] = {
' ', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '0', '=', '\'', ':', '>', '{',
'^', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '|', ',', '(', '~', '\\', '"',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '!', '$', '*', ']', ';', '_',
'+', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '?', '.', ')', '[', '<', '}'
};
/* Interesting BCD characters, from i1401_defs.h */
#define BCD_BLANK 000
#define BCD_ALT 020
#define BCD_WM 035
size_t read_len ( FILE* fi )
/* Read a little-endian four-byte number */
{ unsigned char c; /* A Character from the file */
size_t i;
size_t lc; /* The character, as a long int */
size_t n; /* the number */
if ( fread ( &c, 1, 1, fi ) == 0 )
return (0);
n = c; i = 256;
if ( fread ( &c, 1, 1, fi ) == 0 )
return (0);
n += i*c;
i *= 256;
if ( fread ( &c, 1, 1, fi ) == 0 )
return (0);
n += i*c;
i *= 256;
if ( fread ( &c, 1, 1, fi ) == 0 )
return (0);
n += i*c;
i *= 256;
return (n);
}
void usage ( char* argv[] )
{ printf ( "Usage: %s [options] <input_file>\n", argv[0] );
printf ( " Options: -w to print word marks on a separate line)\n" );
printf ( " -# number of 'files' to print (default 1)\n");
printf ( " -a print all of each record, including blank lines,\n");
printf ( " which are otherwise suppressed (except for the last one)\n");
printf ( " -e E11 format, i.e., don't require even-length records\n" );
printf ( " -h Use the H (Fortran) print arrangement\n");
printf ( " -o Use the 'old simh' print arrangement\n");
}
main ( int argc, char* argv[] )
{ FILE* fi;
int all; /* "print all of a record, even blank lines" */
char* bcd_to_ascii; /* Translation table, ..._a or ..._h */
int cl; /* Command line argument index */
int dowm; /* "do word marks" */
int even; /* Require even-length records */
int i, j; /* Subscript, loop inductor */
int nb; /* Number of characters in print buffer so far */
int nf, nft; /* Number of "files" */
int np; /* Number of characters processed so far */
int nr; /* Number of records dumped so far */
char pr[101]; /* Buffer to print tape contents */
size_t recsiz, recsiz2; /* Record size before, after */
char wm[101]; /* Buffer to print word marks */
if ( argc < 2 )
{ usage( argv );
return(1);
}
all = 0;
bcd_to_ascii = bcd_to_ascii_a;
dowm = 0;
even = 1;
nf = 1;
for ( cl=1; cl<=argc; cl++ )
{ if ( argv[cl][0] != '-' ) break;
if ( argv[cl][1] == 'w' ) dowm = 1;
else if ( argv[cl][1] == 'a' ) all = 1;
else if ( argv[cl][1] == 'e' ) even = 0;
else if ( argv[cl][1] == 'h' ) bcd_to_ascii = bcd_to_ascii_h;
else if ( argv[cl][1] == 'o' ) bcd_to_ascii = bcd_to_ascii_old;
else if ( sscanf(argv[cl], "%d", &nft ) ) nf = -nft;
else
{ usage ( argv );
return(1);
}
}
fi = fopen ( argv[cl], "r" );
if ( fi == NULL )
{ printf ( "Unable to open %s\n", argv[cl] );
return(2);
}
bcd_to_ascii[BCD_BLANK] = bcd_to_ascii[BCD_ALT]; /* use '^' for blank */
nft = 1;
if ( nf > 1 ) printf ( "File %d\n", nft );
while ( nf > 0 )
{ nf--;
for ( np=0; np<100; pr[np++]='.' );
pr[100] = '\0';
for ( np=5; np<=100; np+=5 ) /* Print a row of dots and column numbers */
for ( nb=1, i=np; i>0; i/=10, nb++ ) pr[np-nb] = '0' + ( i%10 );
printf ( " %s\n", pr );
nr = 0;
while ( recsiz = read_len ( fi ) )
{ nb = 1;
nr++;
i = recsiz;
while ( i )
{ for ( np=0; np<101; pr[np]='^',wm[np++]=' ') ; /* Clear buffers */
for ( np=0; i>0 && np<100; np++ )
{ if ( fread ( &pr[np], 1, 1, fi ) <= 0 )
{ printf ( "Error reading %s\n", argv[cl] );
return(3);
}
i--;
pr[np] = bcd_to_ascii[pr[np]];
if ( dowm )
if ( pr[np] == bcd_to_ascii[BCD_WM] ) wm[np--] = '1';
}
for ( j=np--; j>=0 && pr[j] == bcd_to_ascii[BCD_ALT] &&
wm[j] == ' '; j-- ) ;
if ( ( j >= 0 ) || ( nb == 1 ) || all || ( i == 0 ) )
{ printf ( "%5d: ", nb );
pr[np+1] = '\0';
printf ( "%s", pr );
if ( nb == 1 )
{ for ( j=np ; j++<100 ; printf ( " " ) ) ;
printf ( " Record %d", nr );
}
printf ( "\n" );
if ( dowm )
{ for ( ; np >= 0 && wm[np] == ' '; np-- );
wm[++np] = '\0';
printf ( " %s\n", wm );
}
}
nb += 100;
}
if ( (recsiz & 1) && even ) fread ( pr, 1, 1, fi );
recsiz2 = read_len ( fi );
if ( recsiz2 != recsiz )
{ printf("Unequal starting and ending record sizes: %d != %d\n",
recsiz, recsiz2);
return(4);
}
}
if ( nf > 0 ) printf ( "File %d\n", ++nft );
}
}

View File

@@ -1,175 +1,175 @@
ODS2 June '98
A Program to Read ODS2 Disk Volumes
Say, what is this?
ODS2 is a program to read VMS disk volumes written in VMS
ODS2 format.
Why bother?
Well sometimes it is convenient to see what is on a VMS CD,
or copy files from VMS disk on another platform. Maybe in
future it could be used as a basis for a PC Bookreader
program, or possibly other software?
What other platforms?
ODS2 is written in 'Standard C' with the intent that it can
be compiled and run on non-VMS systems. However this requires
a C compiler which has 32 bit 'int' types, 16 bit 'short'
types, and 8 bit 'char'. The current version does no special
'endian' handling so it can only be run on systems which are
little-endian like the VAX. Fortunately that inludes Intel...
Could it be made to run on big-endian systems?
Yes it could! This would probably best be done by defining
C macros or functions to extract words or long words from the
disk structures as appropriate. On a little-endian system these
would be simply pass-through, while on a big-endian system they
would reverse the byte order. I have not attempted this because
I don't have a suitable test system!!
What else is needed?
Some operating system support is also required to read an
absolute disk sector from the target disk. This is NOT as
easy as it sounds. I do not currently have sufficient
documentation to set this up for as many platforms as I
would like!! However I do have modules to read disks under
VMS (easy!) and floppies and CD under OS2, Windows 95 and
Windows NT.
How do I build it?
On a VMS system ODS2 can be compiled by executing the
procedure BUILD.COM. On other platforms you need to compile
Ods2.c, Rms.c, Direct.c, Access.c, Device.c, Cache.c, Vmstime.c,
and the appropriate Phy*.c routine for your system. On OS/2 I
compile using the gcc command:-
gcc -fdollars-in-identifiers ods2.c,rms.c,direct.c,
access.c,device.c,cache.c,phyos2.c,vmstime.c
What can it do?
Basically ODS2 provides cut down DIRECTORY, COPY and
SEARCH commands for VMS volumes on non-VMS systems. These
can be used to find out what is on a VMS volume, and copy
files onto the local file sytem.
What file types?
Basically ODS2 can only deal with sequential files. I do not
have information on how indexed file types are constructed,
and relative files are of limited interest.
What about volume sets?
ODS2 does contain support for multi-volume sets. However there
is no checking that the correct volumes have been specified and
error handling is very fragile. You should ensure that you
specify volume set mount commands very carefully!
What about ODS5?
Sorry, but I have no idea! I have not seen any ODS5 information
or specifications. Most likely this program will fall in a heap
when presented with an ODS5 disk volume.
What about bugs?
There are plenty!! This code has been tested for several hours
by a single developer/user on one workstation (absolutely no
testing or input from any other person up to this point!).
Contrast this to the VMS filesystem which has had hundreds of
developers, millions of users, and has run on about 500,000
systems over the last 20 years!! I would hope to fix some of
the more severe limitations and provide better error handling
fairly soon, perhaps even put some comments into the code?
Maybe the next release might have fewer bugs?
It is free?
Yeap! It is provided 'as is' to help people in the VMS
community. However there is NO SUPPORT! I will try to fix
any reported problems, but as I really only get to work on
it while the kids are at Scouts on Monday nights, fixes
happen slowly! But if you have comments or suggestions then
please feel free to mail me!
Can I use the code?
Yeap! You can use and modify the code provided that you
acknowledge the author in the source of any modules which use
any part of this code. I would also appreciate, where possible,
being sent any enhancements for my own use.
Can I call the routines from my program?
You should be able to. Many of the modules follow an 'RMS'
sort of standard, and programs which only ever read RMS files
from C might be converted to read VMS volumes on another platform
without too much effort. In addition to the RMSish interface,
it would not be difficult to package up an $ASSIGN/$QIOW interface
for common file operations...
What is the status of ODS2?
This is the first release - actually more like a prototype
than an real release! But it may generate useful feedback and
possibly be useful to others the way it is? However if you are
tempted to use this version for real file transfers, DO YOUR OWN
TESTING first! This program may not have encountered volumes and
files like yours and could easily generate garbage results!!!
Is more work happening?
Yes! I find the program very useful moving stuff from my
VAXstation to my PC. I would like to be able to write ODS2 volumes
so that I can move files in the other direction! And yes I hope
to generally improve the code - particularly in the area of error
handling!
Can I make a suggestion?
You sure can! If you see something which needs improvement then
let me know. It may be more interesting than whatever I am doing now!
In fact if I don't hear from anyone then I might even loose interest!
Can I see a command sample?
Sure:-
C:> ODS2
ODS2 v1.2
$> mount E:,F:
%MOUNT-I-MOUNTED, Volume FOX1 mounted on E:
%MOUNT-I-MOUNTED, Volume FOX2 mounted on F:
$> direct/file E:[*...]
Directory E:[PNANKERVIS]
3MONTH.LOWUSE;1 (51,20,2)
ACCTEST.COM;1 (137,4,1)
ACCTEST.EXE;1 (53,4,2)
.....
$> set default E:[sys0.sysmgr]
$> dir [-.sys*...].%
.....
$> copy *.c *.*
%COPY-S-COPIED, E:[SYS0.SYSMGR]ACCESS.C;1 copied to ACCESS.C (3 records)
....
$> show time
24-MAR-1998 20:15:23.5
$> dismount E:
$> exit
What commands are supported?
A summary is:-
mount DRIVE:[,DRIVE:...]
directory [/file|/size|/date] [FILE-SPEC]
copy FILE-SPEC OUTPUT-FILE
dismount DRIVE:
search FILE-SPEC STRING
set default DIR-SPEC
show default
show time
exit
Note - DRIVE: is normally the native system drive name,
for example D: might be a CD on a PC - xxx: might be
/dev/xxx on a Unix system.
- when a list of drives is specified on the mount command
they are assumed to contain a single valid volume set
(this is not validated!!)
- file-spec is in the usual VMS syntax and may contain
wildcards (for example A:[-.*obj%%...]*abc*.obj;-2)
Who would write this?
Me! Maybe it will become the basis of something more? If you
have suggestions or want to know more then please mail me at
paulnank@au1.ibm.com
Thanks for listening!
Paul Nankervis
ODS2 June '98
A Program to Read ODS2 Disk Volumes
Say, what is this?
ODS2 is a program to read VMS disk volumes written in VMS
ODS2 format.
Why bother?
Well sometimes it is convenient to see what is on a VMS CD,
or copy files from VMS disk on another platform. Maybe in
future it could be used as a basis for a PC Bookreader
program, or possibly other software?
What other platforms?
ODS2 is written in 'Standard C' with the intent that it can
be compiled and run on non-VMS systems. However this requires
a C compiler which has 32 bit 'int' types, 16 bit 'short'
types, and 8 bit 'char'. The current version does no special
'endian' handling so it can only be run on systems which are
little-endian like the VAX. Fortunately that inludes Intel...
Could it be made to run on big-endian systems?
Yes it could! This would probably best be done by defining
C macros or functions to extract words or long words from the
disk structures as appropriate. On a little-endian system these
would be simply pass-through, while on a big-endian system they
would reverse the byte order. I have not attempted this because
I don't have a suitable test system!!
What else is needed?
Some operating system support is also required to read an
absolute disk sector from the target disk. This is NOT as
easy as it sounds. I do not currently have sufficient
documentation to set this up for as many platforms as I
would like!! However I do have modules to read disks under
VMS (easy!) and floppies and CD under OS2, Windows 95 and
Windows NT.
How do I build it?
On a VMS system ODS2 can be compiled by executing the
procedure BUILD.COM. On other platforms you need to compile
Ods2.c, Rms.c, Direct.c, Access.c, Device.c, Cache.c, Vmstime.c,
and the appropriate Phy*.c routine for your system. On OS/2 I
compile using the gcc command:-
gcc -fdollars-in-identifiers ods2.c,rms.c,direct.c,
access.c,device.c,cache.c,phyos2.c,vmstime.c
What can it do?
Basically ODS2 provides cut down DIRECTORY, COPY and
SEARCH commands for VMS volumes on non-VMS systems. These
can be used to find out what is on a VMS volume, and copy
files onto the local file sytem.
What file types?
Basically ODS2 can only deal with sequential files. I do not
have information on how indexed file types are constructed,
and relative files are of limited interest.
What about volume sets?
ODS2 does contain support for multi-volume sets. However there
is no checking that the correct volumes have been specified and
error handling is very fragile. You should ensure that you
specify volume set mount commands very carefully!
What about ODS5?
Sorry, but I have no idea! I have not seen any ODS5 information
or specifications. Most likely this program will fall in a heap
when presented with an ODS5 disk volume.
What about bugs?
There are plenty!! This code has been tested for several hours
by a single developer/user on one workstation (absolutely no
testing or input from any other person up to this point!).
Contrast this to the VMS filesystem which has had hundreds of
developers, millions of users, and has run on about 500,000
systems over the last 20 years!! I would hope to fix some of
the more severe limitations and provide better error handling
fairly soon, perhaps even put some comments into the code?
Maybe the next release might have fewer bugs?
It is free?
Yeap! It is provided 'as is' to help people in the VMS
community. However there is NO SUPPORT! I will try to fix
any reported problems, but as I really only get to work on
it while the kids are at Scouts on Monday nights, fixes
happen slowly! But if you have comments or suggestions then
please feel free to mail me!
Can I use the code?
Yeap! You can use and modify the code provided that you
acknowledge the author in the source of any modules which use
any part of this code. I would also appreciate, where possible,
being sent any enhancements for my own use.
Can I call the routines from my program?
You should be able to. Many of the modules follow an 'RMS'
sort of standard, and programs which only ever read RMS files
from C might be converted to read VMS volumes on another platform
without too much effort. In addition to the RMSish interface,
it would not be difficult to package up an $ASSIGN/$QIOW interface
for common file operations...
What is the status of ODS2?
This is the first release - actually more like a prototype
than an real release! But it may generate useful feedback and
possibly be useful to others the way it is? However if you are
tempted to use this version for real file transfers, DO YOUR OWN
TESTING first! This program may not have encountered volumes and
files like yours and could easily generate garbage results!!!
Is more work happening?
Yes! I find the program very useful moving stuff from my
VAXstation to my PC. I would like to be able to write ODS2 volumes
so that I can move files in the other direction! And yes I hope
to generally improve the code - particularly in the area of error
handling!
Can I make a suggestion?
You sure can! If you see something which needs improvement then
let me know. It may be more interesting than whatever I am doing now!
In fact if I don't hear from anyone then I might even loose interest!
Can I see a command sample?
Sure:-
C:> ODS2
ODS2 v1.2
$> mount E:,F:
%MOUNT-I-MOUNTED, Volume FOX1 mounted on E:
%MOUNT-I-MOUNTED, Volume FOX2 mounted on F:
$> direct/file E:[*...]
Directory E:[PNANKERVIS]
3MONTH.LOWUSE;1 (51,20,2)
ACCTEST.COM;1 (137,4,1)
ACCTEST.EXE;1 (53,4,2)
.....
$> set default E:[sys0.sysmgr]
$> dir [-.sys*...].%
.....
$> copy *.c *.*
%COPY-S-COPIED, E:[SYS0.SYSMGR]ACCESS.C;1 copied to ACCESS.C (3 records)
....
$> show time
24-MAR-1998 20:15:23.5
$> dismount E:
$> exit
What commands are supported?
A summary is:-
mount DRIVE:[,DRIVE:...]
directory [/file|/size|/date] [FILE-SPEC]
copy FILE-SPEC OUTPUT-FILE
dismount DRIVE:
search FILE-SPEC STRING
set default DIR-SPEC
show default
show time
exit
Note - DRIVE: is normally the native system drive name,
for example D: might be a CD on a PC - xxx: might be
/dev/xxx on a Unix system.
- when a list of drives is specified on the mount command
they are assumed to contain a single valid volume set
(this is not validated!!)
- file-spec is in the usual VMS syntax and may contain
wildcards (for example A:[-.*obj%%...]*abc*.obj;-2)
Who would write this?
Me! Maybe it will become the basis of something more? If you
have suggestions or want to know more then please mail me at
paulnank@au1.ibm.com
Thanks for listening!
Paul Nankervis