/* * Info Command - C Language Equivalent. * * This command looks and feels like the original AmigaDOS Info command * except that it is written in C and thus available for "forking" with the * lattice 3.10 compiler. Also since it is written in C it is a somewhat * larger than it's BCPL counterpart although a good assembly hack could * probably fix that. * * (c) Copyright 1986 Charles McManis, All rights reserved. * This code may be copied for private use only. It may not be * included as part of any commercial package in whole or in * part without the express written permission of the Author. * * Permission is granted to distribute this package as part of the AmigaDOS * Replacement Project (ARP) or as part of the Fish Library. * * Compiling and Linking Information - This program was coded to minimize * the resulting executable size. To that end 99% of all references to * Lattice's library were removed, what remains are references to _CXD33 * and _CXM33 (some math routines) so you still need lc.lib but it is a * lot smaller than it normally would be. And Carolyn Scheppner's startup * code 'TWstartup.asm' was used rather than Lattice's c.o (I assembled * TWStartup.asm into ac.o.) * * The compile command I used to compile the source was : * LC -r -v info * * and the Blink command file (info.lnk) was set up as follows : * FROM ac.o+info.o * TO info * LIB LIB:amiga.lib+LIB:lc.lib * SMALLCODE * SMALLDATA * NODEBUG * MAP info.map * * The blink command to link this file is * Blink with info.lnk * * After you are done you should end up with an executable that is about * 4336 bytes long. Which compares favorably to the 1708 bytes of the * assem/BCPL version. The advantage to having a C version are two fold. * First, you can use the Lattice fork() call or the AmigaDOS Execute() * call to run this version from your program, and second you get to * see the source to the info command. Something Commodore wouldn't let * you do without paying big bucks. So here it is 'info' the C version. */ #include #include #include #include #include /* Note there is a bug in the Commodore supplied 'info' command. The * way it calculates the size of the disk is with the following formula * * size = ((NumberofBlocks + 2) * 512) / 1024 * * The actual size is : * * size = (NumberofBlocks * NumBytesPerBlock)/ 1024; * * define INFO_COMPATIBLE to get it their way, leave it undefined to get the * correct way. */ #define INFO_COMPATIBLE extern struct DosLibrary *DOSBase; #ifdef DEBUG struct RootNode *rn; struct DeviceList *dl, *t, *t2; struct DeviceNode *dn; struct DosInfo *di; #endif char *TWspec = ""; /* * Function cvtnum(num,str) * This function converts an integer to a string. It returns the length of * the string created. Change BASE for different bases, make it a variable for * dynamic base calculations. */ #define BASE 10 int cvtnum(str,num) char *str; long num; { short int i,j,ndx; long temp; char digit; ndx = 0; if (num < 0) { *(str+ndx++) = '-'; num = - (num); } if (num == 0) { *(str) = '0'; *(str+1) = '\0'; return(1); } i = 0; temp = 1; while (temp <= num) { temp *= BASE; i++; } temp /= BASE; for (j=0; j= size) return; for (i=size; i >= 0; i--) *(str+i) = (j < 0) ? ' ' : *(str+j--); } #define MyExit(cc) Exit(cc) /* These are some macros that help in dealing with BCPL pointers and strings * the first is macro converts a BPTR to a C pointer of type struct DeviceList * * The second two provide the length of a BSTR * and a pointer to it's text. */ #define DLPTR(x) ((struct DeviceList *)BADDR(x)) #define LENGTH(x) (*(UBYTE *)BADDR(x)) #define STRING(x) (((char *)BADDR(x))+1) /* * Function - FindDevice(ListPtr,DeviceType) * * This function will find a device of the specified type in the DeviceInfo * list and return a pointer to it. If the device List pointer you pass it * points to a struct of type DeviceType it will simply return that device * pointer. If you pass it NULL it will return NULL, and if it fails to * find a matching entry it returns NULL. * * Note to find the next device in the list you must update the pointer you * pass to the next device in the list. See the code below for some examples. */ struct DeviceList * FindDevice(dlp,dlt) struct DeviceList *dlp; /* Pointer to a device list structure */ long dlt; /* A device type as defined in dos.h */ { struct DeviceList *t; /* A temporary pointer */ for (t = dlp; ((t != NULL) && (t->dl_Type != dlt)); t = DLPTR(t->dl_Next)); return(t); } /* This macro writes out data to the screen bypassing C's printf statement */ #define PutS(str) Write(Output(),str,strlen(str)) /* * Main code, This is where the code actually implements the Info command. * it is pretty simple really, first we build a list of all the disk devices * and do an 'Info' on each one, then list out all of the volumes. */ void main() /* NOARGS */ { /* The pointers here make it easier later */ #ifndef DEBUG struct RootNode *rn; struct DeviceList *dl, *t, *t2; struct DeviceNode *dn; struct DosInfo *di; #endif struct InfoData info; struct Process *myp; APTR oldwinptr; BPTR l; char buf[80]; int i,a,u,size; PutS("Info command substitute v1.0\n"); /* Then we track down the head of the Device list from the Root Node */ rn = (struct RootNode *)DOSBase->dl_Root; di = (struct DosInfo *)BADDR(rn->rn_Info); /* dl becomes the anchor point that we always start from */ dl = (struct DeviceList *)BADDR(di->di_DevInfo); /* * Ok, now we list out all of the disk devices ... * * Pass 1: Print out all of the known volumes, if they have a handler * task present then they are mounted in a physical device */ PutS("Volumes Available:\n"); for (t = FindDevice(DLPTR(di->di_DevInfo),DLT_VOLUME); t != NULL; t = FindDevice(DLPTR(t->dl_Next),DLT_VOLUME)) { Write(Output(),STRING(t->dl_Name),LENGTH(t->dl_Name)); if (t->dl_Task != NULL) PutS(" [Mounted]"); PutS("\n"); } PutS("\n"); /* Pass 2 : Print out all of the disk devices, like the original we * pretty much assume device names are three characters long. * (They can be more though.) */ /* Disable requesters if no disk present */ myp = (struct Process *) FindTask(NULL); oldwinptr = myp->pr_WindowPtr; myp->pr_WindowPtr = (APTR) -1; PutS("Mounted Disks:\n"); PutS("Unit Size Used Free Full Errs Status Name\n"); i = 0; for (t = FindDevice(DLPTR(di->di_DevInfo),DLT_DEVICE); t != NULL; t = FindDevice(DLPTR(t->dl_Next),DLT_DEVICE)) { dn = (struct DeviceNode *) t; /* This is supposed to distinguish a disk device (a task pointer) */ if (dn->dn_Task) { Write(Output(),STRING(dn->dn_Name), LENGTH(dn->dn_Name)); PutS(": "); for (i=0; idn_Name); i++) buf[i] = *(STRING(dn->dn_Name)+i); buf[i++] = ':'; buf[i] = '\0'; l = Lock(buf,ACCESS_READ); if (l == NULL) PutS("No disk present\n"); else { Info(l,&info); /* Calculate the size in K bytes (add 2 to blocks for) 'reserved' * blocks which is a *bug* in the original info but what the heck. */ a = info.id_NumBlocks; #ifdef INFO_COMPATIBLE size = ((a+2) * 512) >> 10; #else size = (a * info.id_BytesPerBlock ) >> 10; #endif i = cvtnum(buf,size); /* The following case statement formats the number properly */ buf[3] = 'K'; /* defaults to K bytes */ switch (i) { case 1 : buf[2] = buf[0]; buf[1] = ' '; /* fill in with spaces */ buf[0] = ' '; /* fill in with spaces */ break; case 5 : buf[3] = 'M'; case 2 : buf[2] = buf[1]; buf[1] = buf[0]; buf[0] = ' '; break; case 6 : buf[3] = 'M'; case 3 : break; case 4 : case 7 : buf[3] = (i == 4) ? 'M' : 'G'; buf[2] = buf[1]; buf[1] = '.'; break; default: buf[0] = 'H'; /* Bigger than 10 Gigabytes */ buf[1] = 'U'; buf[2] = 'G'; buf[3] = 'E'; break; } /* end switch */ buf[4] = ' '; buf[5] = '\0'; PutS(buf); u = info.id_NumBlocksUsed; /* Now build the stats line without sprintf */ cvtnum(buf,u); Pad(buf,7); *(buf+7) = ' '; cvtnum(buf+8,a-u); Pad(buf+8,7); *(buf+15) = ' '; cvtnum(buf+16,((a-(a-u))*100)/a); Pad(buf+16,3); *(buf+19) = '%'; *(buf+20) = ' '; cvtnum(buf+21,info.id_NumSoftErrors); Pad(buf+21,3); PutS(buf); switch (info.id_DiskState) { case ID_WRITE_PROTECTED : PutS(" Read Only "); break; case ID_VALIDATING : PutS(" Validating "); break; case ID_VALIDATED : PutS(" Read/Write "); break; default: PutS(" Strange "); break; } /* state switch */ t2 = DLPTR(info.id_VolumeNode); if (t2 != NULL) Write(Output(),STRING(t2->dl_Name), LENGTH(t2->dl_Name)); PutS("\n"); UnLock(l); } /* else had a disk in it */ } /* If it was a disk device */ } /* For loop */ PutS("\n"); myp->pr_WindowPtr = oldwinptr; MyExit(RETURN_OK); /* Exit with a status of zero */ }