Metropoli BBS
VIEWER: cdirent.c MODE: TEXT (CP437)
/*

   CDIRENT.C

   (c) 1996 Oliver Kraus

*/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "ccommon.h"
#include "cdirent.h"
#include "cio.h"

#ifdef C_DOS
#include <dos.h>
#include <direct.h>
#include "dpmicall.h"
#endif

#ifdef C_UNIX
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#endif

#define CDIR_EXPAND_MEM 8192

unsigned char c_translation[] =
{
	  0, /*	*/
	  1, /*  */
	  2, /*  */
	  3, /*  */
	  4, /*  */
	  5, /*  */
	  6, /*  */
	  7, /*  */
	  8, /*  */
          9, /*   */
         10, /*   */
	 11, /*  */
	 12, /*  */
	 13, /*  */
	 14, /*  */
	 15, /*  */
	 16, /*  */
	 17, /*  */
	 18, /*  */
	 19, /*  */
	 20, /* ╢ */
	 21, /* º */
	 22, /*  */
	 23, /*  */
	 24, /*  */
	 25, /*  */
	 26, /*	*/
	 27, /*  */
	 28, /*  */
	 29, /*  */
	 30, /*	*/
	 31, /*	*/
	 32, /*	*/
	 33, /* ! */
	 34, /* " */
	 35, /* # */
	 36, /* $ */
	 37, /* % */
	 38, /* & */
	 39, /* ' */
	 40, /* ( */
	 41, /* ) */
	 42, /* * */
	 43, /* + */
	 44, /* , */
	 45, /* - */
	 46, /* . */
	 47, /* / */
	 48, /* 0 */
	 49, /* 1 */
	 50, /* 2 */
	 51, /* 3 */
	 52, /* 4 */
	 53, /* 5 */
	 54, /* 6 */
	 55, /* 7 */
	 56, /* 8 */
	 57, /* 9 */
	 58, /* : */
	 59, /* ; */
	 60, /* < */
	 61, /* = */
	 62, /* > */
	 63, /* ? */
	 64, /* @ */
	'A', /* A */
	'B', /* B */
	'C', /* C */
	'D', /* D */
	'E', /* E */
	'F', /* F */
	'G', /* G */
	'H', /* H */
	'I', /* I */
	'J', /* J */
	'K', /* K */
	'L', /* L */
	'M', /* M */
	'N', /* N */
	'O', /* O */
	'P', /* P */
	'Q', /* Q */
	'R', /* R */
	'S', /* S */
	'T', /* T */
	'U', /* U */
	'V', /* V */
	'W', /* W */
	'X', /* X */
	'Y', /* Y */
	'Z', /* Z */
	 91, /* [ */
	 92, /* \ */
	 93, /* ] */
	 94, /* ^ */
	 95, /* _ */
	 96, /* ` */
	'A', /* a */
	'B', /* b */
	'C', /* c */
	'D', /* d */
	'E', /* e */
	'F', /* f */
	'G', /* g */
	'H', /* h */
	'I', /* i */
	'J', /* j */
	'K', /* k */
	'L', /* l */
	'M', /* m */
	'N', /* n */
	'O', /* o */
	'P', /* p */
	'Q', /* q */
	'R', /* r */
	'S', /* s */
	'T', /* t */
	'U', /* u */
	'V', /* v */
	'W', /* w */
	'X', /* x */
	'Y', /* y */
	'Z', /* z */
	123, /* { */
	124, /* | */
	125, /* } */
	126, /* ~ */
	127, /* ü */
	128, /* ╟ */
	'U', /* ⁿ */
	'E', /* Θ */
	'A', /* Γ */
	'A', /* Σ */
	'A', /* α */
	'A', /* σ */
	'C', /* τ */
	'E', /* Ω */
	'E', /* δ */
	'E', /* Φ */
	'I', /* ∩ */
	'I', /* ε */
	'I', /* ∞ */
	'A', /* ─ */
	'A', /* ┼ */
	'E', /* ╔ */
	145, /* µ */
	'A', /* ╞ */
	'O', /* ⌠ */
	'O', /* ÷ */
	'O', /* ≥ */
	'U', /* √ */
	'U', /* ∙ */
	'Y', /*   */
	'O', /* ╓ */
	'U', /* ▄ */
	'C', /* ó */
	156, /* ú */
	157, /* Ñ */
	158, /* ñ */
	159, /* û */
	'A', /* ß */
	'I', /* φ */
	'O', /* ≤ */
	'U', /* · */
	'N', /* ± */
	'N', /* ╤ */
	166, /* ¬ */
	167, /* ║ */
	168, /* ┐ */
	169, /* ¿ */
	170, /* ¼ */
        171, /* ╜ */
	172, /* ╝ */
	173, /* í */
	174, /* ½ */
	175, /* » */
	176, /* ù */
	177, /* ÿ */
	178, /* Ö */
	179, /* ■ */
	180, /* │ */
	181, /* ┤ */
	182, /* ╡ */
	183, /* ╕ */
	184, /* ╣ */
	185, /* á */
	186, /* ª */
	187, /* ⌐ */
	188, /* ¡ */
	189, /* ╗ */
	190, /* ╛ */
	191, /* └ */
	192, /* ┴ */
	193, /* ┬ */
	194, /* ├ */
	195, /* ╚ */
	196, /* ² */
	197, /* ╩ */
	198, /* ╚ */
	199, /* ╠ */

	200, /*	*/
	201, /*	*/
	202, /*	*/
	203, /*	*/
        204, /*  */
	205, /*	*/
	206, /*	*/
	207, /*	*/
	208, /*	*/
	209, /*	*/
	210, /*	*/
	211, /*	*/
	212, /*	*/
	213, /*	*/
	214, /*	*/
	215, /*	*/
	216, /*	*/
	217, /*	*/
	218, /*	*/
	219, /*	*/
	220, /*	*/
	221, /*	*/
	222, /*	*/
	223, /*	*/
	224, /*	*/
        'S', /* ▀ */
	226, /*	*/
	227, /*	*/
	228, /*	*/
	229, /*	*/
	230, /*	*/
	231, /*	*/
	232, /*	*/
	233, /*	*/
	234, /*	*/
	235, /*	*/
	236, /*	*/
	237, /*	*/
	238, /*	*/
	239, /*	*/
	240, /*	*/
	241, /*	*/
	242, /*	*/
	243, /*	*/
	244, /*	*/
	245, /*	*/
	246, /*	*/
	247, /*	*/
	248, /*	*/
	249, /*	*/
	250, /*	*/
	251, /*	*/
	252, /*	*/
	253, /*	*/
	254, /*	*/
	255  /*	*/
};

