
/*                            FindDisk3.3

     Author      : Ross MacGregor
     Date        : 10/04/88
     Last Update : 23 Apr 91
     Comments    : This is a public domain program.


     DiskList stored in compacted form:

     below: { unskrunched } => { skrunched }
            [] is a byte of memory

     * compacts strings of spaces
         { [$20] [$20] [$20] [$20] [$20] } => { [SKRUNCHAR] [SKRUNOFFS 5] }
         { [$20] [$20] } => { [$20] [$20] }

     * the STARTSTR is compacted
         { STARTSTR } => { [STARTCHAR] }

*/

#include <functions.h>
#include <string.h>

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/libraries.h>
#include <exec/ports.h>
#include <exec/interrupts.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/filehandler.h>


#define DISP_LINES 23

#define CP_BUFF 10000L    /* Buffer size for the file copy function */

/* This indicates the start line of a dir listing, and
   it MUST have the name of the disk on the same line.  */

#define STARTSTR  "Directory of "

/* Special character used to compact the spaces in DiskList */
#define SKRUNCHAR 1
#define SKRUNOFFS 10

/* Special characters used to replace the STARTSTR & XnSTR in DiskList  */
#define STARTCHAR  2

/* Lines in the stored dir listing array */
#define NUMLINES 25

/* Max length of the lines read in */
#define LINELEN  170L
#define MAXBUF   169L

#define MAXPATHLEN 80

/*--------------------- Global Variables ------------------------*/

BPTR fdl, ftmp;
BPTR confh;

char *tempdl="ram:TempDL";

char *dltemp="ram:DiskList";
char *dldisk="FindDisk:DiskList";
char *sdir_pat="df0:";

char *outofmem="Out of Memory.";
char *cutoff=" - - (no more lines available) - - \n";

char dlpath[MAXPATHLEN+1];
char buffer[LINELEN];

/* finddisk uses this */
char dirlist[NUMLINES][LINELEN];

int con_print_line, last_startchar, disp_list;
char *errorstr;
char *nullstr="";

/* function error indicator */
int fcnerr;

/* global main arguments */
int glargc;
char **glargv;

extern char strbuf[];
extern int  subdir, shdsp;

/*------------ dynamic structure for coping DL to memory -------------*/

/* Blocks of memory for storing the disklist */
#define BLKSIZE 4096L

struct mem_block
{
  char buffer[BLKSIZE+1];
  struct mem_block *next;
};

struct mem_block *mem_blocks, *cur_mem_block;
char *mem_block_ptr;
int chrcount;
void init_bufblks(), free_bufblks();
int  write_bufblks(BPTR fd);

/*------------ dynamic structure for listing the volume names --------*/
/*                   used in recursive do_ls call also                */

struct disk
{
  char name[LINELEN];
  struct disk *next;
};
struct disk *firstdisk,*diskptr;

#define INIT_DISKNAMES firstdisk=diskptr=NULL
#define FREE_DISKNAMES free_disknames()

void free_disknames();

/*----------------------------------------------------------------------*/

char *mystrstr(), *strtoupper(), *getstr();

char *skrunch(), *getenv(), *firstchar();
void tocon(), unskrunch(), get_dlpath();
BPTR opendl(), opentmp();

char *strchr(), *malloc();

int update(), remove(), loaddl(), savedl(), sdir(), newdl();

void finddisk_free(), update_free(), remove_free(), ls_free();

char *getenv(fullpath,var)
  char *fullpath, *var;
{
  BPTR lock;
  BPTR fh;
  char *buffer;
  int  len;

  if( lock=Lock(fullpath,(long)ACCESS_READ) )
  {
    UnLock(lock);
    if( !(fh=Open(fullpath,(long)MODE_OLDFILE)) )
      return var;
    if( !(buffer=(char *)malloc(MAXPATHLEN+1)) )
    {
      errorstr=outofmem;
      Close(fh);
      return var;
    }
    len=Read(fh,buffer,(long)MAXPATHLEN);
    Close(fh);
    *(buffer+len)='\0';
    return buffer;
  }
  return var;
}

