Path: utzoo!attcan!uunet!mcsun!unido!cosmo2!mdnet@cosmo.UUCP From: mdnet@cosmo.UUCP (Dr. Carsten Emde/Klinikum Steglitz der FU Berlin) Newsgroups: comp.os.os9 Subject: Browse (part 2 of 3) Keywords: source Message-ID: <4475@cosmo2.UUCP> Date: 9 Jan 90 08:05:27 GMT Sender: news@cosmo2.UUCP Reply-To: mdnet@cosmo.UUCP (Dr. Carsten Emde/Klinikum Steglitz der FU Berlin) Organization: CosmoNet, D-3000 Hannover 1, FRG Lines: 1043 >From unido!zedat.fu-berlin.dbp.de!EMDE Mon Jan 8 10:11:23 1990 Received: by cosmo.UUCP (sendmail 5.61++/1.3) id AA01227; Mon, 8 Jan 90 16:11:31 +0100 Received: from gmdzi.UUCP (gmdzi) (1261) by unido.informatik.uni-dortmund.de for cosmo id AL22685; Mon, 8 Jan 90 11:05:01 +0100 Received: by gmdzi.UUCP id AA07489; Mon, 8 Jan 90 11:06:19 -0100 Date: 6 Jan 90 14:22 +0100 From: EMDE To: cosmo!mdnet Message-Id: <144:EMDE@zedat.fu-berlin.dbp.de> Subject: Browse (part2 of 3) Status: O Organization: Klinikum Steglitz, FU Berlin, Gastro-Labor X-Mailer: O-X-M [v1.3d] ---- Cut Here and unpack ---- #!/bin/sh # OS-9/xshar: Shell Archiver (v1.22) # Packed January 6, 1990 Saturday 11:49:46 am by carsten # from directory /h0/SYSSRC/BROWSE # # Run the following text with /bin/sh to create: # browse.c # sed 's/^X//' << 'SHAR_EOF' > browse.c && X/* -- Just what the hell am I ??? --- */ X X#include X Xchar help[]= X"Browse through a directory, written by Peter da Silva\n\ XAdapted for OS-9 using TOP's os9lib\n\ XSyntax: browse []\n\ XFunction: show an ls-like directory listing which can be 'edited', i.e.\n\ X files may be tagged and inspected, dumped, executed, deleted,\n\ X renamed, copied, edited etc.\n\ XOptions:\n\ X none\n"; X X#ifdef mc68000 X#define sr sr_ X#define PC PC_ X#endif X X#ifdef OSK X#include X#define GETCWD X#define getcwd getwd X#define minor(i) ((i)&0xFF) X#define major(i) minor((i)>>8) X#define SHELLSYM '$' X#define ASSISTCOM "more /dd/sys/browse.hlp" X#define SAVEMACROS "/h0/sys/browse.macros" X#else X#define remote X#define SHELLSYM '!' X#define ASSISTCOM "more /usr/hlp/browse.doc" X#define SAVEMACROS "/usr/tmp/macros" X#endif X X#ifdef M_XENIX X#define USG X#define rindex strrchr X#define GETCWD X#else X#ifdef L_ctermid X#define USG X#define rindex strrchr X#define minor(i) ((i)&0xFF) X#define major(i) minor((i)>>8) X#else X#ifndef OSK X#include X#endif X#endif X#endif X X/* -- Miscellaneous include files -- */ X X#ifdef OSK X#include X#include X#include X#include X#endif X#include /* NCARGS, and others */ X#ifndef M_XENIX X#include /* data types for various files */ X#endif X#include /* stat data structure for getdir(), statout() */ X#include /* dir data structure for getdir() */ X#include /* passwd data structure for u_name() */ X#include /* group data structure for g_name() */ X X#ifdef BSD X#include /* time data structure for printime() */ X#else X#ifndef OSK X#include /* time data structure for printime() */ X#endif X#endif X#ifdef USG X#ifdef M_XENIX X#include X#endif X#include X#else X#ifndef OSK X#include /* terminal modes for tinit(), tend() */ X#endif X#endif X X#include X X/* -- make information -- XBUILD Xbrowse: browse.c X cc browse.c -O -o browse -ltermlib XEND X*/ X X/* -- Miscellaneous defines -- */ X#define FALSE 0 X#define TRUE 1 X X#define MAXID 64 X#define MAXLINE 256 X#ifdef OSK X#define MAXENTS 512 X#define NCOL 54 X#define MAXNAME 24 X#else X#define MAXENTS 320 X#define NCOL 64 X#define MAXNAME 14 X#endif X#define FILENAME 256 X#define MAXARGC (NCARGS/16) /* Estimate max ARGC */ X#define CHARSET 256 /* Number of macros == size of byte */ X#define NOMAC (0) /* Null macro (last) */ X#define TERMBUF 1024 /* Size of term buf for termcap */ X#define SMALLBUF 256 X#define NAME 1 X#define SEC 2 X X/* -- Extended directory entry format -- */ Xstruct entry { X char *e_name; X int e_flags; X#define FTAGGED (1<<0) X#define FPERMANENT (1<<1) X struct stat e_stat; /* file status field */ X char e_uname[9]; /* user name */ X char e_gname[9]; /* user's group name */ X#ifdef OSK X unsigned long e_secno; X#endif X} X*xentries[MAXENTS], **entries=xentries; Xint nentries; X X/* -- Look-up cache for user names -- */ Xstruct idtab { X int id_id; /* user (or group) id */ X char id_name[9]; /* name[8] + filler */ X} Xu_list[MAXID], /* Matched user id's. */ Xg_list[MAXID]; /* ditto group */ Xint u_ptr=0, g_ptr=0; /* current entries */ X X/* -- Global variables -- */ XFILE *efp; /* Environment file */ Xchar efname[MAXLINE]; /* " name */ Xchar *tent; /* Pointer to tbuf */ Xchar PC; /* Pad character */ Xchar *UP, *BC; /* Upline, backsapce character */ Xshort ospeed; /* Terminal output speed */ Xchar termbuf[TERMBUF]; /* Place to put term info */ X Xchar *macbuf[CHARSET], ungetbuf[SMALLBUF]; X /* Buffers for pushback and macros */ Xchar c_macro=NOMAC; /* current macro */ Xchar *macptr = ""; /* Pointer to currently executing macro */ Xchar *ungetptr = ungetbuf; /* Pointer to pushed-back characters */ X Xchar *errname; /* Name of file error found in */ Xextern int errno; /* system error number */ Xint xerrno; /* extended error number */ Xint ccol=NCOL; /* Width of used display, current column */ Xint quickmode; /* short display mode (files only) */ X X#ifdef USG Xstruct termio rawbuf; Xstruct termio cookedbuf; X#else X#ifdef OSK Xstruct sgbuf cookopts,rawopts; Xint signhndl(); X#else Xstruct sgttyb sgbuf; /* buffer for terminal mode info */ Xint rawflags, cookflags; /* flags for raw & cooked tty mode */ X#endif X#endif X Xchar *cm, /* Cursor motion */ X *cs, /* Change scrolling region */ X *sf, /* - scroll forward */ X *sr, /* - scroll backwards */ X *ce, /* Clear to end of line */ X *cl, /* Clear screen */ X *al, /* Insert line */ X *dl, /* delete ditto */ X *so, /* standout */ X *se, /* standout end */ X *us, /* underline */ X *ue, /* underline end */ X *ti, /* Init terminal */ X *te; /* Reset terminal */ Xint li, /* lines on screen */ X co; /* columns ditto */ Xchar xn; /* Magic cookie kludge */ X X/* -- Global error messages -- */ Xchar *emesg[4]={ X "??", X#define TOO_MANY 1 X "Too many directory entries", X#define NOMATCH 2 X "No match", X 0 X}; X Xint top, curr; /* Positions of screen in directory */ X#define bottom ((top+nlines>nentries)?nentries:(top+nlines)) Xchar *dot; /* name of current directory */ Xint nlines; /* number of lines displayed on page */ Xchar display_up; /* Does the display exist? */ Xint todump=1; /* Do we want to dump data? */ Xint ended; /* Have we quite finished? */ Xint intrup; /* Have we been interrupted? */ Xchar *HOME; /* Where did I start from? */ Xchar *SHELL; /* How do I run programs? */ X X/* -- types of functions !!! */ Xchar *getenv(), *tgetstr(); Xchar *malloc(); X X#define NEW(t) (t *)malloc(sizeof (t)) X#define NIL(t) ((t) 0) X X/* -- Code starts here: dummy main -- */ Xmain(ac, av, ep) Xint ac; Xchar **av; Xchar **ep; X{ X int i; X X if(ac>1) X { X for(i=1; i2) X { X perror("only one argument may be specified."); X exit(0); X } X if(chdir(av[1])==-1) X { X perror("can't access directory specified",av[1]); X exit(0); X } X } X X sprintf(efname, "/tmp/br.env.%d", getpid()); X HOME=getenv("HOME"); X SHELL=getenv("SHELL"); X X#ifndef OSK X dumpenv(ep); X#endif X X intrup=0; X tinit(getenv("TERM")); X clear_all(); X X#ifdef OSK X stdin->_flag|=_RBF; stdin->_flag|=_UNBUF; X#endif X X browse(); X tend(); X#ifndef OSK X unlink(efname); X#endif X} X Xclear_all() X{ X int i; X X for(i = 0; i < MAXENTS; i++) X entries[i] = 0; X} X Xchar *clone(name) Xchar *name; X{ X char *hold; X X hold = (char *)malloc(strlen(name)+1); X X if(hold==0) X return 0; X strcpy(hold, name); X return hold; X} X Xnewname(e, name) Xstruct entry *e; Xchar *name; X{ X if(e->e_name) X free(e->e_name); X e->e_name = clone(name); X} X X#if (BSD || OSK) Xreadent(dp, db) XDIR *dp; Xstruct direct *db; X{ X struct direct *ptr; X X ptr = readdir(dp); X if(!ptr) return 0; X X *db = *ptr; /* V7 'C' and above... safe, since UCB=V7+ */ X free(ptr); X return 1; X} X#else X#define opendir(n) fopen(n, "r") X#define DIR FILE Xreadent(dp, db) XDIR *dp; Xstruct direct *db; X{ X if(fread(db, sizeof(struct direct), 1, dp)) X return 1; X /* else */ X return 0; X} X#define closedir fclose X#endif X Xgetdir() X{ X X#ifdef OSK X struct fildes f; X struct tm t; X int physdisk, oldid; X char pdot[32], *slash; X#endif X X char *u_name(), *g_name(); X DIR *dp; X int valid; X struct direct *hold = NEW(struct direct); X int i, p; X X if(!(dp = opendir("."))) { X errname="."; X return FALSE; X } X X p = 0; X for(i = 0; i < nentries; i++) { X if(entries[i]->e_flags & FPERMANENT) { X if(p != i) { X struct entry *hold; X hold = entries[p]; X entries[p] = entries[i]; X entries[i] = hold; X } X p++; X } X } X X for(nentries = p; !intrup && nentries < MAXENTS; nentries += valid) { X X if(!entries[nentries]) { X entries[nentries] = NEW(struct entry); X if(!entries[nentries]) X break; X entries[nentries]->e_name = NIL(char *); X } X X if(!readent(dp, hold)) { X p=nentries; break; X } X X#ifndef OSK X valid = (hold->d_ino != 0); X#else X valid = TRUE; X entries[nentries]->e_secno=hold->d_addr; X#endif X X if(valid) { X#ifndef OSK X if(stat(hold->d_name, &entries[nentries]->e_stat)==-1) { X closedir(dp); X errname=hold->d_name; X free(hold); X return FALSE; X } X#endif X X newname(entries[nentries], hold->d_name); X X#ifndef BSD /* truncate name to 14 characters in non-BSD systems */ X#ifndef OSK X if(strlen(entries[nentries]->e_name)>14) X entries[nentries]->e_name[14] = 0; X#endif X#endif X X entries[nentries]->e_flags = 0; X X#ifndef OSK X strcpy(entries[nentries]->e_uname, X u_name(entries[nentries]->e_stat.st_uid)); X X strcpy(entries[nentries]->e_gname, X g_name(entries[nentries]->e_stat.st_gid)); X#endif X } X } X X closedir(dp); X X free(hold); X X#ifdef OSK X sortdir(SEC); /* optimize head movements */ X oldid=getuid(); super(); X strcpy(pdot,dot); X if(slash=index(pdot+1,'/')) strcpy(slash,"@"); else strcat(pdot,"@"); X if((physdisk=open(pdot,S_IREAD))==-1) return FALSE; X for(nentries = 0; !intrup && nentries < p; nentries ++) { X lseek(physdisk,(entries[nentries]->e_secno)<<8,0); X read(physdisk,&f,sizeof(f)); X X t.tm_year = (int) f.fd_date[0]; X t.tm_mon = (int) f.fd_date[1] - 1; X t.tm_mday = (int) f.fd_date[2]; X t.tm_hour = (int) f.fd_date[3]; X t.tm_min = (int) f.fd_date[4]; X t.tm_sec = 0; X t.tm_isdst = -1; X X entries[nentries]->e_stat.st_atime = X entries[nentries]->e_stat.st_mtime = mktime(&t); X X t.tm_year = (int) f.fd_dcr[0]; X t.tm_mon = (int) f.fd_dcr[1] - 1; X t.tm_mday = (int) f.fd_dcr[2]; X t.tm_hour = t.tm_min = t.tm_sec = 0; X t.tm_isdst = -1; X X entries[nentries]->e_stat.st_ctime = mktime(&t); X memcpy(&(entries[nentries]->e_stat.st_size), f.fd_fsize, X sizeof(long)); X entries[nentries]->e_stat.st_uid = f.fd_own[1]; X entries[nentries]->e_stat.st_gid = f.fd_own[0]; X entries[nentries]->e_stat.st_mode = f.fd_att; X entries[nentries]->e_stat.st_nlink = f.fd_link; X X strcpy(entries[nentries]->e_uname, X u_name(entries[nentries]->e_stat.st_uid)); X X strcpy(entries[nentries]->e_gname, X g_name(entries[nentries]->e_stat.st_gid)); X } X close(physdisk); X setuid(oldid); X#endif X X if(intrup) X return FALSE; X X if(nentries>=MAXENTS || entries[nentries]==NIL(struct entry *)) { X errno=0; X xerrno=TOO_MANY; X errname="."; X return FALSE; X } X X sortdir(NAME); X X if(intrup) X return FALSE; X return TRUE; X} X Xat_current() X{ X at_file(curr); X} X Xat_file(file) Xint file; X{ X if(display_up) { X if(file < top || file >= top+nlines) X return 0; X at(0, curr-top+2); X } else { X if(file != curr) X return 0; X cmdline(); X } X return 1; X} X Xdisplay_flags(flags) X{ X outc((flags&FTAGGED)?'+':((flags&FPERMANENT)?'!':' ')); X} X Xrepaint_flags() X{ X if(!display_up) return; X at(quickmode?0:NCOL-1, curr-top+2); X display_flags(entries[curr]->e_flags); X} X X/* Xrepaint_current() X{ X if(!display_up) return; X at_current(); X dump(curr, curr+1); X} X*/ X Xtag() X{ X entries[curr]->e_flags ^= FTAGGED; X repaint_flags(); X} X Xtag_all(flag) Xint flag; X{ X int i; X X for(i = 0; i < nentries; i++) X if(flag) X { X if(!isdir(entries[i])) entries[i]->e_flags |= FTAGGED; X } X else X entries[i]->e_flags &= ~FTAGGED; X if(display_up) X todump = TRUE; X} X Xdelete_from_display(file) Xint file; X{ X if(!display_up) return; X X if(file>=top+nlines) return; X X if(file < top) file = top; X X scroll(2+file-top, 2+nlines, 1); X at(0, 2+nlines-1); X if(top+nlines >= nentries) X outc('~'); X else X dump(bottom, bottom+1); X} X Xdelete_file_entry(file) Xint file; X{ X struct entry *hold; X int i; X X delete_from_display(file); X X hold = entries[file]; X for(i=file; i= nentries) { X curr--; X if(top >= nentries) { X top--; X display_up = 0; X todump = 1; X } X } X} X Xremove_one(file, doit) Xint file; Xint doit; X{ X if(!doit) { X cmdline(); X outs("Delete "); X ctlouts(entries[file]->e_name); X outs(" [n]?"); X fflush(stdout); X doit = getch() == 'y'; X outs(doit?"Yes.":"No."); X fflush(stdout); X } X if(doit) { X if(unlink(entries[file]->e_name) == 0) { X cmdline(); X outs("Deleted "); X ctlouts(entries[file]->e_name); X outs("."); X delete_file_entry(file); X return 1; X } else { X wperror(entries[file]->e_name); X return 0; X } X } X return 0; X} X Xremove(doit) Xint doit; X{ X int i; X int found_tags; X X found_tags = 0; X i = 0; X while(i < nentries) { X if(entries[i]->e_flags & FTAGGED) { X found_tags = 1; X if(!remove_one(i, doit)) /* decrements nentries */ X break; X } else X i++; X } X if(!found_tags) X remove_one(curr, doit); X} X Xinsert_entry_at(ent, i) Xstruct entry *ent; Xint i; X{ X struct entry *hold; X int j; X X /* Allocate slot at end */ X if(!entries[nentries]) { X entries[nentries] = NEW(struct entry); X if(!entries[nentries]) X return 0; X entries[nentries]->e_name = NIL(char *); X } else if(entries[nentries]->e_name) { X free(entries[nentries]->e_name); X entries[nentries]->e_name = NIL(char *); X } X X /* Copy data into slot */ X *entries[nentries] = *ent; X entries[nentries]->e_name = clone(ent->e_name); X if(!entries[nentries]->e_name) X return 0; X X if(i != nentries) { X /* Rotate slot to middle */ X hold = entries[nentries]; X for(j = nentries; j > i; j--) X entries[j] = entries[j-1]; X entries[i] = hold; X } X nentries++; X X if(display_up) { X if(i < top) X i = top; X if(i >= bottom) X return; X scroll(2+i-top, 2+nlines, -1); X at(0, 2+i-top); X dump(i, i+1); X } X} X Xinsert_entry(ent) Xstruct entry *ent; X{ X int i; X X if(nentries >= MAXENTS) X return 0; X X for(i = 0; i < nentries; i++) X if(entcmpnam(&ent, &entries[i]) < 0) X break; X X return insert_entry_at(ent, i); X} X Xassist() X{ X char cmdbuf[MAXLINE]; X X sprintf(cmdbuf, ASSISTCOM); X if(sys(cmdbuf, 1)) X perror(cmdbuf); X} X Xhexdump() X{ X char cmdbuf[MAXLINE]; X X sprintf(cmdbuf, "dump %s", entries[curr]->e_name); X if(sys(cmdbuf, 1)) X perror(cmdbuf); X} X Xmove() X{ X char scratch[FILENAME]; X struct entry hold; X char inps(); X X hold = *entries[curr]; X X cmdline(); X outs("Rename "); X ctlouts(entries[curr]->e_name); X outc(' '); X if(inps(scratch, entries[curr]->e_name, 0)=='\033') { X killcmd(); X return; X } X if(link(entries[curr]->e_name, scratch)!=0) { X char tmbuf[42]; X sprintf(tmbuf, "(rename %s %s)", entries[curr]->e_name, scratch); X wperror(tmbuf); X return; X } X if(unlink(entries[curr]->e_name)!=0) { X wperror(entries[curr]->e_name); X return; X } X X hold.e_name = scratch; X hold.e_flags &= ~FTAGGED; X X delete_file_entry(curr); X insert_entry(&hold); X} X Xpname(name, mode) Xchar *name; Xint mode; X{ X int i; X char *slash, *rindex(); X int max=quickmode?MAXLINE:(MAXNAME+1); X X#ifdef OSK X if(mode&S_IFDIR) X#else X if((mode&S_IFMT)==S_IFDIR) X#endif X max--; X X#ifndef OSK X else if((mode&S_IFMT)==S_IFREG && (mode&0111)) X max--; X else if((mode&S_IFMT)!=S_IFREG) X max--; X#endif X X if(!quickmode && (slash=rindex(name, '/'))) { X name=slash; X outc('<'); X max--; X } X for(i=0; i"); X X#ifdef OSK X if(mode&S_IFDIR) { X#else X if((mode&S_IFMT)==S_IFDIR) { X#endif X outc('/'); X } X X#ifndef OSK X else if((mode&S_IFMT)==S_IFREG && (mode&0111)) { X outc('*'); X } X else if((mode&S_IFMT)!=S_IFREG) { X outc('?'); X } X#endif X X} X Xsortdir(ele) Xint ele; X{ X int entcmpnam(),entcmpsec(); X X if(ele==NAME) X qsort(entries, nentries, sizeof(struct entry *), entcmpnam); X if(ele==SEC) X qsort(entries, nentries, sizeof(struct entry *), entcmpsec); X} X X#ifndef OSK Xaddname(flag) Xchar flag; X{ X char buf[FILENAME], *ptr, *tmp; X char scratch[FILENAME]; X struct entry hold; X char inps(); X X cmdline(); X outs("Add "); X if(inps(scratch, entries[curr]->e_name, 0)=='\033') { X killcmd(); X return; X } X X if(stat(scratch, &hold.e_stat)==-1) { X wperror(scratch); X return; X } X if(flag!='+' && *scratch != '/') { X strcpy(buf, dot); X ptr = scratch; X for(;;) { /* eat '../' and './' */ X if(ptr[0]=='.' && ptr[1]=='.' && X (ptr[2]=='/' || !ptr[2])) { X tmp = rindex(buf, '/'); X if(!tmp) break; X *tmp=0; X ptr += 2+(ptr[2]=='/'); X continue; X } X if(ptr[0]=='.' && X (ptr[1]=='/' || !ptr[1])) { X ptr += 1+(ptr[1]=='/'); X continue; X } X break; X } X if(*ptr) { X strcat(buf, "/"); X strcat(buf, ptr); X } X hold.e_name = buf; X } else X hold.e_name = scratch; X strcpy(hold.e_uname, X u_name(hold.e_stat.st_uid)); X strcpy(hold.e_gname, X g_name(hold.e_stat.st_gid)); X hold.e_flags = 0; X if(flag!='+') X hold.e_flags |= FPERMANENT; X insert_entry(&hold); X} X Xaddperm() X{ X char buf[FILENAME], *ptr, *tmp; X struct entry hold; X int entcmpnam(), i; X X if(entries[curr]->e_flags & FPERMANENT) X return; X X if(entries[curr]->e_name[0]!='/') { X strcpy(buf, dot); X ptr = entries[curr]->e_name; X for(;;) { /* eat '../' and './' */ X if(ptr[0]=='.' && ptr[1]=='.' && X (ptr[2]=='/' || !ptr[2])) { X tmp = rindex(buf, '/'); X if(!tmp) break; X *tmp=0; X ptr += 2+(ptr[2]=='/'); X continue; X } X if(ptr[0]=='.' && X (ptr[1]=='/' || !ptr[1])) { X ptr += 1+(ptr[1]=='/'); X continue; X } X break; X } X if(*ptr) { X strcat(buf, "/"); X strcat(buf, ptr); X } X hold = *entries[curr]; X X hold.e_name = buf; X hold.e_flags &= ~FTAGGED; X hold.e_flags |= FPERMANENT; X insert_entry(&hold); X } else { X entries[curr]->e_flags |= FPERMANENT; X entries[curr]->e_flags &= ~FTAGGED; X repaint_flags(); X } X} X Xdelperm() X{ X entries[curr]->e_flags &= ~(FPERMANENT|FTAGGED); X repaint_flags(); X} X#endif X Xentcmpnam(e1, e2) Xstruct entry **e1, **e2; X{ X if((*e1)->e_name[0] == '/') { X if((*e2)->e_name[0] != '/') X return 1; X } else if((*e2)->e_name[0] == '/') X return -1; X X return strcmp((*e1)->e_name, (*e2)->e_name); X} X Xentcmpsec(e1, e2) Xstruct entry **e1, **e2; X{ X if((*e1)->e_secno < (*e2)->e_secno) return -1; X if((*e1)->e_secno > (*e2)->e_secno) return 1; X return 0; X} X Xdump(start, end) Xint start; Xint end; X{ X int i; X int lo = (starte_name, X &entries[i]->e_stat, X entries[i]->e_uname, X entries[i]->e_gname, X entries[i]->e_flags); X nl(); X } X return TRUE; X} X Xstatout(name, sbuf, user, group, flags) Xchar *name; Xstruct stat *sbuf; Xchar *user, *group; Xint flags; X{ X int mode = sbuf->st_mode; X X if(!quickmode) { X#ifndef OSK X printf("%5u ", sbuf->st_ino); X#endif X X X#ifdef OSK X if(mode&S_IFDIR) outc('d'); else outc('-'); X if(mode&S_ISHARE) outc('s'); else outc('-'); X if(mode&S_IOEXEC) outc('e'); else outc('-'); X if(mode&S_IOWRITE) outc('w'); else outc('-'); X if(mode&S_IOREAD) outc('r'); else outc('-'); X if(mode&S_IEXEC) outc('e'); else outc('-'); X if(mode&S_IWRITE) outc('w'); else outc('-'); X if(mode&S_IREAD) outc('r'); else outc('-'); X#else X if((mode&S_IFMT)==S_IFCHR) outc('c'); X else if((mode&S_IFMT)==S_IFBLK) outc('b'); X else if((mode&S_IFMT)==S_IFDIR) outc('d'); X else if((mode&S_IFMT)==S_IFREG) outc('-'); X else outc('?'); X triad((mode>>6)&7, mode&S_ISUID, 's'); X triad((mode>>3)&7, mode&S_ISGID, 's'); X triad(mode&7, mode&S_ISVTX, 't'); X#endif X X outc(' '); X X printf("%1u ", sbuf->st_nlink); X printf("%-8s ", user); X printf("%-8s ", group); X X#ifdef OSK X if(!(mode&S_IFDIR)) X#else X if((mode&S_IFMT)==S_IFREG || (mode&S_IFMT)==S_IFDIR)) X#endif X printf("%7ld ", sbuf->st_size); X else X#ifdef OSK X printf(" --- "); X#else X X printf("%3d,%3d ", X major(sbuf->st_rdev),