#define c_toupper(c) (c_translation[(unsigned char)(c)])

char *c_strupr(char *s)
{
   char *t = s;
   if ( s != NULL )
   {
      while(*s != '\0')
      {
         *s = c_toupper(*s);
         s++;
      }
   }
   return t;
}

int patmat(char *raw, char *pat)
{
   if ( *pat == '\0' )
      return *raw == '\0';                  /*  *raw == '\0' ? 1 : 0  */

   if (*pat != '*')                         /* if pattern is not a '*'*/
   {
      if (*raw == '\0')                     /*  if end of raw then    */
          return( 0 ) ;                     /*     mismatch           */
      while ((*pat == '?') || (*pat == *raw))  /*  if chars match then   */
      {
         raw++; pat++;
         if ( *pat == '\0' )
            return *raw == '\0';            /* *raw == '\0' ? 1 : 0   */
      }
   }  /* no else !!! */                     /* no match, if pat is not '*' */
   if (*pat == '*')                         /* if pattern is a '*'    */
   {
      while(*pat == '*')                    /* ignore more '*'        */
         pat++;
      if (*(pat  ) == '\0')                 /*    if it is end of pat */
         return( 1 ) ;                      /*    then match          */

      while( *raw != '\0' )                 /*    else hunt for match */
      {
         if((*pat == '?') || (*pat == *raw))
         {
            if (patmat(++raw, pat+1) != 0)  /*      if found,match    */
                 return( 1 ) ;              /*        rest of pat     */
         }
         else
         {
            raw++;
         }
      }
   }
   return( 0 ) ;                            /*  no match found        */
}