tmpsize()
{
  int size;
  if( !(ftmp=opentmp((long)MODE_OLDFILE)) )
  {
    errorstr=nullstr;
    return 0;
  }
  size=Read(ftmp,buffer,(long)MAXBUF);
  Close(ftmp);
  return size;
}

#define finddisk_cleanup(x) { finddisk_free(); return x; }
finddisk()
{
  int thisone=0, line=0;
  int i;

  if( !(fdl=opendl((long)MODE_OLDFILE)) )
    return 1;

  confh=0;

  /* Converts non-case sensitive keywords to upper case */
  for(i=1; i<glargc; i++)
    if( *glargv[i]!='!' )
      strtoupper(glargv[i]);

  con_print_line=0;
  disp_list=1;

  /* get line of DiskList */
  while( getstr(buffer,fdl)!=NULL && disp_list)
  {
    /* first checks for a startchar of a dirlist */
    if( strchr(buffer,(char)STARTCHAR) )
    {
       if( thisone )
       {
         last_startchar=con_print_line;
         if( printdir(&line) )
           finddisk_cleanup(1);
         thisone=0;
       }

       line=1;
    }


    if( line )
    {

       /* Copies the line in buffer to the stored dirlist */
       strcpy(dirlist[line-1],buffer);

       if( ++line > NUMLINES )
         line--;

       /* Checks for given keywords */
       if( thisone==0 )
         thisone=chkmatch(buffer);
    }/* if(line) */

  } /* while( get next buffer) */
  if( fcnerr )
  {
    fcnerr=0;
    finddisk_cleanup(2);
  }

  if( !disp_list )
    while( getstr(buffer,fdl)!=NULL);
  else
  {
    if( thisone )
      if( printdir(&line) )
        finddisk_cleanup(3);

    if( con_print_line )
    {
      fputstr("[ Quit ]",confh);
      Read(confh,buffer,5L);
    }
  }

  finddisk_cleanup(0)
}

void finddisk_free()
{
  Close(fdl);
  if( confh )
    Close(confh);
}


printdir(line)
  int *line;
{
  int i;

  if( !confh )
    if( (confh=Open("CON:0/0/640/200/FindDisk3.3",(long)MODE_OLDFILE))==0)
    {
       errorstr=(" Could not open display window.");
       return 1;
    }

  /* print the directory */
  (*line)--;
  for(i=0; i<*line; i++)
    if( shdsp && i )
    {
      if( chkmatch(dirlist[i]) )
        unskrunch(dirlist[i]);
    }
    else
      unskrunch(dirlist[i]);

  /* if at the end of the dirlist array- prints 'cut off' */
  if( *line==NUMLINES-1 )
    tocon(cutoff);

  return 0;
}


chkmatch(buffer)
  char *buffer;
{
  int i, kase;
  char *p;

  for(i=1; i<glargc; i++)
  {
    if( *glargv[i]=='!' )
    {
      p=glargv[i]+1;
      kase=1;
    }
    else
    {
      p=glargv[i];
      kase=0;
    }
    if( !mystrstr(buffer,p,kase) )
      return 0;
  }
  return 1;
}


void tocon(s)
  char *s;
{
  char inp[6];

  if( ++con_print_line>=DISP_LINES )
  {
    fputstr("[ More... ]",confh);
    Read(confh,inp,5L);
    inp[5]='\0';
    if( strchr(inp,'q') )
      disp_list=0;
    fputstr("\013\033[K\015",confh);
    con_print_line-=last_startchar;
  }
  fputstr(s,confh);
}


#define update_cleanup(x)  { update_free(); return x; }

