/* MYLIB.C Generic Library Functions */
/* Public Domain -- Gregg Jennings 1989-1995 */
/* This source file may be freely used and distributed without restriction. */
#include <stdio.h>
#include <ctype.h>
#include <conio.h>
#include <string.h>
#include <dos.h>
#include "mylib.h"
#include "console.h" /* for console I/O (my print() etc.) */
/*
The following are for DISKED use. The #ifdefs are for
marking the DISKED specific code. These Should be removed
for general usage.
*/
#ifdef DISKED
#include "disked.h"
static void displval(int x, int base, int c);
static int getlnum(unsigned int max, unsigned *num, int base);
#endif
#define _tohex(c) ( (c<='9') ? (c-'0') : (c-'7') )
/*
Convert two ASCII hex-valid chars to one hex number.
A '0' and a 'd' returns the value 0x0d. The second
argument can be a '\r'.
No checking for validity.
ver 1.1 9/91 fixed ascii mask error, added _tohex() macro
ver 1.0 12/90
*/
unsigned char hexbyte(register int a,register int b)
{
a=toupper(a);
b=toupper(b);
if (b=='\r') { /* swap if '\r' */
b=a;
a='0';
}
return((unsigned char)((_tohex(a)*16)+_tohex(b)));
}
/*
* Display a number to the console with leading zeros or space
* and a certain length, and any base from 2 to 36.
*
* pn print int number
* pln print long number
*
* Returns: number of digits.
*
* ver 1.0 9/91 eliminated all but 2 divisions pln(), 3 in pn()
* ver 0.1 12/90
*/
int pn(unsigned int n, int base)
{
int r=1;
int i;
if (n/base)
r+=pn(n/base,base);
i=n%base;
output((i>9) ? i+'A'-10 : i+'0');
return(r);
}
int pln(unsigned long n, int base)
{
int r=1;
long l;
int i;
if (((l=n/(long)base))>0)
r+=pln(l,base);
i=(int)(n%(long)base);
if (i>9)
output(i+'A'-10);
else
output(i+'0');
return(r);
}
/*
* Display a number to the console with leading zeros or space
* and a certain length, and any base from 2 to 36.
*
* pnlz print number leading zero
* pnls print number leading space
* plnlz print long number leading zero
* plnls print long number leading space
*
* ver 1.0 9/91
*/
void pnlz(unsigned int n, unsigned int length, int base)
{
register int t;
for (t=length-getlen(n,base);t>0;t--)
output('0');
pn(n,base);
}
void pnls(unsigned int n, unsigned int length, int base)
{
register int t;
for (t=length-getlen(n,base);t>0;t--)
output(' ');
pn(n,base);
}
void plnlz(unsigned long n, unsigned int length, int base)
{
register int i;
for (i=length-getlength(n,base);i>0;i--)
output('0');
pln(n,base);
}
void plnls(unsigned long n, unsigned int length, int base)
{
register int i;
for (i=length-getlength(n,base);i>0;i--)
output(' ');
pln(n,base);
}
/*
* get the display length (number of digits) of a
* number, i.e. 100 dec returns 3, 64 hex (100 dec)
* returns 2
*/
int getlen(register unsigned int n, register int base)
{
int j;
for (j = 1; n >= (unsigned int)base; n /= base,++j)
;
return(j);
}
/*
Get length of number.
Pass: long number, int base (1 to 26).
Returns: the number of digits the number needs to be displayed.
ver 0.1 12/90
ver 0.2 3/91 changed to long
*/
int getlength(unsigned long l, int base)
{
register int r;
for (r=1;l>=(unsigned long)base;l/=(long)base,++r)
;
return(r);
}
/*
Convert a string containing escape sequences
to their correct values.
Returns: the converted string's length.
ver 1.1 9/91 changed \x to fixed 2 chars (\x0d not \xd)
ver 1.0 3/91
ver 0.1 12/90
*/
int convert(register char *a)
{
register char *s;
int j;
s=a;
for (j=0;*a!='\0';a++,j++) {
if (*a=='\\') {
switch (*++a) {
case 'x':
*(s+j)=hexbyte(*(a+1),*(a+2));
a+=2;
break;
case 'a':
*(s+j)='\a';
break;
case 'b':
*(s+j)='\b';
break;
case 'f':
*(s+j)='\f';
break;
case 'n':
*(s+j)='\n';
break;
case 'r':
*(s+j)='\r';
break;
case 't':
*(s+j)='\t';
break;
case 'v':
*(s+j)='\v';
break;
case '0':
*(s+j)='\0';
break;
case '\\':
*(s+j)='\\';
break;
default:
break;
}
}
else
*(s+j)=*a;
}
*(s+j)='\0';
a=s;
return(j);
}
/*
Display the current directory in a combination DIR /P /W
format.
ver 0.3 9/91 call to lpd()
ver 0.2 3/91
*/
#ifdef DISKED
extern unsigned int disk;
extern unsigned avail_clusters;
extern unsigned secs_cluster;
extern unsigned sec_size;
#endif
void directory(void)
{
int files=0;
struct _find_t file;
struct _diskfree_t ds;
long dsize,fsize = 0L;
output('\n');
if (_dos_findfirst("*.*",0x3f,&file)==0)
{
do
{
pname(file.name);
print(" ");
if (file.attrib&_A_SUBDIR)
print(" <DIR>");
else if (file.attrib&_A_VOLID)
print(" <VOL>");
else
{
plnls(file.size,7,10);
fsize+=file.size;
}
++files;
print((files%3==0) ? "\n" : " ");
if (files%60==0)
pause();
} while (_dos_findnext(&file)==0); /* while being found*/
}
if (files==0)
print("no files");
output('\n');
#ifdef DISKED
if (avail_clusters==0)
{
_dos_getdiskfree(disk,&ds);
dsize = ((long)ds.avail_clusters*(long)ds.sectors_per_cluster*(long)ds.bytes_per_sector);
}
else
dsize = ((long)avail_clusters*(long)secs_cluster*(long)sec_size);
#else
{
unsigned disk;
_dos_getdrive(&disk);
_dos_getdiskfree(disk,&ds);
dsize = ((long)ds.avail_clusters*(long)ds.sectors_per_cluster*(long)ds.bytes_per_sector);
}
#endif
print(" file space %ld, disk space %ld\n",fsize,dsize);
}
/*
Displays the filename returned by _dos_findnext() in a nice
format.
ver 0.2 3/91
*/
void pname(char *s)
{
register int i;
register int j;
i=0;
output(' ');
while (s[i]!='.' && s[i]!='\0')
output(s[i++]);
j= (s[i]!='\0') ? i+1 : i;
while (i++<8)
output(' ');
if (s[j])
output('.');
else
output(' ');
while (i++<=11)
output( (s[j]=='\0') ? ' ' : s[j++]);
}
/*
Modified K&R index() for a non-null terminated string.
ver 0.1 12/90
*/
int search(unsigned char *s,unsigned char *t,size_t size, size_t len)
{
unsigned int i;
register unsigned int j,k;
if (size>len) {
size-=len;
for (i=0;i<=size;i++) {
for (j=i,k=0;k<len && s[j]==t[k];j++,k++)
continue;
if (k==len)
return(i);
}
}
return(-1);
}
/* case-insensitive search 11-93 */
int isearch(unsigned char *s,unsigned char *t, size_t size, size_t len)
{
unsigned int i;
register size_t j,k;
if (size > len)
{
size-=len;
for (i=0;i <= size;i++)
{
for (j=i,k=0;k<len && (s[j]==t[k] || toupper(s[j]) == toupper(t[k]));j++,k++)
continue;
if (k==len)
return(i);
}
}
return(-1);
}
/*
Display a string with a question mark and return TRUE if a 'y'
is found on console, else return FALSE.
mode: 0 no mov/clr
(bit) 1 cursor back to "Yes/No "
2 cursor back to arg s
4 clreol if "Yes"
ver 0.3 9/93 added cursor, clreol
ver 0.2 3/91
ver 0.1 12/91
*/
int getver(register char *s,int mode)
{
int c;
if (mode&2) /* mov arg */
savecursor();
print(s);
output('?');
output(' ');
if (mode&1) /* mov yn */
savecursor();
c=input();
if (tolower(c)!='y')
{
print("No ");
c = 0;
if (mode)
restcursor();
}
else
{
print("Yes");
c = 1;
if (mode)
restcursor();
if (mode&4)
clreol();
}
return c;
}
/*
Get number from console by calling getstr() and sscanf().
Handles base of 10 or 16 only.
Pass: long maximum number, pointer to number, int base (1 to 26).
Returns: TRUE (1) if number okay
FALSE (0) if no entry
ERROR (-1) if too big a number
ABORT (-2) on ESC or ^C
Calls: getstr()
ver 0.1 12/90
ver 1.0 2/91 pass pointer
*/
int getnumber(unsigned long max, void *num, int base)
{
char tmpstr[11]; /* longest number is unsigned long of 10 digits */
char form[4]; /* format string for sscanf() */
int i;
unsigned long l;
long *pl=num; /* make sure we have enough space */
i=0;
form[i++]='%';
form[i++]='l';
(base==10) ? (form[i]='d') : (form[i]='x');
form[++i]='\0';
i=getstr(tmpstr,getlength(max,base),(base==10)?_DIGIT:_HEX);
if (i<0)
{
if (i==ERROR)
i=0;
return(i);
}
sscanf(tmpstr,form,&l);
if (l>max)
return(ERROR);
*pl=l;
return(TRUE);
}
int getnum(unsigned int max, unsigned *num, int base)
{
char tmpstr[7]; /* longest number is unsigned 6 digits */
char form[3]; /* format string for sscanf() */
int i;
unsigned int u;
unsigned int *pu=num; /* make sure we have enough space */
i = 0;
form[i++] = '%';
(base == 10) ? (form[i] = 'u') : (form[i] = 'x');
form[++i] = '\0';
i = getstr(tmpstr,getlen(max,base),(base == 10) ? _DIGIT : _HEX);
if (i < 0)
{
if (i == ERROR)
i = 0;
return i;
}
sscanf(tmpstr,form,&u);
if (u > max)
return ERROR;
*pu = u;
return TRUE;
}
/*
Get a string from console, masking to hex or decimal
numbers only or punctuation, depending on the mask value,
with CP/M editing control keys.
Pass: pointer to string, int max length, int mask.
Returns: -2 on ESC or ^C
-1 on no input ('\r')
-3 on no input (space or ',')
ver 1.1 17-Mar-1994 better input type checking
ver 1.0 9/93 added -3 return
ver 0.1 12/90
*/
int getstr(char *s,unsigned int len,int mask)
{
register unsigned int i;
register int c = 0;
savecursor();
for (i = 0; i < len; )
{
switch (c = input())
{
case '\b':
if (i)
{
output(c);
output(' ');
output(c);
--i;
}
break;
case 'U'-'@': /* ^U to delete */
if (i)
{
restcursor();
clreol();
i = 0;
}
break;
case 0x1b: /* ESC to abort */
case 'C'-'@': /* ^C */
i = 0;
goto end_input; /* goto's!?!?!? -- Yeah! They work! */
case ',':
if (mask & _PUNCT)
goto use_it;
else
goto end_input;
case ' ':
if (mask & _BLANK)
goto use_it;
else
goto end_input;
case '\r': /* end of input */
goto end_input;
default:
use_it:
if (mask == _DIGIT && (!isdigit(c)))
continue;
if (mask == _HEX && (!isxdigit(c)))
continue;
if (!(mask & _CONTROL) && iscntrl(c))
continue;
output(c); /* save and echo numbers */
s[i++] = (char)c;
break;
}
}
end_input:
s[i] = '\0';
if (!i)
return (c=='\r') ? ERROR : -3;
return i;
}
/***
* Edit a buffer, in a debugger type format. Asks for the starting
* point of the editing. Checks for end of buffer and wraps around.
* Allows hex and ASCII substitutions, jumps to a buffer location, and
* hex number fills.
*
* A complicated, horrible looking function but it works.
*
* Uses getnum(), bdos(), hexbyte(), dispval() and <ctype.h>.
*
* 1.1 23-Mar-1995 fixed '=' test of > bufend ( >= !)
* 1.0 15-Mar-1995 restructured (tabs and whitespsace)
* changes for file tracking (getlnum(), displval())
*
* GAJ initial
* GAJ added ASCII subs
* GAJ 1-8-89 added ^x
* GAJ 1-9-89 added \c
* GAJ 3-8-89 updated help
* GAJ 12-8-90 cleaned up
****/
int change(register unsigned char *buffer, unsigned int bufend, int base)
{
unsigned int a;
unsigned int b;
int c; /* chars gotten from the console */
unsigned int n,i; /* x = buffer index, n = getval, i = general purpose*/
register unsigned int x;
int inquote,ad; /* for inputing a string */
int l;
char t[66];
if (bufend <= 0)
return 0;
n = 0;
#ifdef DISKED
if (ft_track)
i = getlnum(bufend,&n,base);
else
#endif
i = getnum(bufend,&n,base);
if (i == ABORT)
return 0;
ad = getlen(bufend,base);
x = n;
inquote = FALSE;
output('\n');
for (;;)
{
c = buffer[x];
#ifdef DISKED
if (ft_track)
displval(x,base,c);
else
#endif
dispval(x,ad,base,c); /* display address, byte, and ASCII */
if (!inquote)
a = input()&0xff;
if (a=='\\') /* search */
{
output(a); /* echo */
a = input()&0xff; /* get */
if (a=='^') /* control */
{
output(a); /* echo */
b = input()&0xff; /* get */
if (isalpha(b)) /* letter */
{
a = toupper(b); /* upper */
output(a); /* echo */
c = (a-'@'); /* convert */
}
else continue; /* else redo */
}
else if (a == '\'') /* get ASCII */
{
output(a);
b = input()&0xff;
if (b >= ' ') /* is okay? */
{
output(b); /* echo */
c = b; /* set */
}
else continue; /* else redo */
}
else if (isxdigit(a)) /* get hex */
{
output(a);
b = input()&0xff; /* get second */
if (isxdigit(b) || b == '\r')
{
if (b != '\r')
output(b);
c = hexbyte(a,b); /* convert */
}
else continue;
}
/* search loop */
i = x; /* save place */
while (c != (int)buffer[++x])
{
if (x == bufend) /* wrap at end */
x = 0;
if (x == i) /* stop */
break;
}
continue;
}
else if (a == '\"') /* get string */
{
output(a);
inquote = FALSE; /* bool for continuing */
if ((l = getstr(t,63,_TEXT)) > 0)
{
for (i = 0; i < (unsigned)l; i++)/* copy string */
{
buffer[x++] = t[i];
if (x == bufend) /* wrap around */
x = 0;
}
}
else continue;
if (l == 63)
inquote = TRUE;
continue;
}
else if (a == '^') /* get control */
{
output(a);
b = input()&0xff;
if (isalpha(b))
{
b = toupper(b);
output(b);
buffer[x] = (char)(b-'@');
}
else continue;
}
else if (a == '\'') /* get ASCII */
{
output(a);
b = input()&0xff;
if (b >= ' ') /* is okay? */
{
output(b); /* yes, display and set */
buffer[x] = (char)b;
}
else continue;
}
else if (a == '=') /* jump to addr */
{
output(a);
#ifdef DISKED
if (ft_track)
i = getlnum(bufend,&n,base);
else
#endif
i = getnum(bufend,&n,base);
if (i < 1)
continue;
if (n >= bufend)
continue;
x = n;
continue;
}
else if (a == '\r' || a == ' ') /* go to next */
;
else if (a == '\t') /* goto 0000: */
{
x = 0;
continue;
}
else if (a == '.' || a == ESC) /* exit */
break;
else if (a == '\b') /* go to previous */
{
if (--x == 0xffff)
{
x = (bufend-1); /* if end, wrap */
output('\n');
}
continue;
}
else if (a=='/' || a=='?')
{
print("\n\n\txx enter hex value xx");
print("\n\t'c enter ASCII char c");
print("\n\t^c enter control char c");
print("\n\t\"s enter string s");
print("\n\tCR/SP next location");
print("\n\tBS previous location");
print("\n\tTAB goto location 00");
print("\n\t=n goto location n");
print("\n\t\\xx goto hex value xx");
print("\n\t\\\'c goto char c");
print("\n\t\\^c goto control char c");
print("\n\t-x1,x2 write x1, x2 times");
print("\n\t+x1,x2 replace all x1, with x2");
print("\n\t.|ESC end\n");
continue;
}
else if (a == '-') /* fill */
{
output(a);
if (getnum(0xff,&a,16) < 1)
continue;
output(',');
if (getnum(bufend,&b,16) < 1) /* get second byte */
continue;
n = x; /* save position */
for (i = 0; i < b; i++) /* all okay, fill it */
{
buffer[x] = (char)a;
if (++x == bufend) /* wrap around at end */
x = 0;
}
x = n; /* restore position */
continue;
}
else if (a == '+') /* fill */
{
output(a);
if (getnum(0xff,&a,16) < 1) /* get first byte */
continue;
output(',');
if (getnum(0xff,&b,16) < 1) /* get second byte */
continue;
if (a==b)
continue;
for (i = 0; i < bufend; i++) /* all okay, fill it */
{
if (buffer[i] == (unsigned char)a)
buffer[i] = (unsigned char)b;
}
continue;
}
else if (isxdigit(a))
{
output(a);
b = input()&0xff; /* get second */
if (isxdigit(b) || b == '\r')
{
if (b != '\r')
output(b);
buffer[x] = hexbyte(a,b); /* convert */
}
else continue;
}
else continue;
if (++x == bufend) /* increment pointer, wrap if end */
{
x = 0;
output('\n');
}
}
output('\n');
return 1;
}
void dispval(int x, int len, int base, int c)
{
output('\n');
pnlz(x,len,base);
output(':');
output(' ');
pnlz(c,2,16);
output(' ');
if (isprint(c)) {
output('\'');
output(c);
output('\'');
}
else if (iscntrl(c)) {
output('^');
output(c+'@');
output(' ');
}
else
put(3,' ');
put(2,' ');
}
#ifdef DISKED
static void displval(int x, int base, int c)
{
long l = filebytes();
if (base == 10)
print("\n%08ld: ",(long)x + l);
else
print("\n%06lx: ",(long)x + l);
print("%02x ",c);
if (isprint(c))
print("'%c' ",c);
else if (iscntrl(c))
print("^%c ",c+'@');
else
print(" ");
}
static int getlnum(unsigned int max, unsigned *num, int base)
{
int i;
long n,l = filebytes();
n = 0L;
if ((i = getnumber(l + max,&n,base)) > 0)
{
if (n < l)
*num = 0;
else
*num = (int)(n - l);
}
return i;
}
#endif
void pause(void)
{
savecursor();
print("<more>");
input();
restcursor();
clreol();
}
/* view file to screen */
void viewfile(char *filename, int display)
{
char buf[255];
FILE *fh;
int i = 1;
if (stricmp(filename,"none") == 0 || filename[0] == '\0')
return;
if ((fh = fopen(filename,"r")) == NULL)
{
perror(filename);
return;
}
if (display)
print(" %s File Contents:\n",filename);
output('\n');
while (!feof(fh))
{
if (fgets(buf,255,fh) == NULL)
break;
print(buf);
if (++i == 23)
{
print("<more>\r");
i = input();
if (i == 0)
input();
print(" \r");
if (i == ESC)
break;
else
i = 0;
}
}
fclose(fh);
}