int upatmat(char *raw, char *pat)
{
   if ( *pat == '\0' )
      return *raw == '\0';                  /*  *raw == '\0' ? 1 : 0  */

   if (*pat != '*')                         /* if pattern is not a '*'*/
   {
      if (*raw == '\0')                     /*  if end of raw then    */
          return( 0 ) ;                     /*     mismatch           */
      while (((unsigned char)*pat == c_toupper(*raw)) || (*pat == '?'))
      {
         raw++; pat++;
         if ( *pat == '\0' )
            return *raw == '\0';            /* *raw == '\0' ? 1 : 0   */
      }
   }  /* no else !!! */                     /* no match, if pat is not '*' */
   if (*pat == '*')                         /* if pattern is a '*'    */
   {
      while(*pat == '*')                    /* ignore more '*'        */
         pat++;
      if (*(pat  ) == '\0')                 /*    if it is end of pat */
         return( 1 ) ;                      /*    then match          */

      while( *raw != '\0' )                 /*    else hunt for match */
      {
         if (((unsigned char)*pat == c_toupper(*raw)) || (*pat == '?'))
         {
            if (upatmat(++raw, pat+1) != 0) /*      if found,match    */
                 return( 1 ) ;              /*        rest of pat     */
         }
         else
         {
            raw++;
         }
      }
   }
   return( 0 ) ;                            /*  no match found        */
}

int _add_name(CDIR *dirp, char *name, char *short_name, unsigned long size, int is_dir)
{
   size_t len;
   struct c_dirent *de;
   if ( name == NULL )
      return 1;
   if ( name[0] == '\0' )
      return 1;

   if ( (dirp->options & CDIR_MATCH_ALL) == 0 )
   {
      if ( is_dir == 0 )
      {
         if ( dirp->pat[0] == '\0' )
            return 1;
         if ( dirp->patmat_fn(name, dirp->pat) == 0 )
            if ( dirp->patmat_fn(short_name, dirp->pat) == 0 )
               return 1;
      }
   }
   len = strlen(name)+1+sizeof(struct c_dirent);
   len = (size_t)(len + sizeof(long) - (size_t)1) & (size_t)0x0fffffffc;
   while ( dirp->cnt+len > dirp->max )
   {
      char *ptr;
      ptr = (char *)realloc(dirp->ptr, dirp->max+CDIR_EXPAND_MEM);
      if ( ptr == NULL )
         return 0;
      dirp->ptr = ptr;
      dirp->max += CDIR_EXPAND_MEM;
   }
   de = (struct c_dirent *)(dirp->ptr+dirp->cnt);
   de->d_size = size;
   /* de->d_ino = 0L; */
   de->d_off = 0L;
   de->d_reclen = (unsigned short)len;
   de->d_is_dir = (short)is_dir;
   strcpy(de->d_name, name);
   strncpy(de->d_short_name, short_name, 14);
   de->d_short_name[13] = '\0';
   dirp->cnt += len;
   return 1;
}

#ifdef C_DOS

int _add_dos_files(CDIR *dirp)
{
   struct _find_t fileinfo;
   if ( _dos_findfirst("*.*",
      _A_SUBDIR | _A_NORMAL | _A_HIDDEN | _A_RDONLY | _A_ARCH | _A_SYSTEM,
      &fileinfo) == 0 )
   {
      do
      {
         if ( _add_name(dirp,
               fileinfo.name,
               fileinfo.name,
               fileinfo.size,
               (fileinfo.attrib & _A_SUBDIR)==0?0:1 ) == 0 )
            return 0;
      } while(_dos_findnext(&fileinfo) == 0);
   }
   return 1;
}

