[comp.os.msdos.programmer] ls.c

mangor@disk.UUCP (Darrell Kitchen) (09/06/90)

I found a problem already with the following code and the "-C" command-line
option.  Look this over and see what I've found.

In article <4049@disk.UUCP> mangor@disk.UUCP (Darrell Kitchen) writes:
 
 ============================= LS.C ===========================================
 #include <stdio.h>
 /*    if your <stdio.h> doesn't have memory allocation functions then
       #include <alloc.h>  or  #include <malloc.h>
 */
 #include <errno.h>
 #include <mem.h>
 #include <dir.h>
 #include <dos.h>
 #include <stat.h>   /* should be #include <sys\stat.h> */
 
 #ifndef TRUE
 #define TRUE  1
 #endif
 #ifndef FALSE
 #define FALSE 0
 #endif
 
 #define nil    '\0'
 #define ALL_F  0xFF
================================ Add this ==================================
 #define ERR_F  0x1F
 
 #define EOL(c) (((c)=='\n' || (c)==nil) ? TRUE : FALSE)
 
 #define DY(date_) (((date_ & 0xFE00) >> 9) + 80)
 #define DATE_DAY(date_)  (date_ & 0x001F)
 #define DATE_MON(date_)  ((date_ & 0x01E0) >> 5)
 #define DATE_YEAR(date_) (DY(date_) == 100 ? 0 : DY(date_))
 
 #define T(t_) ((t_ & 0xF800) >> 11)
 #define TH(time_) (T(time_) == 0 ? 12 : T(time_))
 #define TIME_SEC(time_) (time_ & 0x001F)
 #define TIME_MIN(time_) ((time_ & 0x07E0) >> 5)
 #define TIME_HOUR(time_) (T(time_) > 12 ? TH(time_) = 12 : TH(time_))
 #define AP(time_) ((T(time_) > 12 && TIME_MIN(time_) > 0) ? 'p' : 'a')
 
 struct d_info {
      struct ffblk *f_inf;
      struct d_info *prev, *next;
 };
 
 #define crlf() printf("\n\r");
 
 static char *months[12] = {
      "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
 };
 
 static struct d_info *head;
 static struct stat f_stat;
 static char Cf,Ff,Rf,af,bf,cf,df,ff,gf,If,lf,mf,nf,of,pf,qf,rf,sf,tf,uf,xf,zf;
                       /* ^ command line option flags */
 static int  F_FLAG=0; /* file search flag */
 static int  tfiles=0; /* total files found for request */
 static char *path;    /* file found at requested directory path */
 static char *fpath;   /* to hold the filepath for call to ff_stat() */
 
 int nfexit(val,opt) int val, opt; {
      printf("\nls: ");
      switch(val) {
           case 1: printf("illegal option == %c\n",opt);
                   printf("usage: ls =RadCxmnlogrtucpFbqisfz [files]\n");
      }
      exit(val);
 }
 
 int istok(ch,str) const char ch; char *str; {
      int i;
 
      for(i=0;;i++) {
           if(str[i]==ch) return(i);
==============================[ CHANGE THIS ]============================
           if(str[i]==nil) return(0);                                   |
=========================================================================
==================================[ TO ]=================================
|          if(!str[i]) return(ERR_F);                                   |
=========================================================================
      }
 }
 
 int is_exec(dir) struct d_info *dir; {
      int i;
 
      for(i=0;dir->f_inf->ff_name[i]!='.';i++)
           if(dir->f_inf->ff_name[i]==nil) break;
      if(!strncmp(&(dir->f_inf->ff_name[i]),".bat",4)) return(TRUE);
      if(!strncmp(&(dir->f_inf->ff_name[i]),".exe",4)) return(TRUE);
      if(!strncmp(&(dir->f_inf->ff_name[i]),".com",4)) return(TRUE);
      if(!strncmp(&(dir->f_inf->ff_name[i]),".bin",4)) return(TRUE);
      if(!strncmp(&(dir->f_inf->ff_name[i]),".obj",4)) return(TRUE);
      if(!strncmp(&(dir->f_inf->ff_name[i]),".sys",4)) return(TRUE);
      if(!strncmp(&(dir->f_inf->ff_name[i]),".lib",4)) return(TRUE);
      return(FALSE);
 }
 
 int pr_time(dir) struct d_info *dir; {
      printf("%02d:%02d ",
           TH(dir->f_inf->ff_ftime),
           TIME_MIN(dir->f_inf->ff_ftime));
      return(0);
 }
 
 int ff_stat(dir,f_stat) struct d_info *dir; struct stat *f_stat; {
      FILE *f1;
      char *fname;
 
      memset(f_stat,0,sizeof(struct stat));
      if(dir->f_inf->ff_attrib & FA_DIREC) return(1); /* cant open directory */
      if(dir->f_inf->ff_attrib & FA_LABEL) return(1); /* and label entries   */
      fname=(char *)calloc(1,215);
      strcpy(fname,fpath);
      strcat(fname,dir->f_inf->ff_name);
      f1=fopen(fname,"r");
      if(f1==NULL) {
           printf("ls: error %d in ff_stat (%s)\n",errno,fname);
           free(fname);
           exit(0);
      }
      fstat(fileno(f1),f_stat);
      fclose(f1);
      free(fname);
      return(0);
 }
 
 int pr_inode() {
      printf("%5.1d ",f_stat.st_ino);
           /* msdos doesnt provide i=node info; unix dependent */
      return(0);
 }
 
 int pr_uid(dir) struct d_info *dir; {
 
      if(nf && gf) return(0);
      if(nf) printf("%4.1d ",f_stat.st_uid);
      else if(of || lf) {
           if(dir->f_inf->ff_attrib & FA_SYSTEM)
           printf("sys  "); else printf("dos  ");
      }
           /* msdos doesnt provide user id info; unix dependent */
      return(0);
 }
 
 int pr_gid(dir) struct d_info *dir; {
 
      if(nf && of) return(0);
      if(nf) printf("%4.1d ",f_stat.st_gid);
      else if(gf || lf) {
           if(dir->f_inf->ff_attrib & FA_SYSTEM)
           printf("sys  "); else printf("dos  ");
      }
           /* msdos doesnt provide group id info; unix dependent */
      return(0);
 }
 
 int pr_links() {
      printf("%3.1d ",f_stat.st_nlink); /* always 1 in msdos */
      return(0);
 }
 
 int pr_block(dir) struct d_info *dir; {
      int block=0;  /* in unix each dir entry has a size larger then 0  */
                    /* in pc/msdos each dir entry has a size of 0       */
                    /* but the dir entry occupies a 512 byte block      */
                    /* although not alone = i.e. more then one entry in */
                    /* each block                                       */
      block=dir->f_inf->ff_fsize / 512;
      if(block == 0) block = 1;
      printf("%4.1d ",block);
      return(0);
 }
 
 int pr_stat(dir) struct d_info *dir; { /*   0123456789   */
      char attlist[11];                 /*   ==========   */
                                        /*   drwxrwxhsl   */
      memset(attlist,'-',10);
      attlist[10]=nil;
      attlist[1]='r'; attlist[2]='w';
      attlist[4]='r'; attlist[5]='w';
      if(dir->f_inf->ff_attrib & FA_DIREC) attlist[0]='d';
      if(dir->f_inf->ff_attrib & FA_RDONLY) {
           attlist[2]='-'; attlist[5]='-';
      }
      if((dir->f_inf->ff_attrib & FA_DIREC) ||
         (is_exec(dir)) || (f_stat.st_mode & S_IEXEC)) {
           attlist[3]='x'; attlist[6]='x';
      }
      if(dir->f_inf->ff_attrib & FA_HIDDEN) {
           attlist[7]='h';  /* hidden should be honored as not readable */
           attlist[1]='-';  /* so in that aspect remove 'r' from 1,4    */
           attlist[4]='-';
      }
      if(dir->f_inf->ff_attrib & FA_SYSTEM) attlist[8]='s';
      if(dir->f_inf->ff_attrib & FA_LABEL)  attlist[9]='l';
      printf("%-11s",attlist);
      return(0);
 }
 
 int pr_date(dir) struct d_info *dir; {
      printf("%s %2.0d %2.0d ",
           months[DATE_MON(dir->f_inf->ff_fdate) = 1],
           DATE_DAY(dir->f_inf->ff_fdate),
           DATE_YEAR(dir->f_inf->ff_fdate));
      return(0);
 }
 
 int pr_size(dir) struct d_info *dir; {
      printf("%7.1ld ",dir->f_inf->ff_fsize);
      return(0);
 }
 
 int pr_name(dir) struct d_info *dir; {
      struct stat f_stat;
============================[ add this ]================================
|     char *str;                                                       |
|     int i;                                                           |
|                                                                      |
|     str=(char *)calloc(1,128);                                       |
|     strcpy(str,dir= f_inf->ff_name);                                 |
========================================================================
      ff_stat(dir,&f_stat);
==========================[ CHANGE THIS ]================================
      printf("%s",dir->f_inf->ff_name);                                 |
      if((Ff || pf) && (dir->f_inf->ff_attrib & FA_DIREC)) printf("\\");|
      if(Ff && (is_exec(dir))) printf("*");                             |
=========================================================================
===============================[ TO ]===================================
|     i=strlen(str)+1;                                                 |
|     if((Ff || pf) && (dir= f_inf->ff_attrib & FA_DIREC))             |
|          str[strlen(str)]='\\';                                      |
|     if(Ff && (is_exec(dir))) str[strlen(str)]='*';                   |
|     if(Cf && (mod % 5 != 4)) for(i=strlen(str);i<=14;i++) str[i]=' ';|
|     str[i]=nil;                                                      |
|     printf("%s",str);                                                |
|     free(str);                                                       |
========================================================================

If flag(Cf) is on then the string to be displayed needs to be extended
out as if a call to gotoxy(mod * 15,wherey()) were called.  Since I was
having problems with that call, and since it would make portability to 
MSC or QC a bit nasty, i just decided to add white spaces to extend it
15 = strlen(str), and only when the modulo value is 4. 

The line: i=strlen(str)+1;  and  str[i]=nil; will work under any condition
provided that the entire length of "str" is longer then strlen(str)+1.  If
it weren't then you would be trashing up the data segment.  That is why I
calloc()'d it to 128 = to be on the safe side.

Also the directory indicator ('\') and the executable indicator ('*') were
imbedded in "str" this time instead of using seperate printf() statements.

      return(0);
 }
 
===========================[ DELETE THESE ]=============================
 int fa_arch(dir) struct d_info *dir; {                                |
      char attrib;                                                     |
                                                                       |
      attrib=dir->f_inf->ff_attrib;                                    |
      attrib &= FA_ARCH;                                               |
      if(attrib == FA_ARCH) return(TRUE);                              |
      return(FALSE);                                                   |
 }                                                                     |
                                                                       |
 int fa_norm(dir) struct d_info *dir; {                                |
      if(dir->f_inf->ff_attrib & FA_LABEL) return(TRUE);               |
      if(dir->f_inf->ff_attrib & FA_DIREC) return(TRUE);               |
      return(FALSE);                                                   |
 }                                                                     |
                                                                       |
========================================================================

The above functions just take up space.  They arent called by any other
function, and unless you specifically want to keep them, then just delete
them.

 struct d_info *getdirstruct() { /* create memory space for struct */
      struct d_info *head, *next, *dir;
      struct ffblk *fnf;
      int errflag=0;
      FILE *f1;
 
      fnf=(struct ffblk *)calloc(1,sizeof(struct ffblk));
      head=(struct d_info *)calloc(1,sizeof(struct d_info));
      dir=head;
      dir->prev=head;
      dir->next=head;
      dir->f_inf=(struct ffblk *)calloc(1,sizeof(struct ffblk)+8);
      errflag=findfirst(path,fnf,F_FLAG);
      if(!errflag) {
           if(!(fnf->ff_attrib & F_FLAG)) errflag=1;
           tfiles++;
           strlwr(fnf->ff_name);
           memcpy(dir->f_inf,fnf,sizeof(struct ffblk));
           while(!errflag) {
                next=dir;
                dir->next=(struct d_info *)calloc(1,sizeof(struct d_info));
                dir=dir->next;
                dir->next=head;
                dir->prev=next;
                head->prev=dir;
                dir->f_inf=(struct ffblk *)calloc(1,sizeof(struct ffblk)+8);
                errflag=findnext(fnf);
                if(!errflag && !(fnf->ff_attrib & F_FLAG)) errflag=1;
                if(!errflag) tfiles++; /* just to shut warning msg from tc */
                strlwr(fnf->ff_name);
                memcpy(dir->f_inf,fnf,sizeof(struct ffblk));
           }
      }
      free(fnf);
      return(head);
 }
 
 int setflags(flag,val) const int flag, val; {
      switch(flag) {
           case ALL_F:
           case  0: Cf=val; if(flag != ALL_F) break;
           case  1: Ff=val; if(flag != ALL_F) break;
           case  2: Rf=val; if(flag != ALL_F) break;
           case  3: af=val; if(flag != ALL_F) break;
           case  4: bf=val; if(flag != ALL_F) break;
           case  5: cf=val; if(flag != ALL_F) break;
           case  6: df=val; if(flag != ALL_F) break;
           case  7: ff=val; if(flag != ALL_F) break;
           case  8: gf=val; if(flag != ALL_F) break;
           case  9: If=val; if(flag != ALL_F) break;
           case 10: lf=val; if(flag != ALL_F) break;
           case 11: mf=val; if(flag != ALL_F) break;
           case 12: nf=val; if(flag != ALL_F) break;
           case 13: of=val; if(flag != ALL_F) break;
           case 14: pf=val; if(flag != ALL_F) break;
           case 15: qf=val; if(flag != ALL_F) break;
           case 16: rf=val; if(flag != ALL_F) break;
           case 17: sf=val; if(flag != ALL_F) break;
           case 18: tf=val; if(flag != ALL_F) break;
           case 19: uf=val; if(flag != ALL_F) break;
           case 20: xf=val; if(flag != ALL_F) break;
           case 21: zf=val;
      }
      return(TRUE);
 }
 
 int getflags(args) char *args; {
      char tokens[23] = "CFRabcdfgilmnopqrstuxz";
      int i, index, ind=FALSE;
 
      if(args[0]=='-') {
           for(i=1;i <= strlen(args);i++) {
===============================[ CHANGE THIS ]================================
                if((index=istok(args[i],tokens))!=0)                         |
==============================================================================
====================================[ TO ]====================================
|               if((index=istok(args[i],tokens))!=ERR_F)                     |
==============================================================================

Position '0' just happens to be the position of the 'C' flag and it was
returning an error back to the function and exiting the program.

                     ind=setflags(index,TRUE);
                else nfexit(1,args[i]);
           }
      }
      if(Cf && !xf) xf=Cf;
      if(xf && !Cf) Cf=xf;
      if(cf && !uf) uf=cf;
      if(uf && !cf) cf=uf;
      if(lf && cf && !tf) tf=1;
      if(zf && tf)  tf=0; /* the presence of =z flag negates =t flag */
      if(cf && !tf) cf=0;
      return(ind);
 }
 
 char *f_toke(path,fpath) char *path, *fpath; {
      int  i;
 
      for(i=0;path[i]!=nil;i++) {
           if(path[i]=='\\') strncpy(fpath,path,i+1);
      }
      return(fpath);
 }
 
 char *st_toke(path) char *path; {
      int err;
      struct ffblk fnf;
      char *tmps;
 
      err=findfirst(path,&fnf,FA_DIREC);
      tmps=path;
      for(;;tmps++) {
           if(!strcmp(tmps,"*.*") || !strcmp(tmps,"?.?") ||
              !strcmp(tmps,"*.?") || !strcmp(tmps,"?.*")) return(path);
           if(!strcmp(tmps,"\\")) {
                strcat(path,"*.*"); return(path);
           }
           if(!strcmp(tmps,"*") || !strcmp(tmps,"?")) {
                strcat(path,".*");  return(path);
           }
           if(!strcmp(tmps,"*.") || !strcmp(tmps,"?.") || !strcmp(tmps,".")) {
                strcat(path,"*");   return(path);
           }
           if(*tmps=='?') err = =1;
           if(EOL(*tmps)) {
                switch(err) {
                     case  0: strcat(path,"\\");
                     case =1: strcat(path,"*.*");
                }
                return(path);
           }
      }
 }
 
 int sort(ptr) struct d_info *ptr; {
      struct d_info *d1;
      struct d_info *d2;
      void *d3;
 
      if(ff) return(0);  /* ff = fflag = =f (on command line) = no sorting */
      d1=ptr;
      if(!strcmp(d1->f_inf->ff_name,".")) d1=d1->next;
      if(!strncmp(d1= f_inf->ff_name,"..",1)) d1=d1->next;
      for(;d1!=ptr= prev;d1=d1->next)
         for(d2=ptr= prev->prev;d2!=d1->prev;d2=d2->prev) {
            if((!rf &&
              ((!tf && !zf &&
                strcmp(d1= f_inf->ff_name,d2->f_inf->ff_name) > 0) ||
               (!zf && !cf && tf &&
                d1= f_inf->ff_fdate > d2->f_inf->ff_fdate) ||
               (!zf && cf && tf &&
                d1= f_inf->ff_ftime > d2->f_inf->ff_ftime) ||
               (zf && !cf && !tf &&
                d1= f_inf->ff_fsize > d2->f_inf->ff_fsize))) ||
               (rf &&
               ((!tf && !zf &&
                strcmp(d1= f_inf->ff_name,d2->f_inf->ff_name) < 0) ||
               (!zf && !cf && tf &&
                d1= f_inf->ff_fdate < d2->f_inf->ff_fdate) ||
               (!zf && cf && tf &&
                d1= f_inf->ff_ftime < d2->f_inf->ff_ftime) ||
               (zf && !cf && !tf &&
                d1= f_inf->ff_fsize < d2->f_inf->ff_fsize)))) {
               d3=(void *)(d1= f_inf);
               d1= f_inf=d2->f_inf;
               (void *)(d2= f_inf)=d3;
            }
         }
      return(0);
 }
 
 struct d_info *d_inc(ptr) struct d_info *ptr; {
      char *str;
      struct d_info *p1=0L;
 
      p1=ptr;
      str=ptr= f_inf->ff_name;
      if(!strcmp(str,".")) {
           ptr=ptr= next;
           ptr= prev=p1->prev;
           p1= prev->next=ptr;
           free(p1);       /* drat = a hole in memory */
           p1=ptr;
           ==tfiles;
      }
      str=ptr= f_inf->ff_name;
      if(!strcmp(str,"..")) {
           ptr=ptr= next;
           ptr= prev=p1->prev;
           p1= prev->next=ptr;
           free(p1);       /* double drat = another hole in memory */
           ==tfiles;
      }
 
      return(ptr);
 }
 
 main(argc,argv) int argc; char **argv; {
      int i=0;
      struct d_info *dir;
 
      fpath=(char *)calloc(1,128);
      path=(char *)calloc(1,215);
      F_FLAG=FA_ALL;
      setflags(ALL_F,0);
      if(argc == 2) {
           if(argv[1][0]=='-') {
                getflags(argv[1]);
                strcpy(path,"*.*");
           }
           else strcpy(path,argv[1]);
      }
      if(argc  = 3) {
           for(i=1;i<=argc=2;i++)
                if(argv[i][0]=='-')
                     getflags(argv[i]);
           strcpy(path,argv[argc=1]);
      }
      if(Rf) printf("\nls: option =R not yet implemented.\n");
      path=st_toke(path);
      fpath=f_toke(path,fpath);
      if(af) F_FLAG=FA_ALLF;
      if(df) F_FLAG=FA_DIREC;
      head=getdirstruct();
      if(!af) head=d_inc(head);  /* no . and .. unless =a is used */
      sort(head);
      dir=head;
      crlf();
      printf("total %d\n",tfiles);
      while((dir= next != head) && (dir->next != NULL)) {
           ff_stat(dir,&f_stat);
           if((gf || If || lf || nf || of || sf) && !Cf) {
                if(If) pr_inode();
                if(sf) pr_block(dir);
                pr_stat(dir);
                if(gf || lf || nf || of) pr_links();
                if(lf || of || nf) pr_uid(dir);
                if(lf || gf || nf) pr_gid(dir);
                pr_size(dir);
                pr_date(dir);
                pr_time(dir);
           }
=============================[ CHANGE THIS ]==============================
           pr_name(dir);                                                 |
           if(!Cf) {crlf(); i=0; }                                       |
           if(Cf && i%5 == 4) crlf();                                    |
           i++;                                                          |
==========================================================================
=================================[ TO ]===================================
|          pr_name(dir,i);                                               |
|          if(!Cf) crlf();                                               |
|          else if(i++ % 5 == 4) { crlf(); i=0; }                        |
==========================================================================

The pr_name() function was printing sloppy lines when the "C" or "x" flags
were used at the program startup.  So "i" was included as a parameter to
pr_name() to determine the modulo of 5 (see added notes under function
pr_name() above).

           dir=dir->next;
           if(dir->next==head) break;
      }
      if(tfiles==0) printf("%s: file not found\n",path);
 }
 
 ============================ end of file =====================================
 

Darrell (mangor@disk.uucp)