/* L - Display files and directories in columns. Original effort by Fabio Rossetti. (c) 1989 by Fabio Rossetti To compile under Lattice C v5.0x use: lc -O -v -cus l blink lib:cres.o l.o to l lib lib:a.lib lib:lc.lib sd nd */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* command line arguments */ #define PAT 0 #define CD 1 #define NOCOL 2 #define NARGS 3 /* their # */ /* */ /* global */ /* */ struct ArpBase *ArpBase; struct IntuitionBase *IntuitionBase; struct Window *CliWin; /* pointer to console window */ struct Process *Pr; /* line arguments stuff, must be accessed by several functions */ LONG argc; STRPTR argv[NARGS]; /* general purpose string buffers */ TEXT Bf[256]="\0"; TEXT Buf[256]="\0"; /* general purpose lock pointer */ BPTR Lck; struct FileInfoBlock *Fib; TEXT *Path; /* this is exec stuff for GetWin, to be kept global for Cleanup() */ struct MsgPort iorp = { {0, 0, NT_MSGPORT, 0, 0}, 0, -1, /* initialize signal to -1 */ 0, /* start with empty list */ {&iorp.mp_MsgList.lh_Tail, 0, &iorp.mp_MsgList.lh_Head, 0, 0} }; struct IOStdReq ior = { {{0, 0, 0, 0, 0}, &iorp, 0}, 0 /* device is zero */ }; /* pointer to ordered list of files to be displayed */ struct DirectoryEntry *FileList = NULL; /* Stamptostr() stuff, kept global for future expansions and v5.0 quirks */ struct DateTime D = { 0L,0L,0L, FORMAT_DOS, NULL, NULL, NULL, NULL }; TEXT Date[LEN_DATSTRING], Time[LEN_DATSTRING], Day[LEN_DATSTRING]; VOID MemCleanup() { } /* general shutdown routine*/ VOID Cleanup(code,retcode,filelist,anchor) LONG code; LONG retcode; struct DirectoryEntry *filelist; struct AnchorPath *anchor; { if (ior.io_Device != 0) { if (iorp.mp_SigBit != -1) { FreeSignal(iorp.mp_SigBit); } CloseDevice(&ior); } CloseLibrary((struct Library*)ArpBase); if (anchor) FreeAnchorChain(anchor); if (filelist) FreeDAList(filelist); Pr->pr_Result2=retcode; exit(code); } /* bulletproofly obtain a pointer to the CLI window sending a ACTION_DISK_INFO packet to the console process and looking into InfoData */ struct Window *GetWin() { struct MsgPort *con; struct StandardPacket *packet=NULL; struct InfoData *id=NULL; /* open the console device */ if ((OpenDevice("console.device", -1, &ior, 0)) != 0) { Cleanup(RETURN_FAIL,ERROR_DEVICE_NOT_MOUNTED,NULL,NULL); } /* set up the message port in the I/O request */ if ((iorp.mp_SigBit = AllocSignal(-1)) < 0) { Cleanup(RETURN_FAIL,ERROR_NO_FREE_STORE,NULL,NULL); } iorp.mp_SigTask = (struct Task*)Pr; /* try to find console associated with calling process */ /* if started from CLI, than is */ if ((iorp.mp_SigTask->tc_Node.ln_Type == NT_PROCESS)) { con = (struct MsgPort *) ((struct Process *) iorp.mp_SigTask) -> pr_ConsoleTask; if (con != 0) { if ((packet = (struct StandardPacket *) ArpAlloc(sizeof(*packet)))) { if ((id = (struct id *) ArpAlloc(sizeof(*id)))) { /* this is the console handlers packet port */ packet->sp_Msg.mn_Node.ln_Name = &(packet->sp_Pkt); packet->sp_Pkt.dp_Link = &(packet->sp_Msg); packet->sp_Pkt.dp_Port = &iorp; packet->sp_Pkt.dp_Type = ACTION_DISK_INFO; packet->sp_Pkt.dp_Arg1 = ((ULONG) id) >> 2; PutMsg(con, packet); WaitPort(&iorp); /* Pointer to console window, all we need..*/ return( (struct Window*)(id->id_VolumeNode)); } } } /* error */ return((struct Window *)-1); } } /* function to display filenames */ VOID Disp(de,max) struct DirectoryEntry *de; LONG max; { TEXT Name[108]; REGISTER TEXT *from; REGISTER WORD i,j, /* number of filenames to be displayed in a row, according to the CLI window and its (fixedwidth!) font's sizes */ nitems = (((CliWin->Width-24)/CliWin->RPort->Font->tf_XSize)/(max+1)); REGISTER BPTR fh = Output(); REGISTER BOOL Flag; /* if the window is just too small */ if (nitems < 1) nitems = 1; while (de) { /* check for ^C */ if (SetSignal(0,0) & SIGBREAKF_CTRL_C) { Puts("***Break"); Cleanup(RETURN_WARN,NULL,FileList,NULL); } /* display a row of filenames */ for(i=1; (i <= nitems) && de ; i++){ from = de->de_Name; /* pad Name string with blanks to columnize names */ Flag = TRUE; for (j = 0; j < max ;j++) { if (*(from + j) && Flag) *(Name + j) = *(from + j); else { Flag = FALSE; *(Name + j) = ' '; } } Name[max] = '\0'; /* display filenames, Write()s are faster than a single Printf() */ if (de->de_Flags && !argv[NOCOL]) { Write(fh,"\033[33m",5); Write(fh,Name,max); Write(fh," \033[31m",6); } else { Write(fh,Name,max); Write(fh," ",1); } de = de->de_Next; } /* carriage return */ Write(fh,"\n",1); } } /* get filenames with Anchors, put them in a ordered DAList, display directory name, date, size and # of files */ VOID ShowDir() { TEXT EnvBuf[2]; /* buffer to hold the value of 'dateformat' environment variable */ REGISTER struct DirectoryEntry *De; REGISTER struct AnchorPath *Anchor=NULL; REGISTER LONG Result,m,max=0; REGISTER ULONG Dirs=0,Files=0,Size=0,NumBlocks=0; struct DateTime *Dat; /* Initialize Stamptostr() stuff */ Dat = &D; Dat->dat_StrDay = Day; Dat->dat_StrDate = Date; Dat->dat_StrTime = Time; /* Allocate space for anchorpath */ if ( Anchor = (struct AnchorPath *)ArpAlloc( (ULONG)sizeof( *Anchor )) ) { Anchor->ap_Length = 0; /* No path required */ Anchor->ap_BreakBits = SIGBREAKF_CTRL_C; /* stop if ^C */ } else { Puts("Error:No memory"); Cleanup(RETURN_FAIL,ERROR_NO_FREE_STORE,NULL,NULL); } /* examine files specified by pattern */ Result = FindFirst(argv[PAT],Anchor); while ( Result == 0 ) { /* the __builtin_ is the way Lattice inserts inline string functions; with other compilers use a corresponding construct (if any) */ if((m = __builtin_strlen(Anchor->ap_Info.fib_FileName)) > max) max = m; /* add filename to ordered DAList */ if ( !(De=AddDANode(Anchor->ap_Info.fib_FileName, &FileList, 0L, 0L))) { Puts("Error: no memory"); Cleanup(RETURN_FAIL,ERROR_NO_FREE_STORE,FileList,Anchor); } /* update files-size counts & mark entry as dir or file */ if (Anchor->ap_Info.fib_DirEntryType >= 0) { Dirs++; De->de_Flags = (BYTE) 1; } else { De->de_Flags = (BYTE) 0; Files++; } Size += Anchor->ap_Info.fib_Size; NumBlocks +=Anchor->ap_Info.fib_NumBlocks+1; Result = FindNext((struct AnchorPath*) Anchor ); } /* Free the Anchor chain */ FreeAnchorChain( Anchor ); /* error handling */ if (Result == ERROR_OBJECT_NOT_FOUND) { Printf("Error:Can't find %s\n",argv[PAT]); Cleanup(RETURN_ERROR,Result,FileList,NULL); } else if (Result == ERROR_BREAK) { Puts("***Break"); Cleanup(RETURN_WARN,NULL,FileList,NULL); } else if (Result != ERROR_NO_MORE_ENTRIES) { Puts("Error"); Cleanup(RETURN_ERROR,Result,FileList,NULL); } argv[PAT][strlen(argv[PAT])-strlen(BaseName(argv[PAT]))] = '\0'; /* empty pattern = current directory */ if (*argv[PAT]) Lck = ArpLock(argv[PAT],ACCESS_READ); else Lck = Pr->pr_CurrentDir; PathName(Lck,Buf,255); /* check for dateformat environment variable and consequentially act over DateTime structure */ if(Getenv("dateformat",EnvBuf,2)) switch (EnvBuf[0]) { case '1': Dat->dat_Format = FORMAT_INT; break; case '2': Dat->dat_Format = FORMAT_USA; break; case '3': Dat->dat_Format = FORMAT_CDN; break; }; /* display directory path with current date/time */ DateStamp((long *)Dat); StamptoStr(Dat); Printf("\"%s\" on %s %s %s\n",Buf,Day,Date,Time); Disp(FileList,max); /* display disk occupation and number of files */ if (Dirs && !(Files)) Printf("%ld blocks in %ld dirs.\n",NumBlocks,Dirs); else if (Files || Dirs) { Printf("%ld bytes, %ld blocks in %ld files",Size,NumBlocks,Files); if (Dirs) Printf(" and %ld dirs.\n",Dirs); else Printf(".\n"); } else Puts("Directory or Volume is empty"); FreeDAList(FileList); } /* _main used instead of main to slim code */ VOID _main(Line) STRPTR Line; { Pr = (struct Process *) FindTask(NULL); if(!(ArpBase = (struct ArpBase*)OpenLibrary(ArpName,ArpVersion))) exit(20); IntuitionBase = (struct IntuitionBase *)ArpBase->IntuiBase; if((CliWin = GetWin()) == (struct Window *)-1) Cleanup(RETURN_FAIL,ERROR_NO_FREE_STORE,NULL,NULL); /* parse command line */ for (argc=0; argc < NARGS; ++argc) argv[argc] = (STRPTR) NULL; while(*Line > ' ') ++Line; argc = GADS(++Line, strlen(Line), "\nUsage: L Pattern [CD] [NOCOL]\n", argv, "PAT,CD/S,NOCOL/S"); /* analyze user given pattern and make it suitable for FindFirst() and FindNext() */ /* parent dir */ if (!Strcmp(argv[PAT],"/")) { strcat(Bf,"/*");/* Why in the world do I have to */ argv[PAT]=Bf; /* do this mess to keep code */ } /* LIB:cres.o compatible ?????? */ /* root dir */ else if (!Strcmp(argv[PAT],":")) { strcat(Bf,":*"); argv[PAT]=Bf; } /* current dir */ else if (*argv[PAT] == '\0') { strcat(Bf,"*"); argv[PAT]=Bf; } /* some dir */ else { if (Lck=Lock(argv[PAT],ACCESS_READ)) /* something on disk ? */ { if(!(Fib=ArpAllocMem(sizeof(struct FileInfoBlock), MEMF_CLEAR))) Cleanup(RETURN_FAIL, ERROR_NO_FREE_STORE,NULL,NULL); (VOID)Examine(Lck,Fib); /* really a directory ? */ if (Fib->fib_DirEntryType >= 0) { strcpy(Bf,argv[PAT]); if (argv[PAT][strlen(argv[PAT])-1] == ':') strcat(Bf,"*"); else strcat(Bf,"/*"); argv[PAT]=Bf; } UnLock(Lck); } } ShowDir(); /* if required change the current dir with listed directory in a PROMPT "%S" compatible way */ if (argv[CD]) { /* get directory name */ argv[PAT][strlen(argv[PAT])-strlen(BaseName(argv[PAT]))] = '\0'; if (argv[PAT][strlen(argv[PAT])-1] == '/') argv[PAT][strlen(argv[PAT])-1] = '\0'; /* null pattern = current dir */ if (*argv[PAT]) { /* change the current dir lock */ Lck = Lock(argv[PAT],ACCESS_READ); UnLock(Pr->pr_CurrentDir); Pr->pr_CurrentDir = Lck; } else Lck = Pr->pr_CurrentDir; /* or keep it ..*/ PathName(Lck,Buf,255); CtoBStr(Buf,(BSTR)((((struct CommandLineInterface *) ((Pr->pr_CLI) << 2))->cli_SetName)),255); } Cleanup(RETURN_OK,NULL,NULL,NULL); }