struct _win95_find_data
{
   unsigned long attr;
   unsigned long create_time1;
   unsigned long create_time2;
   unsigned long access_time1;
   unsigned long access_time2;
   unsigned long modify_time1;
   unsigned long modify_time2;
   unsigned long size1;    /* high bytes */
   unsigned long size2;    /* low bytes */
   char fill[8];
   char long_name[260];
   char short_name[14];
};

#ifdef C_DIRECT_16_
int _add_longfile(CDIR *dirp)
{
   unsigned short handle;
   char far *search = "*";
   struct _win95_find_data fd;

   union REGS r;
   struct SREGS s;

   r.x.ax = 0x0714e;
   r.h.cl = 0x0ff;   /* every attrib ok */
   r.h.ch = 0;   /* no attrib req. */
   r.x.si = 0; /* win95 time format?? */
   s.ds = (unsigned)(((unsigned long)search)>>16);
   r.x.dx = (unsigned)(((unsigned long)search)&0x0ffffUL);
   s.es = (unsigned)(((unsigned long)((void far *)&fd))>>16);
   r.x.di = (unsigned)(((unsigned long)((void far *)&fd))&0x0ffffUL);
   int86x(0x021, &r, &r, &s);
   if ( r.x.cflag != 0 )
      return 0;
   handle = (unsigned short)r.x.ax;

   for(;;)
   {
      if ( _add_name(dirp,
            fd.long_name,
            fd.short_name,
            fd.size2,
            (fd.attr&0x010)==0?0:1 ) == 0 )
         break;

      r.x.ax = 0x0714f;
      r.x.bx = handle;
      r.x.si = 0; /* win95 time format?? */
      s.es = (unsigned)(((unsigned long)((void far *)&fd))>>16);
      r.x.di = (unsigned)(((unsigned long)((void far *)&fd))&0x0ffffUL);
      int86x(0x021, &r, &r, &s);
      if ( r.x.cflag != 0 )
         break;
   }
   r.x.ax = 0x071a1;
   r.x.bx = handle;
   int86x(0x021, &r, &r, &s);

   return 1;
}
#endif


int _add_dpmi_longfile(CDIR *dirp)
{
   unsigned short handle;
   short sel_search, seg_search;
   short sel_fd, seg_fd;
   rminfo_struct rmi;
   struct _win95_find_data fd;

   if ( dpmi_alloc_dos_memory(4, &sel_search, &seg_search ) == 0 )
      return 0;
   if ( dpmi_alloc_dos_memory(sizeof(struct _win95_find_data), &sel_fd, &seg_fd ) == 0 )
   {
      dpmi_free_dos_memory(sel_search);
      return 0;
   }
   dpmi_copy_to_dos(sel_search, (void *)"*", 2);

   rmi.eax = 0x0714eL;
   rmi.ecx = 0x0ffL;   /* every attrib ok, no attrib req. */
   rmi.esi = 0L;       /* win95 time format?? */
   rmi.ds = seg_search;
   rmi.edx = 0L;
   rmi.es = seg_fd;
   rmi.edi = 0L;
   if ( dpmi_simulate_rmi(0x021, &rmi) != 0 )
      return 0;
   handle = (unsigned short)rmi.eax;

   for(;;)
   {
      dpmi_copy_from_dos(sel_fd, &fd, sizeof(struct _win95_find_data));
      if ( _add_name(dirp,
            fd.long_name,
            fd.short_name,
            fd.size2,
            (fd.attr&0x010)==0?0:1 ) == 0 )
         break;

      rmi.eax = 0x0714fL;
      rmi.ebx = (long)handle;
      rmi.esi = 0L;       /* win95 time format?? */
      rmi.es = seg_fd;
      rmi.edi = 0L;
      if ( dpmi_simulate_rmi(0x021, &rmi) != 0 )
         break;
   }
   rmi.eax = 0x071a1L;
   rmi.ebx = (long)handle;
   dpmi_simulate_rmi(0x021, &rmi);

   dpmi_free_dos_memory(sel_fd);
   dpmi_free_dos_memory(sel_search);

   return 1;
}

