/* Some unix emulation procedures to make XV happy */
/* 1-NOV-1990 GJC@MITECH.COM */

#include <stdio.h>

#include <string.h>
#include <descrip.h>
#include <rmsdef.h>
#include <ssdef.h>
#include <stat.h>


int xv_bcmp ( s1, s2, size )
    char *s1, *s2;
    int size;
{
    int i;
    for ( i = 0; i < size; i++ ) if ( *s1++ != *s2++ ) {
	if ( *(--s1) > *(--s2) ) return 1; else return -1;
    }
    return 0;
}

bcopy(x,y,n)
     char *x,*y;
     long n;
{memmove(y,x,n);}	/* reverse order of arguments */

static char *getwd_tmp = NULL;

char *getwd(p)
     char *p;
{int c;
 char *root_dir,*l2;
 getcwd(p,512,0);	/* get current working directory in unix format*/

 root_dir = strstr ( p, "/000000" );
 if ( root_dir != NULL ) {
    /* trim root directory out of specification */
    if ( (strlen(root_dir) == 7) && 
	 (strpbrk(p+1,"/") == root_dir) ) *root_dir = '\0';
 }
 /* special kludge for "/" directory */
 if ( strcmp ( p, "/DEVICE_LIST_ROOT" ) == 0 ) strcpy  ( p, "/" );
 return(p);
}

unlink(p)
     char *p;
{printf("unlink: '%s'\n",p); delete(p);}

rindex(p,c)
     char *p;
     int c;
{return(strrchr(p,c));}

int lstat(f,st)		/* fake a stat operation to return file type */
   char *f;
   stat_t *st;
{
    char *dirext, *name;
    int extlen;

    st->st_mode = S_IFREG;	/* default to normal file */
    name = strrchr ( f, '/' );	/* locate rightmost slash */
    if ( name == NULL ) name = f; else name++;

    dirext = strstr ( name, ".DIR" );
    if ( dirext != NULL ) {
	/* make it an exact match */
	extlen = strcspn(&dirext[1],".;");
        if ( (extlen == 0) || (extlen == 3) ) {
	    st->st_mode = S_IFDIR;
	    if ( strncmp ( name, "000000.", 7 ) == 0 ) return 0;
	    else return (stat ( f, st ));
	}
    }
    return 0;
}

do_vms_wildcard(pargc,pargv)
     int *pargc;
     char ***pargv;
{int j,vsize;
 int argc; char **argv;
 argc = *pargc;
 argv = *pargv;
 *pargc = 0;
 vsize = 3;
 *pargv = (char **) malloc(sizeof (char *) * vsize);
 for(j=0;j<argc;++j)
   vms_wild_putargs(argv[j],pargc,pargv,&vsize);}

vms_wild_putargs(s,pargc,pargv,pvsize)
     char *s; int *pargc; char ***pargv; int *pvsize;
{if ( (!strchr(s,'*')) && (!strchr(s,'%')) )
   vms_wild_put_one(s,pargc,pargv,pvsize);
 else
   vms_wild_put_wild(s,pargc,pargv,pvsize);}


vms_wild_put_one(s,pargc,pargv,pvsize)
     char *s; int *pargc; char ***pargv; int *pvsize;
{int nvsize,i;
 char ** nargv, *uname, *SHELL$TRANSLATE_VMS();
 if (*pargc == *pvsize)
   {nvsize = 2 * *pvsize;
    nargv = (char **) malloc(sizeof (char *) * nvsize);
    for(i=0;i < *pargc; ++i) nargv[i] = (*pargv)[i];
    free(*pargv);
    *pargv = nargv;
    *pvsize = nvsize;}
 if ( uname = SHELL$TRANSLATE_VMS ( s ) ) {
    /* printf("vms: '%s' -> unix: '%s'\n", s, uname ); */
    if ( strlen(s) >= strlen(uname) ) { strcpy(s,uname); free(uname); }
    else s = uname;  /* will lose s's old allocation */
 } 
 (*pargv)[(*pargc)++] = s;}


set_dsc(x,buff,len)
 struct dsc$descriptor *x;
 char *buff;
 int len;
{(*x).dsc$w_length = len;
 (*x).dsc$a_pointer = buff;
 (*x).dsc$b_class = DSC$K_CLASS_S;
 (*x).dsc$b_dtype = DSC$K_DTYPE_T;
 return(x);}

 struct dsc$descriptor *
set_dsc_cst(x,buff)
 struct dsc$descriptor *x;
 char *buff;
{return(set_dsc(x,buff,strlen(buff)));}