update()
{
  int  i;

  if( !(fdl=opendl((long)MODE_OLDFILE)) )
    return 1;

  if( !(ftmp=opentmp((long)MODE_OLDFILE)) )
  {
    Close(fdl);
    return 0;
  }

  INIT_DISKNAMES;
  init_bufblks();

  /* finds the disks names in TempDL */
  while( getstr(buffer,ftmp) !=NULL )
  {
      if( mystrstr(buffer,STARTSTR,1) )
      {
         skrunch(buffer);
         if( storename(buffer) )
           update_cleanup(3)
      }
  }
  if( fcnerr )
  {
    fcnerr=0;
    update_cleanup(10)
  }

  if( storedl() )
    update_cleanup(4)

  Seek(ftmp,0L,(long)OFFSET_BEGINNING);

  /* store TempDL in memory */
  while( getstr(buffer,ftmp) !=NULL )
    if( store( skrunch(buffer) ) )
      update_cleanup(5)
  if( fcnerr )
  {
    fcnerr=0;
    update_cleanup(6);
  }

  Close(fdl);
  if( !(fdl=opendl((long)MODE_NEWFILE)) )
  {
    Close(ftmp);
    FREE_DISKNAMES;
    free_bufblks();
    return 6;
  }

  /* write the in memory disklist to the one in ram: */
  if( write_bufblks(fdl) )
    update_cleanup(8)

  Close(ftmp);
  if( !(ftmp=opentmp((long)MODE_NEWFILE)) )
    update_cleanup(7)

  update_free();
  return 0;
}

void update_free()
{
  Close(fdl);
  Close(ftmp);
  FREE_DISKNAMES;
  free_bufblks();
}


#define remove_cleanup(x)  { remove_free(); return x; }

remove()
{
  int i;
  char *p;

  if( *(p=firstchar(strbuf))=='\0' )
     return 1;

  if( !(fdl=opendl((long)MODE_OLDFILE)) )
    return 2;

  INIT_DISKNAMES;
  init_bufblks();

  /* finds the disk name in DiskList */
  while( getstr(buffer,fdl) !=NULL )
  {
      if( mystrstr(buffer,p,1) )
      {
         if( storename(buffer) )
           remove_cleanup(3)
      }
  }
  if( fcnerr )
  {
    fcnerr=0;
    remove_cleanup(4);
  }

  Seek(fdl,0L,(long)OFFSET_BEGINNING);

  if( storedl() )
    remove_cleanup(4)

  Close(fdl);
  if( !(fdl=opendl((long)MODE_NEWFILE)) )
  {
    FREE_DISKNAMES;
    free_bufblks();
    return 5;
  }

  /* write the in memory disklist to the one in ram: */
  if( write_bufblks(fdl) )
      remove_cleanup(6)

  remove_free();
  return 0;
}

void remove_free()
{
  Close(fdl);
  FREE_DISKNAMES;
  free_bufblks();
}


/* loads the DiskList into memory but leaves out the directories in the
   diskname list, pointed to by firstdisk */
storedl()
{
  int storeit=1;  /* saving this directory */

  /* doesn't store directories that are in the temp file */
  while( getstr(buffer,fdl) !=NULL )
  {
      if( strchr(buffer,(char)STARTCHAR) )
      {
         storeit=1;
         diskptr=firstdisk;
         while(diskptr)
         {
           if( mystrstr(buffer,diskptr->name,1) )
           {
             storeit=0;
             break;
           }
           diskptr=diskptr->next;
         }
      }

      if(storeit)
       if( store(buffer) )
         return 1;
  }

  if( fcnerr )
  {
    fcnerr=0;
    return 2;
  }
  return 0;
}

