mirror of
https://github.com/open-simh/simtools.git
synced 2026-03-03 01:58:59 +00:00
Import most recent simtools.zip and add a few extra tape converters
This commit is contained in:
66
README.md
Normal file
66
README.md
Normal 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
69
converters/decsys.c
Normal 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
424
converters/hpconvert.c
Normal 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
120
converters/indent.c
Normal 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
71
converters/m8376.c
Normal 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
87
converters/mt2tpc.c
Normal 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
66
converters/noff.c
Normal 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
72
converters/strrem.c
Normal 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
74
converters/strsub.c
Normal 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
92
converters/tar2mt.c
Normal 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
25
converters/tar2mt.txt
Normal 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
84
converters/tpc2mt.c
Normal 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
930
crossassemblers/hpasm.c
Normal 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);
|
||||
}
|
||||
/****************************************************/
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
862
extracters/ods2/access.c
Normal 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
237
extracters/ods2/access.h
Normal 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);
|
||||
237
extracters/ods2/access.h.bak
Normal file
237
extracters/ods2/access.h.bak
Normal 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
37
extracters/ods2/build.com
Normal 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
411
extracters/ods2/cache.c
Normal 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
411
extracters/ods2/cache.c.bak
Normal 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
44
extracters/ods2/cache.h
Normal 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
34
extracters/ods2/descrip.h
Normal 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
85
extracters/ods2/device.c
Normal 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
550
extracters/ods2/direct.c
Normal 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
31
extracters/ods2/direct.h
Normal 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
37
extracters/ods2/fibdef.h
Normal 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
896
extracters/ods2/ods2.c
Normal 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
895
extracters/ods2/ods2.c.bak
Normal 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
44
extracters/ods2/phyio.h
Normal 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
517
extracters/ods2/phynt.c
Normal 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,
|
||||
®,sizeof(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,
|
||||
®,sizeof(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,
|
||||
®,sizeof(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,§buff)) & 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
210
extracters/ods2/phyos2.c
Normal 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
87
extracters/ods2/phyvms.c
Normal 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
1049
extracters/ods2/rms.c
Normal file
File diff suppressed because it is too large
Load Diff
229
extracters/ods2/rms.h
Normal file
229
extracters/ods2/rms.h
Normal 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
48
extracters/ods2/ssdef.h
Normal 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
754
extracters/ods2/vmstime.c
Normal 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
52
extracters/ods2/vmstime.h
Normal 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
184
extracters/tpdump.c
Normal 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 );
|
||||
}
|
||||
}
|
||||
350
ods2_readme.txt
350
ods2_readme.txt
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user