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)