/* must be used in the WHILE( GETSTR()!=NULL) fashion */
char *getstr(line,f)
  char *line;
  BPTR f;
{
  static char *buffer, *bufptr;
  static int  last_read;
  int len, n=MAXBUF;
  char temp, *p, empty='\0';

  if( !buffer )
  {
    if( (buffer=(char *)AllocMem((long)CP_BUFF+1,0L))==0)
    {
       errorstr=outofmem;
       fcnerr=1;
       return (char *)0;
    }
    bufptr=&empty;
  }

  while(1)
    if( p=strchr(bufptr,'\n') )
    {
      temp=*(++p);
      *p='\0';
      strncpy(line,bufptr,n);
      *p=temp;
      bufptr=p;
      return line;
    }
    else
    {
      strncpy(line,bufptr,n);
      len=strlen(line);
      n-=len;
      line+=len;

      if( last_read )
      {
        FreeMem(buffer,CP_BUFF+1);
        buffer=0;
        last_read=0;
        return (char *)0;
      }
      else
        if( (len=Read(f,buffer,CP_BUFF)) <1 )
          last_read=1;
        else
        {
          last_read= len!=CP_BUFF;
          bufptr=buffer;
          *(buffer+len)='\0';
        }
    }
}


/* Saves the name of a disk in a linked list structure */
storename(buffer)
 char *buffer;
{
  if( diskptr==NULL )
  {
    if( (firstdisk=(struct disk *)malloc(sizeof(struct disk)) )==NULL)
    {
      errorstr=outofmem;
      return 1;
    }
    diskptr=firstdisk;
    strcpy(diskptr->name,buffer);
    diskptr->next=NULL;
  }
  else
  {
    if( (diskptr->next=(struct disk *)malloc(sizeof(struct disk)) )==NULL)
    {
      errorstr=outofmem;
      return 2;
    }
    diskptr=diskptr->next;
    strcpy(diskptr->name,buffer);
    diskptr->next=NULL;
  }

  return 0;
}

void free_disknames()
{
  struct disk *p;

  while(firstdisk)
  {
    p=firstdisk->next;
    free(firstdisk);
    firstdisk=p;
  }
}


/* prints line to confh unskrunched */
/* format  [BYTE]=>   [SKRUNCHAR] [# of spaces ]   */

void unskrunch(line)
  char *line;
{
  char output[LINELEN], *p;
  int i;

  p=output;
  while(*line)
  {
    switch((int)*line)
    {
      case SKRUNCHAR : line++;
                       for(i=SKRUNOFFS; i<(int)*line; i++)
                         *(p++)=' ';
                       break;

      case STARTCHAR : strcpy(p,STARTSTR);
                       p+=strlen(STARTSTR);
                       break;

      default : *(p++)=*line;
    }

    line++;
  }
  *p='\0';
  tocon(output);
}


char *skrunch(line)
  char *line;
{
  char skbuf[LINELEN],*p;
  int  spaces=0;

  /* first tokenizes the STARTSTR/XnSTR if in line */

  tokenize(line,STARTSTR,STARTCHAR);

  /* this is the compaction of >2 spaces */
  p=skbuf;
  while( *line )
  {
    if( *line==' ' )
      spaces++;
    else
    {
      if( spaces )
        if( spaces>2 )
        {
          *(p++)=(char)SKRUNCHAR;
          *(p++)=(char)(spaces+SKRUNOFFS);
          spaces=0;
        }
        else
        {
          *(p++)=' ';
          if( spaces>1 ) *(p++)=' ';
          spaces=0;
        }

      *p=*line;
      p++;
    }
    line++;
  }
  *p='\0';
  strcpy(buffer,skbuf);
  return buffer;
}


/* will tokenize first occurance of STR in LINE */
tokenize(line,str,chr)
  char *line,*str;
  int  chr;
{
  char *p,*q;

  if( p=mystrstr(line,str,1) )
  {
    q=p+strlen(str);
    *p=(char)chr;
    strcpy(p+1,q);
    return 1;
  }
  return 0;
}

/* stores line to memory */
store(buffer)
  char *buffer;
{
  struct mem_block *p;
  int i;

  i=strlen(buffer);
  chrcount+=i;

  if( chrcount>=BLKSIZE )
  {
    if( mem_block_ptr )
      *mem_block_ptr='\0';
    chrcount=i;

    if( (p=(struct mem_block *)malloc(sizeof(struct mem_block)) )==NULL)
    {
       errorstr=outofmem;
       return 2;
    }

    p->next=NULL;

    if( mem_blocks )
      cur_mem_block->next=p;
    else
      mem_blocks=p;
    cur_mem_block=p;

    mem_block_ptr=cur_mem_block->buffer;
  }

  strcpy(mem_block_ptr,buffer);
  mem_block_ptr+=i;

  return 0;
}

