1
0
mirror of https://github.com/prirun/p50em.git synced 2026-01-11 23:42:56 +00:00
prirun.p50em/util/istext.c

307 lines
7.9 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* this function decides if this is a Prime text file or binary file
by checking the contents of the first tape buffer. The conditions
for a text file are:
- it can't be inside a segdir (checked before calling here)
- it has to be a SAM or DAM file - COMO files are DAM files :(
- it has to have at least 1 newline in the first buffer, usually
4090+ bytes; text files with an initial line longer than this have
to be converted after the restore using ptextu
- lines have to start on word boundaries, with zero padding after nl
(NOTE: como files have space padding, so allow that too)
- only text characters, nl, ff, :001 at the beginning of a line,
:221 (compression) and :211 (tab) are allowed in text files
*/
/* max length of extension including . and ending null byte */
#define MAXEXTENSION 10
static struct {
char ext[MAXEXTENSION];
int ftype;
} exttype[] = {
{".basic", 1},
{".cbl", 1},
{".c", 1},
{".cc", 1},
{".ci", 1},
{".cobol", 1},
{".comi", 1},
{".como", 1},
{".cpl", 1},
{".f77", 1},
{".ftn", 1},
{".ibas", 1},
{".ins", 1},
{".list", 1},
{".map", 1},
{".mod", 1},
{".pascal", 1},
{".plp", 1},
{".pl1", 1},
{".pl1g", 1},
{".pma", 1},
{".rpg", 1},
{".runi", 1},
{".runo", 1},
{".spl", 1},
{".sr", 1},
{".vrpg", 1},
{".bin", 0},
{".dl", 0},
{".save", 0},
};
#define EXTENTRIES sizeof(exttype)/sizeof(exttype[0])
int isptext(char *path, int filetype, unsigned char *buf, int len) {
int i, hasnl, skipline;
unsigned char ch;
unsigned char extension[MAXEXTENSION];
/* scan backward to get file extension */
extension[0] = 0;
for (i=strlen(path)-1; i >= 0; i--)
if (path[i] == '.') {
strncpy(extension, path+i, sizeof(extension)-1);
break;
}
if (extension[0] == '.')
for (i=0; i < EXTENTRIES; i++)
if (strcasecmp(extension, exttype[i].ext) == 0)
return exttype[i].ftype;
if (filetype == 0 || (filetype == 1 && strcasecmp(extension,".como") == 0))
;
else {
#ifdef DEBUG
fprintf(stderr, "Filetype %d can't be a text file\n", filetype);
#endif
return 0;
}
hasnl = 0;
skipline = 0;
for (i=0; i<len; i++) {
ch = buf[i];
if (ch == 0212) {
skipline = 0;
hasnl = 1;
if ((i&1) == 0) /* nl is in the left byte */
if (buf[++i] != 0 && buf[i] != 0240)
return 0; /* unusual padding = not a text file */
} else if (skipline) /* skipping this line? */
continue;
else if (ch == 0221) /* space compression */
i++; /* skip the compression count */
else if (ch == 0001) /* spooler pagination control lines; skip 'em */
skipline = 1;
else if ((ch & 0x7f) == 014 || ch == 0211 || (0240 <= ch /* && ch <= 0377 */))
;
else {
#ifdef DEBUG
fprintf(stderr,"Character %o at position %d kept this from being a text file.\n", ch, i);
#endif
return 0;
}
}
return hasnl; /* buffer has to contain a newline to be a text file */
}
/* writes a buffer of Prime text, converting it to Unix text. The
2-character space compression sequences may cross buffers; "state"
is used to track this:
state=0 means no compression pending
state=1 means the next buffer character is the compression count
Before calling convtext for a new file, state must be initialized
to zero in the caller, then left alone after that.
*/
int ptextu(int fd, unsigned char *buf, int len, int *state) {
int i, n;
unsigned char ch;
/* NOTE: one interation through the text conversion loop could add up
to 255 spaces because of text compression, so some slop is added
to the size of the output buffer in the declaration */
#define OBUFMAX 4096
unsigned char obuf[OBUFMAX+256];
n = 0; /* next output buffer postion */
for (i=0; i<len; i++) {
ch = buf[i];
if (*state == 1) { /* expand spaces */
while (ch--)
obuf[n++] = ' ';
*state = 0;
} else if (ch == 0221) /* start of compression sequence */
*state = 1;
else {
obuf[n++] = (ch & 0x7f);
if (ch == 0212 && (i&1) == 0)
i++;
}
if (n >= OBUFMAX) {
if (fd != -1)
if (write(fd, obuf, n) != n) {
fprintf(stderr,"File write error text conversion, n=%d\n", n);
exit(1);
}
n = 0;
}
}
if (n > 0 && fd != -1 && write(fd, obuf, n) != n) {
fprintf(stderr,"File write error text conversion, n=%d\n", n);
exit(1);
}
return len;
}
/* scans buffer contents to see if it qualifies as a Unix text file that
should be converted to Prime text. Text files can only have:
- printable ASCII characters
- tab
- newline
- carriage return
- form feed
*/
int isutext(char *path, unsigned char *buf, int len) {
int i, hasnl, skipline;
unsigned char ch;
unsigned char extension[MAXEXTENSION];
/* scan backward to get file extension */
extension[0] = 0;
for (i=strlen(path)-1; i >= 0; i--)
if (path[i] == '.') {
strncpy(extension, path+i, sizeof(extension)-1);
break;
}
if (extension[0] == '.')
for (i=0; i < EXTENTRIES; i++)
if (strcasecmp(extension, exttype[i].ext) == 0)
return exttype[i].ftype;
/* extension didn't determine type; check file contents */
hasnl = 0;
for (i=0; i<len; i++) {
ch = buf[i];
if (ch == '\n') {
skipline = 0;
hasnl = 1;
} else if (skipline) /* skipping this line? */
continue;
else if (ch == '\f' || ch == '\t' || ch == '\r' || (040 <= ch && ch <= 0177 ))
;
else {
#ifdef DEBUG
fprintf(stderr,"Character %o at position %d kept this from being a text file.\n", ch, i);
#endif
return 0;
}
}
return hasnl; /* buffer has to contain a newline to be a text file */
}
#if 0
/* writes a buffer of Unix or Windows text, converting it to Prime
uncompressed text.
The state argument is a structure that needs to be initialized
before each new file:
state->oddbyte = 0;
state->col = 0;
state->spaces = 0;
It's possible that a string of spaces could be lost at the end of
the file, but this is very unlikely since text files are supposed
to end with a newline.
*/
int utextp(unsigned char *buf, int len, utextp_t *state) {
int i, n, nsp;
unsigned char ch;
n = 0; /* next output buffer position */
for (i=0; i<len; i++) {
ch = buf[i];
if (ch == ' ')
state->spaces++;
else if (ch == '\t') {
nsp = 8 - (state->col & 7);
state->spaces += nsp;
state->col += nsp;
} else {
while (state->spaces) { /* dump held-up spaces for non-space */
if (state->spaces < 3) {
state->obuf[n++] = 0240;
state->spaces--;
state->oddbyte = ~state->oddbyte;
} else {
nsp = state->spaces;
if (nsp > 255) /* can only handle 255 at once! */
nsp = 255;
state->obuf[n++] = 0221;
state->obuf[n++] = nsp;
state->spaces = state->spaces - nsp;
}
}
if (ch == '\r') /* ignore carriage returns (Windoze) */
continue;
state->obuf[n++] = ch | 0x80;
if (ch == 0212 && !state->oddbyte)
state->obuf[n++] = 0; /* pad line to a word boundary */
else
state->oddbyte = ~state->oddbyte;
}
if (n >= OBUFMAX) {
if (fd != -1)
if (write(fd, state->obuf, n) != n) {
fprintf(stderr,"File write error text conversion, n=%d\n", n);
exit(1);
}
n = 0;
}
}
if (n > 0 && fd != -1 && write(fd, state->obuf, n) != n) {
fprintf(stderr,"File write error text conversion, n=%d\n", n);
exit(1);
}
return len;
}
#endif
/* converts a fixed-length string in place from Prime to regular ascii */
void pasciiu(char *p, int len) {
int i;
for (i=0; i<len; i++)
p[i] &= 0x7f;
}
/* converts a fixed-length string in place from regular to Prime ascii */
void uasciip(char *p, int len) {
int i;
for (i=0; i<len; i++)
p[i] |= 0x80;
}