Files
open-simh.simtools/extracters/rstsflx/filename.c
Paul Koning bf7c17ab4a Add RSTSFLX V2.6. This is a file system access utility for RSTS
file systems.  It supports reading and writing as well as a number
of other operations, such as octal dump, file system initialize,
and file system check ("clean").

This was originally maintained as a Subversion repository at
svn://akdesign.dyndns.org/flx/branches/V2.6.
as suggested by Timothe Litt on the SIMH mailing list.
2016-04-27 15:00:42 -04:00

310 lines
7.9 KiB
C

/* subroutines to handle rsts file name conversion and file spec parse */
#include <ctype.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include "flx.h"
#include "filename.h"
#include "fldef.h"
#define isr50(c) (isalnum (c) || (c) == ' ' || (c) == '?' || (c) == '*')
const char *parsename (const char *p, firqb *out) /* parse the name part of a spec */
{
int n;
for (n = 0; n < 6; n++) out->name[n] = ' ';
out->name[6] = '\0'; /* put in terminator */
if (isr50(*p)) { /* name present */
n = 0;
while (isr50(*p)) {
if (*p == ' ') { /* skip blanks */
p++;
continue;
}
out->flags |= f_name;
if (*p == '*') {
if (n < 6) {
out->name[n++] = '?';
out->flags |= f_namw;
} else p++;
} else {
if (n < 6) out->name[n++] = tolower (*p);
if (*p++ == '?') out->flags |= f_namw;
}
}
}
return (p);
}
const char *parsenameext (const char *p, firqb *out) /* parse the name.ext part of a spec */
{
int n;
for (n = 0; n < NAMELEN - 1; n++) out->name[n] = ' ';
p = parsename (p, out); /* parse the name part */
out->name[6] = '.';
out->name[NAMELEN - 1] = '\0'; /* put in terminator */
if (*p == '.') { /* extension present */
p++;
out->flags |= f_ext;
if (isr50(*p)) {
n = 0;
while (isr50(*p)) {
if (*p == ' ') { /* skip blanks */
p++;
continue;
}
if (*p == '*') {
if (n < 3) {
out->name[7 + n++] = '?';
out->flags |= f_extw;
} else p++;
} else {
if (n < 3) out->name[7 + n++] = tolower (*p);
if (*p++ == '?') out->flags |= f_extw;
}
}
}
}
return (p);
}
int parse (const char *p, firqb *out) /* returns FALSE if error, TRUE if ok */
{
char *pp;
out->proj = 0;
out->prog = 0;
out->flags = 0;
if (*p == '[' || *p == '(' || *p == '/') { /* PPN first */
p++;
out->flags |= f_ppn; /* flag PPN present */
if (*p == '*') { /* wild proj */
p++;
out->proj = 255;
out->flags |= f_ppnw;
} else {
out->proj = strtoul (p, &pp, 10);
if (pp == p || out->proj > 254) return (FALSE);
p = pp;
}
if (*p != ',' && *p != '/') return (FALSE);
p++;
if (*p == '*') { /* wild prog */
p++;
out->prog = 255;
out->flags |= f_ppnw;
} else {
out->prog = strtoul (p, &pp, 10);
if (pp == p || out->prog > 254) return (FALSE);
p = pp;
}
if (out->proj == 0 && out->prog == 0) return (FALSE);
if (*p != ']' && *p != ')' &&
*p != '/' && *p != '\0') return (FALSE);
if (*p != '\0') p++;
} else switch (*p) { /* see if special PPN char */
case '$':
out->proj = 1; /* supply [1,2] */
out->prog = 2;
out->flags |= f_ppn; /* indicate PPN present */
p++; /* skip that char */
break;
case '!':
out->proj = 1; /* supply [1,3] */
out->prog = 3;
out->flags |= f_ppn; /* indicate PPN present */
p++; /* skip that char */
break;
case '%':
out->proj = 1; /* supply [1,4] */
out->prog = 4;
out->flags |= f_ppn; /* indicate PPN present */
p++; /* skip that char */
break;
case '&':
out->proj = 1; /* supply [1,5] */
out->prog = 5;
out->flags |= f_ppn; /* indicate PPN present */
p++; /* skip that char */
break;
default: /* no PPN supplied */
out->proj = 1; /* supply default of [1,2] */
out->prog = 2; /* don't set f_ppn flag */
}
p = parsenameext (p, out);
if (*p == '<') { /* protection code present */
p++;
out->flags |= f_prot;
out->newprot = strtoul (p, &pp, 10);
if (pp == p) return (FALSE);
p = pp;
if (*p++ != '>') return (FALSE);
}
return (*p == '\0'); /* success if all was parsed */
}
static const char r50table[] = " abcdefghijklmnopqrstuvwxyz$.?0123456789:";
char *r50toascii (word16 r50, char *string, int space)
{
int t, c, pos;
pos = 03100;
for (t = 0; t<3; t++) {
c = r50 / pos;
if (c || space) *string++ = r50table[c];
r50 %= pos;
pos /= 050;
}
*string = '\0'; /* put in string terminator */
return (string);
}
char *r50toascii2 (word16 r50[], char *string, int space)
{
string = r50toascii (r50[0], string, space);
return (r50toascii (r50[1], string, space));
}
void r50filename (word16 r50[], char *name, int space)
{
name = r50toascii2 (r50, name, space);
*name++ = '.';
name = r50toascii (r50[2], name, space);
}
void printfqbppn (const firqb *f)
{
if (f->proj == 255) printf ("[*,");
else printf ("[%d,", f->proj);
if (f->prog == 255) printf ("*]");
else printf ("%d]", f->prog);
}
void printfqbname (const firqb *f)
{
int n;
printfqbppn (f);
for (n = 0; n < NAMELEN - 1; n++)
if (f->name[n] != ' ') putchar (f->name[n]);
}
void printcurname (const firqb *f)
{
if (f->stat & us_ufd)
{
if (f->cproj == 255)
printf ("[*,*]");
else if (f->cprog == 255)
printf ("[%d,*]", f->cproj);
else printf ("[%d,%d]", f->cproj, f->cprog);
}
else printf ("[%d,%d]%s", f->cproj, f->cprog, f->cname);
}
/* merge a native (unix or dos) input filespec or RSTS name.ext with a
* (possibly wild) rsts output file spec to produce the specific output
* filename as a 3-word rad50 value. If the third argument is TRUE, then
* the last directory element in the input filename path must be numeric,
* and is used to set the current PPN fields in the output FIRQB.
*/
void mergename (char *iname, firqb *oname, int tree)
{
int n, spflag;
firqb inf;
char c;
char *in1, *in2;
char tname[FILENAME_MAX];
int ppn;
if ((in1 = strrchr (iname, '/')) != NULL) in1++;
else in1 = iname;
if ((in2 = strrchr (in1, '\\')) != NULL) in1 = in2 + 1;
inf.flags = 0; /* clear parse flags */
if (*(parsenameext (in1, &inf)) != '\0' /* see if we can parse that */
|| (inf.flags & F_WILD)) /* it should not have * or ? */
memcpy (inf.name, "xxxxxx.xxx", NAMELEN); /* use xxx if bad name */
oname->cname[6] = '.'; /* make sure . is in */
spflag = FALSE; /* no spaces yet */
for (n = 0; n < NAMELEN - 1; n++) {
if (n == 6) {
spflag = FALSE; /* no spaces yet in ext */
continue; /* skip the '.' separator */
}
c = oname->name[n]; /* start with output spec */
if (c == '?' && !spflag)
c = inf.name[n]; /* use input if output wild */
if (c == ' ') spflag = TRUE; /* stop if we find a space */
if (spflag) c = ' '; /* force spaces after space */
oname->cname[n] = c; /* store result */
}
oname->cname[NAMELEN - 1] = '\0'; /* ensure terminator */
if (tree) {
n = in1 - iname; /* get offset to name part */
if (n) n--; /* now to the / */
else {
oname->cproj = oname->cprog = 0; /* can't set PPN from iname */
return;
}
strcpy (tname, iname); /* copy the name */
tname[n] = '\0'; /* chop off directory part */
if ((in1 = strrchr (tname, '/')) != NULL) in1++;
else in1 = tname;
if ((in2 = strrchr (in1, '\\')) != NULL) in1 = in2 + 1;
ppn = strtoul (in1, &in2, 10); /* convert to decimal */
if (*in2 != '\0') ppn = 0; /* check for error */
if (oname->proj == 255) {
if (strlen (in1) < 4) ppn = 0;
oname->cproj = ppn / 1000; /* proj = first digits */
} else oname->cproj = oname->proj;
if (oname->prog == 255)
oname->cprog = ppn % 1000;
else oname->cprog = oname->prog;
if (oname->cproj > 254 || oname->cprog > 254)
oname->cproj = oname->cprog = 0;
}
return;
}
/* routines to convert ascii names to rad50. These assume that the name
* is valid rad50, i.e., letters and digits only. Special case: for the
* parsing of RTS names, '.' is also accepted as a rad50 character.
* Any non-rad50 character is treated as space, i.e., rad50 0.
*/
word cvtr50 (const char *in)
{
int mul, r50, n;
for (r50 = 0, mul = 03100, n = 0; n < 3; in++, mul /= 050, n++) {
if (isdigit (*in)) r50 += (*in - '0' + 036) * mul;
else if (isalpha (*in)) r50 += (tolower (*in) - 'a' + 001) * mul;
else if (*in == '.') r50 += 034 * mul;
}
return (r50);
}
/* convert 6-character name */
void cvtnametor50 (const char *in, word16 *out)
{
out[0] = cvtr50 (in);
out[1] = cvtr50 (in + 3);
}
/* convert name.ext */
void cvtnameexttor50 (const char *in, word16 *out)
{
cvtnametor50 (in, out);
out[2] = cvtr50 (in + 7); /* skip the "." */
}