write_bufblks(BPTR fd)
{
  struct mem_block *p;

  p=mem_blocks;
  while(p)
  {
    if( fputstr(p->buffer,fd) )
      return 1;
    p=p->next;
  }

  return 0;
}


void init_bufblks()
{
  mem_block_ptr=NULL;
  chrcount=BLKSIZE+1;
  cur_mem_block=NULL;
  mem_blocks=NULL;
}

void free_bufblks()
{
  struct mem_block *p,*next;

  p=mem_blocks;
  while(p)
  {
    next=p->next;
    free(p);
    p=next;
  }
}


void get_dlpath()
{
  BPTR lock;

  dlpath[MAXPATHLEN]='\0';

  if( lock=Lock(dltemp,(long)ACCESS_READ) )
  {
    strncpy(dlpath,dltemp,MAXPATHLEN);
    UnLock(lock);
  }
  else
    strncpy(dlpath,dldisk,MAXPATHLEN);
}

BPTR opendl(mode)
  long mode;
{
  BPTR fdl;

  if( (fdl=Open(dlpath,mode))==NULL)
  {
    errorstr="Can't open DiskList.";
    return 0;
  }
  return fdl;
}


#define MODE_APPEND 1000L

BPTR opentmp(mode)
  long mode;
{
  BPTR ftmp;
  BPTR lock;
  int    seek=0;

  if( mode==MODE_APPEND)
  {
    if( lock=Lock(tempdl,(long)ACCESS_READ) )
    {
      UnLock(lock);
      mode=(long)MODE_OLDFILE;
      seek=1;
    }
    else
      mode=(long)MODE_NEWFILE;
  }

  if( (ftmp=Open(tempdl,mode))==NULL)
  {
    errorstr=" Can't open TempDL.";
    return 0;
  }

  if( seek )
    Seek(ftmp,0L,(long)OFFSET_END);

  return ftmp;
}


sdir()
{
  char *p;

  if( *(p=firstchar(strbuf))=='\0' )
    p=sdir_pat;

  if( !(ftmp=opentmp(MODE_APPEND)) )
    return 1;

  if( do_ls(p,ftmp,subdir) )
  {
    Close(ftmp);
    return 2;
  }
  Close(ftmp);
  return 0;
}


#define ls_cleanup(x) { ls_free(lock,f_info); return x; }