int _add_files(CDIR *dirp)
{
   if ( c_is_long_filename() != 0 )
      return _add_dpmi_longfile(dirp);
   return _add_dos_files(dirp);
}

#endif


#ifdef C_UNIX
int _add_files(CDIR *dirp)
{
   DIR *d;
   struct dirent *e;
   struct stat s;
   d = opendir(".");
   if ( d == NULL )
      return 0;
   for(;;)
   {
      e = readdir(d);
      if ( e == NULL )
         break;
      if ( stat(e->d_name, &s) != 0 )
      {
         closedir(d);
         return 0;
      }
      if ( _add_name(dirp,
            e->d_name,
            "",
            s.st_size,
            (s.st_mode&S_IFDIR)!=0?1:0 ) == 0 )
         break;
   }
   closedir(d);
   return 1;
}

#endif


CDIR *c_opendir(const char *path, const char *pat, int options)
{
   CDIR *d;
   d = (CDIR *)malloc(sizeof(struct _CDIR_struct));
   if ( d != NULL )
   {
      d->options = options;
      d->path = (char *)malloc(strlen(path)+2);
      if ( d->path != NULL )
      {
         strcpy(d->path, path);
         d->pat = (char *)malloc(strlen(pat)+2);
         if ( d->pat != NULL )
         {
            strcpy(d->pat, pat);
            d->ptr = (char *)malloc(CDIR_EXPAND_MEM);
            if ( d->ptr != NULL )
            {
               d->max = (size_t)CDIR_EXPAND_MEM;
               d->cnt = (size_t)0;
               d->pos = 0;
               d->patmat_fn = patmat;
               if ( (options & CDIR_MATCH_CASE) == 0 )
               {
                  d->patmat_fn = upatmat;
                  c_strupr(d->pat);
               }

               c_chdir(path);
               if ( _add_files(d) == 0 )
               {
                  /* ... */
               }
               return d;
            }
            free(d->pat);
         }
         free(d->path);
      }
      free(d);
   }
   return NULL;
}

int c_closedir(CDIR *dirp)
{
   if ( dirp != NULL )
   {
      free(dirp->ptr);
      free(dirp->pat);
      free(dirp->path);
      free(dirp);
   }
   return 1;
}

struct c_dirent *c_readdir(CDIR *dirp)
{
   struct c_dirent *de;
   if ( dirp == NULL )
      return NULL;
   if ( dirp->pos >= dirp->cnt )
      return NULL;
   de = (struct c_dirent *)(dirp->pos+dirp->ptr);
   dirp->pos += de->d_reclen;
   return de;
}

void c_rewinddir(CDIR *dirp)
{
   if ( dirp == NULL )
      return;
   dirp->pos = 0;
}

long c_telldir(CDIR *dirp)
{
   if ( dirp == NULL )
      return -1L;
   return (long)dirp->pos;
}

void c_seekdir(CDIR *dirp, long pos)
{
   if ( dirp == NULL )
      return;
   dirp->pos = (size_t)pos;
}

#ifdef CDIRENT_MAIN
#include <stdio.h>
void main(void)
{
   CDIR *d;
   struct c_dirent *e;
   d = c_opendir(".", "*", 0);
   for(;;)
   {
      e = c_readdir(d);
      if ( e == NULL )
         break;
      if ( c_is_dir(e) != 0 )
         printf("<dir> ");
      else
         printf("      ");
      printf("%-14s %s\n", e->d_short_name, e->d_name);
   }
   c_closedir(d);
}
#endif
[ RETURN TO DIRECTORY ]