/* myls.c: my own version of ls. */ /* Define SELFTALK if you want this program to self-talk under jupiter */ /* the symbol DOSLIKE is used to conditionally compile those constructs * that are common to DOS and NT, but not typical of Unix. */ #ifdef MSDOS #define DOSLIKE #endif #ifdef _WIN32 #define DOSLIKE #endif #ifdef LINUX_LARGEFILE #define _FILE_OFFSET_BITS 64 #endif #include #include #include #include #include #include #include #include #ifdef DOSLIKE #include #endif #include #ifdef MSDOS #include #endif #ifndef DOSLIKE #include #include #include #include #include #endif typedef unsigned char bool; #define false 0 #define true 1 #define stringEqual !strcmp #ifdef DOSLIKE static char global[] = "/*.*"; #ifdef MSDOS static struct _find_t dta; #else static struct _finddata_t dta; #endif #else static struct stat statbuf; static unsigned short modebits; static bool issymlink; static struct passwd *pwbuf; static struct group *grpbuf; static struct dirent *de; static DIR *df; #endif bool iaflag; /* interactive */ #define NFILES 2000 /* max number of files in a directory */ static char *filenames[NFILES]; static int nfiles; #ifdef MSDOS _setenvp(){} /* no enviromnent */ #endif void loopmain_init() { #ifdef _WIN32 iaflag = true; #else iaflag = isatty(1); #endif #ifdef SELFTALK if(iaflag) { printf("\33{ebuf"); fflush(stdout); } #endif } /* loopmain_init */ extern int loopmain(char *) ; void eprint(const char *s, ...) { char bailflag; va_list p; int a1, a2, a3, a4, a5; va_start(p, s); a1 = va_arg(p, int); a2 = va_arg(p, int); a3 = va_arg(p, int); a4 = va_arg(p, int); a5 = va_arg(p, int); va_end(p); bailflag = -1; if(*s == '@') { ++s; bailflag = 1; fprintf(stderr, "disaster, "); } if(*s >= '0' && *s <= '9') { bailflag = *s - '0'; ++s; } fprintf(stderr, s, a1,a2,a3,a4,a5); fprintf(stderr, "\n"); if(bailflag >= 0) exit(bailflag); } /* eprint */ char *ZC_usage = "usage: ls [-adlipt] [files|directories]"; void usage() { eprint("1%s", ZC_usage); } /* usage */ bool opt_a; bool opt_d; bool opt_l; bool opt_i; bool opt_p; bool opt_t; int main(int argc, char **argv) { char **new_argv, **save_argv, *s, *t; int new_argc, save_argc, status, i; static char *single[3]; single[0] = *argv; save_argv = argv; save_argc = argc; new_argv = argv+1; new_argc = 0; for(++argv, --argc; argc; ++argv, --argc) { s = *argv; if(*s != '-' || !s[1]) { /* regular arg, no options */ *new_argv++ = s; ++new_argc; continue; } for(++s; *s; ++s) switch(*s) { case 'a': opt_a = true; continue; case 'd': opt_d = true; continue; case 'l': opt_l = true; continue; case 'i': opt_i = true; continue; case 'p': opt_p = true; continue; case 't': opt_t = true; continue; default: usage(); /* unknown option */ } /* end switch on option */ } /* end options */ status = 0; argv = save_argv; argc = ++new_argc; if(argc < save_argc) argv[argc] = 0; /* at this point it looks like main was called with just the args, * options are magically set. */ if(argc == 1) { single[1] = ""; argv = single; argc = 2; } loopmain_init(); for(i = 1; i < argc; ++i) { status |= loopmain(argv[i]); } status |= loopmain_close(); exit(status); return 0; /* to quiet -W3 */ } /* main */ static void *emalloc(unsigned n) { void *s; if(! (s = malloc(n))) eprint("1error allocating %u bytes", n); return s; } /* emalloc */ static void output(char **list, int n, bool expand) ; static void dirlist(char *dir) ; static char *fls(char *dirname, char *base, bool fromcmd) ; int loopmain(char *arg) { if(stringEqual(arg, "")) { dirlist(0); return 0; } #ifdef DOSLIKE #ifdef MSDOS if(_dos_findfirst(arg, 027, &dta)) { #else if(_findfirst(arg, &dta) < 0) { #endif eprint("%s not found", arg); return 1; } #else issymlink = false; if(!lstat(arg, &statbuf)) { modebits = statbuf.st_mode; if((modebits & S_IFMT) == S_IFLNK) issymlink = true; } if(stat(arg, &statbuf)) { eprint("%s%s not found", arg, issymlink ? "@" : ""); return 1; } #endif if(nfiles == NFILES) eprint("1too many arguments"); filenames[nfiles++] = fls(NULL, arg, true); return 0; } /* loopmain */ int loopmain_close() { int i; char *p; output(filenames, nfiles, (bool)!opt_d); if(!opt_d) { /* expand directories */ for(i=0; i filenames[i] && p[-1] == '@') p[-1] = 0; dirlist(filenames[i]); } } } #ifdef SELFTALK if(iaflag) { printf("\33{for\33{read"); fflush(stdout); } #endif return 0; } /* loopmain_close */ /* list files in sorted order */ static void output(char **list, int n, bool expand) { register i; char *swap; bool change; /* bubble sort */ change = true; while(change) { change = false; for(i=0; id_ino == 0) continue; if(de->d_name[0] == '.') { if(!opt_a) continue; if(de->d_name[1] == 0) continue; if(de->d_name[1] == '.' && de->d_name[2] == 0) continue; } #endif if(nfiles1 == NFILES) eprint("1too many files in directory %s", dir ? dir : "."); filenames1[nfiles1++] = fls(dir,0, false); #ifdef DOSLIKE nextfile: #ifdef MSDOS rc = _dos_findnext(&dta); #else rc = _findnext(handle, &dta); #endif } /* end loop over files in directory */ if(allocate) free(p); #else } /* end reding directory entries */ closedir(df); #endif output(filenames1, nfiles1, 0); putchar('\n'); } /* dirlist */ static char *fls(char *dirname, char *base, bool fromcmd) { char *buf; static char *months[13]={0, "Jan","Feb","Mar","Apr", "May","Jun","Jul","Aug", "Sep","Oct","Nov","Dec" }; char *s; struct tm *cur_tm; #ifndef DOSLIKE #else #ifdef MSDOS int date,time; #endif #endif if(base) { buf = emalloc(strlen(base) + 70); strcpy(buf, base); } else { #ifdef DOSLIKE buf = emalloc(strlen(dta.name) + 70); strcpy(buf, dta.name); #else buf = emalloc(strlen(de->d_name) + 70); buf[0] = 0; if(dirname) { strcpy(buf, dirname); strcat(buf, "/"); } strcat(buf, de->d_name); issymlink = false; memset(&statbuf, 0, sizeof(statbuf)); lstat(buf, &statbuf); modebits = statbuf.st_mode; if((modebits & S_IFMT) == S_IFLNK) issymlink = true; memset(&statbuf, 0, sizeof(statbuf)); /* This could fail if it's a broken symbolic link */ stat(buf, &statbuf); strcpy(buf, de->d_name); #endif } s = buf + strlen(buf); #ifdef DOSLIKE if(dta.attrib & 020) *s++ = '/'; #else if(issymlink) *s++ = '@'; modebits = statbuf.st_mode; if((modebits & S_IFMT) == S_IFDIR) *s++ = '/'; if((modebits & S_IFMT) == S_IFBLK) *s++ = '*'; if((modebits & S_IFMT) == S_IFCHR) *s++ = '<'; if((modebits & S_IFMT) == S_IFIFO) *s++ = '|'; if((modebits & S_IFMT) == S_IFSOCK) *s++ = '^'; #endif *s = 0; if(s[-1] == '/' && fromcmd && !opt_d) return buf; if(opt_l|opt_i|opt_p|opt_t) *s++ = ':'; #ifndef DOSLIKE if(opt_i) { sprintf(s, " I%d L%d", statbuf.st_ino, statbuf.st_nlink); s = buf+strlen(buf); if(modebits & S_IFCHR) { sprintf(s, " M%d/%d", (int)(statbuf.st_rdev>>8), (int)(statbuf.st_rdev&0xff)); s = buf+strlen(buf); } } /* inode flag */ if(opt_p) { *s++ = ' '; pwbuf = getpwuid(statbuf.st_uid); if(pwbuf) strcpy(s, pwbuf->pw_name); else sprintf(s, "%d", statbuf.st_uid); s += strlen(s); *s++ = ' '; grpbuf = getgrgid(statbuf.st_gid); if(grpbuf) strcpy(s, grpbuf->gr_name); else sprintf(s, "%d", statbuf.st_gid); s += strlen(s); *s++ = ' '; modebits &= 07777; if(modebits & 07000) *s++ = '0' + (modebits>>9); modebits &= 0777; *s++ = '0' + (modebits>>6); modebits &= 077; *s++ = '0' + (modebits>>3); modebits &= 7; *s++ = '0'+modebits; } /* permission flag */ #endif if(opt_l) { #ifdef LINUX_LARGEFILE const char* size_specifier = " %lld"; #else const char* size_specifier = " %ld"; #endif #ifdef DOSLIKE sprintf(s, " %c%c%c", (dta.attrib&04)?'s':' ', (dta.attrib&02)?'h':' ', (dta.attrib&01)?'r':' '); s += 4; sprintf(s, size_specifier, dta.size); #else sprintf(s, size_specifier, #ifdef _WIN32 dta.size); #else statbuf.st_size); #endif #endif s = buf + strlen(buf); } /* length */ if(opt_t) { #ifdef MSDOS time=dta.wr_time; date=dta.wr_date; sprintf(s, " %s %2d %02d:%02d", months[(date>>5) & 0x0F], (date ) & 0x1F, (time>>11) & 0x1F, (time>> 5) & 0x3F); #else #ifdef _WIN32 cur_tm = localtime(&dta.time_write); #else cur_tm = localtime(&statbuf.st_mtime); #endif sprintf(s, " %s %d %d %02d:%02d", months[cur_tm->tm_mon+1], cur_tm->tm_mday, cur_tm->tm_year+1900, cur_tm->tm_hour, cur_tm->tm_min); #endif s = buf + strlen(buf); } /* time */ *s = 0; return buf; } /* fls */ /* end of generated source file, copy this comment just to make sure * we aren't out of disk space. The source copy routine checks for this. */