do_ls(pat,fh,recur)
  char *pat;
  BPTR fh;
  int recur;
{
  BPTR lock=NULL;
  struct FileInfoBlock *f_info;

  char *s, *tempstr;
  int  slen, isadir, col, patchg=0, firstrun=1;
  char *spaces1, *spaces2;
  struct disk *nextdir;
  char basename[80], tempname[80];


  /* strings of 18 & 36 spaces for formatting output */
  /*       012345678901234567                        */
  spaces1="                  ";
  /*       0123456789012345678901234567890123456     */
  spaces2="                                     ";

  INIT_DISKNAMES;
  nextdir=NULL;

  strcpy(tempname,"/");
  tempstr=tempname+1;

  if((f_info=(struct FileInfoBlock *)
     AllocMem((long)sizeof(struct FileInfoBlock),0L))==0)
  {
    errorstr=outofmem;
    FREE_DISKNAMES;
    return 1;
  }

  do
  {
    if( firstdisk )
    {
      while( nextdir && *(nextdir->name)=='/' )
      {
        strncpy(basename,(nextdir->name)+1,78);
        strncpy(basename+strlen(basename),"/",2);
        nextdir=nextdir->next;
        if( !nextdir )
          ls_cleanup(0)
      }
      strncpy(tempname+1,basename,78);
      slen=strlen(tempname);
      strncpy(tempname+slen,nextdir->name,79-slen);
      if( storename(tempname) )
        ls_cleanup(1);
      pat=tempname+1;
    }

    do
    {
      if( firstrun )
      {
        if(patchg==1)
        {
          patchg=2;
          strncpy(tempstr,f_info->fib_FileName,78);
          slen=strlen(tempstr);
          tempstr[slen]=':';
          strncpy(tempstr+slen+1,s+4,78-slen);
          pat=tempstr;
        }
        else if( strchr(pat,':')<strchr(pat,'\0')-1 )
        {
          patchg=2;
          if( !(strncmp(pat,"df0:",4) && strncmp(pat,"df1:",4)) )
          {
            patchg=1;
            strncpy(tempstr,pat,4);
            *(tempstr+4)='\0';
            s=pat;
            pat=tempstr;
          }
        }
      }

      if((lock=Lock(pat,(long)ACCESS_READ))==0)
        ls_cleanup(2)

      if((Examine(lock,f_info))==0)
        ls_cleanup(3)
    }
    while( patchg==1 );
    firstrun=0;

    if( fputstr(STARTSTR,fh) )
      ls_cleanup(4)
    if( firstdisk )
    {
      fputstr(tempname+1,fh);
      fputstr ("\n",fh);
    }
    else
    {
      if( patchg )
      {
        patchg=0;
        if( fputstr(pat,fh) )
          ls_cleanup(5)
        fputstr ("\n",fh);
        strncpy(basename,pat,79L);
        slen=strlen(basename);
        basename[slen++]='/';
        basename[slen]='\0';

      }
      else
      {
        if( fputstr(f_info->fib_FileName,fh) )
          ls_cleanup(6)
        fputstr (":\n",fh);
        strncpy(basename,f_info->fib_FileName,78);
        slen=strlen(basename);
        basename[slen++]=':';
        basename[slen]='\0';
      }
    }
    col=0;

    while( (ExNext(lock,f_info))!=0)
    {
      s=f_info->fib_FileName;
      slen=strlen(s);
      isadir= (f_info->fib_DirEntryType>0);

      if((col == 3) && slen >18) {
           fputstr("\n",fh);
           col = 0;
      }

      if (isadir)
        fputstr ("\033[33m ",fh);
      else
        fputstr (" ",fh);

      if (slen >18) {
         if( fputstr(s,fh) )
           ls_cleanup(7)
         col += 2;
         if( fputstr(spaces2+slen,fh) )
           ls_cleanup(8)
      }
      else {
         if( fputstr(s,fh) )
           ls_cleanup(9)
         if( fputstr(spaces1+slen,fh) )
           ls_cleanup(10)
         col++;
      }

      if( isadir && recur )
        if(storename(s))
          ls_cleanup(1);

      if (isadir)
        fputstr("\033[0m",fh);

      if (col > 3) {
         fputstr("\n",fh);
         col = 0;
      }

    }
    fputstr("\n",fh);
    if( col )
      fputstr("\n",fh);

    UnLock(lock);
    lock=NULL;

    if( nextdir )
      nextdir=nextdir->next;
    else
      nextdir=firstdisk;
  }
  while( nextdir );

  ls_free(lock,f_info);
  return 0;
}

void ls_free(lock,f_info)
  BPTR lock;
  struct FileInfoBlock *f_info;

{
  if( lock )
    UnLock(lock);
  FreeMem(f_info,(long)sizeof(struct FileInfoBlock));
  FREE_DISKNAMES;
}


fputstr(str,fh)
  char *str;
  BPTR fh;
{
   long len;
   len=(long)strlen(str);
   if( Write(fh,str,len)==len)
     return 0;
   return 1;
}


savedl()
{
  if( update() )
    return 1;

  if( strcmp(dlpath,dldisk) )
  {
    if( copy(dlpath,dldisk) )
      return 2;
    DeleteFile(dlpath);
    strncpy(dlpath,dldisk,MAXPATHLEN);
    DeleteFile(tempdl);
  }
  return 0;
}

