Metropoli BBS
VIEWER: mylib.c MODE: TEXT (ASCII)
/* 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);
}
[ RETURN TO DIRECTORY ]