vms_wild_put_wild(s,pargc,pargv,pvsize)
     char *s; int *pargc; char ***pargv; int *pvsize;
{struct dsc$descriptor fnamed,foutd,rfnamed;
 char *ns,*p;
 int rval;
 long context;
 set_dsc_cst(&rfnamed,";");
 set_dsc_cst(&fnamed,s);
 set_dsc(&foutd,0,0);
 foutd.dsc$b_class = DSC$K_CLASS_D;
 context = 0;
 while(1)
  {rval = lib$find_file(&fnamed,&foutd,&context,0,&rfnamed,0,0);
   if (rval == RMS$_NMF) break;
   if (rval == RMS$_FNF) break;
   if (rval != RMS$_NORMAL) exit(rval);
   ns = (char *) malloc(foutd.dsc$w_length + 1);
   ns[foutd.dsc$w_length] = 0;
   memcpy(ns,foutd.dsc$a_pointer,foutd.dsc$w_length);
   /*if (p = strchr(ns,']')) ns = p+1;*/
   /* if (p = strchr(ns,';')) *p = 0; */
   vms_wild_put_one(ns,pargc,pargv,pvsize);}
 if (foutd.dsc$a_pointer) lib$sfree1_dd(&foutd);
 if (context)
   {rval = lib$find_file_end(&context);
    if (rval != SS$_NORMAL) exit(rval);}}

/*
 * Define substitue qsort for one that dec broke.  Only handle case where
 * element size is 4 (same as integer).
 */
#ifdef qsort
#undefine qsort
#endif
void xv_qsort ( array, size, unit, compare )
   int array[1000];	/* array to be sorted */
   int size;		/* size of array to sort, should be at least 100 */
   int unit;		/* Size of array element */
   int compare();	/* comaparison function */
{
   int stack[68], *top;	/* work array, depth of stack is bounded */
   int start, finish, lbound, hbound, pivot, temp, i, j;

   if ( unit != sizeof(int) ) {	/* punt */
	qsort ( array, size, unit, compare );
	return;
    }
   if ( size <= 1 ) return;
   /* set up initial partition on top of stack */
   top = &stack[68];
   *--top = 0;		/* push lbound */
   *--top = size-1;	/* push initial hbound */

   /* loop until stack is emtpy */

   while ( top < &stack[68] ) {

      /* pop next range from stack and see if it has at least 3 elements */

      finish = *top++; start = *top++;
      pivot = array[start];
      if ( finish > start + 1 ) {
         /*
          *  more than 2 elements, split range into 2 sections according to
          *  the relation to the pivot value.
          */
	 array[start] = array[(start+finish)/2];	/* avoid sequence */
	 array[(start+finish)/2] = pivot; pivot = array[start];
         lbound = start; hbound = finish;
         while ( lbound < hbound ) {
            if ( compare(&pivot, &array[lbound+1]) > 0 ) {
               lbound++;
            } else {
               temp = array[hbound];
               array[hbound] = array[lbound+1];
               hbound--;
               array[lbound+1] = temp;
            }
         }
         /* determine which parition is bigger and push onto stack */
         if ( lbound + lbound < (start+finish) ) {
            /* push high partition first. */
            *--top = lbound + 1;
            *--top = finish;
            finish = start;		/* skip add step below */
             /* either push low partition or sort by inspection */
            if ( lbound - start > 1 ) {
               *--top = start;
               *--top = lbound;
            } else {
               /* 2 element parition (start+1=lbound), sort by looking */
               if ( pivot > array[lbound] ) {
                  array[start] = array[lbound];
                  array[lbound] = pivot;
               }
            }
         } else if ( lbound != finish ) {
            /* either push low partition or sort by inspection */
            if ( lbound - start > 1 ) {
               *--top = start;
               *--top = lbound;
            } else if ( lbound  > start ) {
               /* 2 element parition (start+1=lbound), sort by looking */
               if ( compare(&pivot, &array[lbound]) > 0 ) {
                  array[start] = array[lbound];
                  array[lbound] = pivot;
               }
            }
            /* push high partition or sort by inspection */
            if ( lbound < finish - 2 ) {
               *--top = lbound + 1;
               *--top = finish;
            } else if ( lbound < finish - 1 ) {  /* 2 in partition */
               if ( compare(&array[lbound+1], &array[finish]) > 0 ) {
                  temp = array[lbound+1];
                  array[lbound+1] = array[finish];
                  array[finish] = temp;
               }
            }
         } else {
            /*
             * Special case: high partition is empty, indicating that pivot
             * value is at maximum.  Move to end and re-push remainder.
             */
            array[start] = array[finish];
            array[finish] = pivot;
            *--top = start;
            *--top = finish - 1;
         }

      } else {
         /* only 2 elements in partition, sort inline */
         if ( compare(&pivot,&array[finish]) > 0 ) {
            array[start] = array[finish];
            array[finish] = pivot;
         }
      }
   }
} 