loaddl()
{
  if( strcmp(dltemp,dlpath) )
    if( copy(dlpath,dltemp) )
      return 1;
  strncpy(dlpath,dltemp,MAXPATHLEN);
  return 0;
}

newdl()
{
  BPTR fh;

  if( fh=Open(dlpath,(long)MODE_NEWFILE) )
  {
    Close(fh);
    return 0;
  }
  return 1;
}

copy(src,dest)
  char *src,*dest;
{
  BPTR sfh,dfh;
  char *buffer;
  int  len;

  if((sfh=Open(src,(long)MODE_OLDFILE))==0)
    return 1;

  if((dfh=Open(dest,(long)MODE_NEWFILE))==0)
  {
    Close(sfh);
    return 2;
  }
  if( (buffer=(char *)AllocMem(CP_BUFF,0L))==0)
  {
    Close(sfh);
    Close(dfh);
    errorstr=outofmem;
    return 3;
  }

  do
  {
    len=Read(sfh,buffer,CP_BUFF);
    Write(dfh,buffer,(long)len);
  }
  while( len!=0 );

  FreeMem(buffer,CP_BUFF);

  Close(sfh);
  Close(dfh);
  return 0;
}

char *firstchar(s)
  char *s;
{
  while(*s==' ')
    s++;
  return s;
}

/*   OK, this is not quite a true strstr() with case switch.
     The sub string must be in upper case if kase=0 (?!sorry)    */
char *mystrstr(string,sub,kase)
  char *string,*sub;
  int  kase;
{
  int length;
  char copstr[LINELEN], *str;

  /* string copied so it will not be converted to upper case */
  strcpy(copstr,string);
  str=copstr;

  length=strlen(sub);

  if( kase )
    str=strchr(str,*sub);
  else
    str=strchr(strtoupper(str),*sub);

  while( str )
  {
    if( strncmp(str,sub,length) )
      str++;
    else
      return string+(str-copstr);

    str=strchr(str,*sub);
  }
  return NULL;
}

char *strtoupper(s)
  char *s;
{
    register char *p = s;

    while(*p)
    {
       *p = toupper(*p);
       p++;
    }
    return(s);
}


/* Following lifted from ...*/

/* misc.c
 *      Misc. subroutines that like to live together...
 *
 * Phillip Lindsay (c) 1987 Commodore-Amiga - This code may be freely used
 * as long as the copyright notice is left intact.
 */

/* btoc() takes a pointer to a BSTR and converts it to a
 * C string.
 */
char *btoc(bstring)
CPTR bstring;
{
 register UBYTE len,count,*cstring=NULL;

 if (bstring) {
    cstring = (UBYTE *) bstring;
    len = cstring[0];
    for(count=0;count < len;count++)
        cstring[count] = cstring[count+1];

    cstring[count] = '\0';
 }
 return((char *)cstring);
}

/*
 *  find a dos node in the system device list
 *
 */
struct DeviceNode *finddosnode(lookfor)
char    *lookfor;
{
    extern   struct DosLibrary *DOSBase;
             struct RootNode   *rnode;
             struct DosInfo    *dinfo;
    register struct DeviceNode *dnode;
    register char              *bname;
    char                        name2[81];
    BOOL                        found = FALSE;

    rnode   = (struct RootNode *)  DOSBase->dl_Root;        /* find root node */
    dinfo   = (struct DosInfo  *)  BADDR(rnode->rn_Info);   /* now dos info   */

    Forbid();

    for(dnode = (struct DeviceNode *) BADDR(dinfo->di_DevInfo); ( dnode ) ;
      dnode = (struct DeviceNode *) BADDR(dnode->dn_Next))
    {
        bname = (char *) BADDR(dnode->dn_Name);
        memmove(name2, bname, (ULONG)( bname[0] + 1 ) );

        if ( !( strcmp( lookfor, strtoupper(btoc(name2)) ) ) ) {
            found   =   TRUE;
            break;
        }

    }

    Permit();

    return dnode;       /* NULL if not found */
}

/* end of misc.c */

