Fixed out-by-one error in previous commit.
[AROS.git] / workbench / c / Info.c
blob475a719d96ab490c70d1e7a02a62e898d28af764
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Info Cli Command
6 Lang: English
7 */
9 /******************************************************************************
12 NAME
14 Info
16 SYNOPSIS
18 DISKS/S, VOLS=VOLUMES/S, ALL/S, BLOCKS/S, DEVICES/M
20 LOCATION
24 FUNCTION
26 Show information on file system devices and volumes. When given no
27 arguments, information on all devices and volumes found in the system
28 is displayed. If information is wanted only for some specific devices,
29 these names may be given as arguments.
31 INPUTS
33 DISKS -- show information on file system devices
34 VOLS -- show information on volumes
35 ALL -- show information on bad devices or volumes
36 BLOCKS -- show additional block size and usage information
37 DEVICES -- device names to show information about
39 RESULT
41 NOTES
43 EXAMPLE
45 Info
47 Unit Size Used Free Full Errs State Type Name
48 Harddisk: 964.1M 776.7M 187.4M 81% 0 read/write OFS AROS
49 RAM: 8.0M 7.1M 7.1M 12% 0 read/write OFS Ram Disk
51 BUGS
53 SEE ALSO
55 INTERNALS
57 The original source showed that AROS version of ReadArgs() handles
58 the /M switch with zero arguments differently from AmigaOS. While AROS
59 returns an array where the first pointer is NULL, AmigaOS just returns
60 NULL.
62 HISTORY
64 16.11.2000 SDuvan -- converted to AROS
65 23.12.2000 SDuvan -- changed semantics and updated
66 (now fully functional)
67 17.02.2005 Joe Fenton -- fixed 64bit calculation
69 Based on the original by:
70 © 1997-1998 by Stephan Rupprecht
71 All rights resevered
72 ******************************************************************************/
74 #define DEBUG 0
75 #include <aros/debug.h>
77 #include <dos/dos.h>
78 #include <dos/dosextens.h>
79 #include <dos/filehandler.h>
80 #include <exec/memory.h>
81 #include <libraries/locale.h>
83 #include <proto/dos.h>
84 #include <proto/exec.h>
85 #include <proto/utility.h>
86 #include <proto/locale.h>
87 #include <proto/alib.h>
89 #include <string.h>
91 #define ID_MAC_DISK2 (0x4d414300L) /* MAC\0 - xfs mac disk */
92 #define ID_MNX1_DISK (0x4d4e5801L) /* MNX\1 - xfs minix disk */
93 #define ID_MNX2_DISK (0x4d4e5802L) /* MNX\2 - xfs minix disk */
94 #define ID_QL5A_DISK (0x514c3541L) /* QL5A - xfs ql 720k / ed disk */
95 #define ID_QL5B_DISK (0x514c3542L) /* QL5B - xfs ql 1440k disk */
96 #define ID_ZXS0_DISK (0x5a585300L) /* Spectrum Disciple - xfs */
97 #define ID_ZXS1_DISK (0x5a585301L) /* Spectrum UniDos - xfs */
98 #define ID_ZXS2_DISK (0x5a585302L) /* Spectrum SamDos - xfs */
99 #define ID_ZXS4_DISK (0x5a585304L) /* Spectrum Opus 180k - xfs */
100 #define ID_ARME_DISK (0x41524d44L) /* Archimedes - xfs */
101 #define ID_ARMD_DISK (0x41524d43L) /* Archimedes - xfs */
102 #define ID_CPM_DISK (0x43505c4dL) /* CP/M - xfs */
103 #define ID_ZXS3_DISK (0x5a585303L) /* ZXS\3 - Plus3Dos xfs */
104 #define ID_1541_DISK (0x31353431L) /* 1541 - xfs */
105 #define ID_1581_DISK (0x31353831L) /* 1581 - xfs */
106 #define ID_MAC_DISK (0x4d534800L) /* MSH\0 - CrossDos MACDisk ?! */
107 #define ID_ACD0_DISK (0x41434400L) /* ACD\0 - AmiCDFS disk */
108 #define ID_CDFS_DISK (0x43444653L) /* CDFS - AmiCDFS disk */
109 #define ID_CACHECDFS_DISK (0x43443031L)
110 #define ID_ASIMCDFS_DISK (0x662dabacL)
111 #define ID_PFS_DISK (0x50465301L) /* PFS */
112 #define ID_PFS2_DISK (0x50465302L)
113 #define ID_PFS2_SCSI_DISK (0x50445300L)
114 #define ID_PFS2_muFS_DISK (0x6d755046L)
115 #define ID_FLOPPY_PFS_DISK (0x50465300L)
116 #define ID_P2A0_DISK (0x50324130L)
117 #define ID_AFS0_DISK (0x41465300L) /* AFS\0 */
118 #define ID_muFS_DISK (0x6d754653L) /* muFS - Multiuserfsys */
119 #define ID_FAT12_DISK (0x46415400L) /* FAT12 */
120 #define ID_FAT16_DISK (0x46415401L) /* FAT16 */
121 #define ID_FAT32_DISK (0x46415402L) /* FAT32 */
122 #define ID_EXT2_DISK (0x45585432L) /* Extended 2 - Linux */
125 /* Prototypes */
127 ULONG ComputeKBytes(ULONG a, ULONG b);
128 void FmtProcedure(struct Hook *hook, char a, struct Locale *locale);
129 ULONG ExtUDivMod32(ULONG a, ULONG b, ULONG *mod);
130 void doInfo();
133 const TEXT VersionStr[] = "$VER: Info 41.2 (26.05.2012)";
135 struct Catalog *cat;
136 struct Locale *loc = NULL;
137 ULONG MaxLen;
139 APTR Pool;
142 /* catalog string id:s */
143 enum
145 UNIT,
146 DEVTITLE,
147 DISKSTITLE,
148 DEVFMTSTR,
149 DATEFMTSTR,
150 READONLY,
151 READWRITE,
152 VALIDATING,
153 MOUNTEDSTR,
154 SMALLNUMFMT,
155 BIGNUMFMT,
156 VOLNAMEFMTSTR,
157 BLOCKSSTR
161 struct InfoDosNode
163 struct InfoDosNode *Next;
164 ULONG IsVolume;
165 ULONG DosType;
166 struct MsgPort *Task;
167 struct DateStamp VolumeDate;
168 TEXT Name[108];
171 struct InfoDosNode *head = NULL;
174 struct DiskTypeList
175 { ULONG id;
176 STRPTR str;
179 struct DiskTypeList dtl[] =
181 { ID_DOS_DISK, "OFS" },
182 { ID_FFS_DISK, "FFS" },
183 { ID_INTER_DOS_DISK, "OFS-INT" },
184 { ID_INTER_FFS_DISK, "FFS-INT" },
185 { ID_FASTDIR_DOS_DISK, "OFS-DC" },
186 { ID_FASTDIR_FFS_DISK, "FFS-DC" },
187 { ID_MSDOS_DISK, "MS-DOS" },
188 { ID_ACD0_DISK, "CDFS" },
189 { ID_CACHECDFS_DISK, "CDFS" },
190 { ID_ASIMCDFS_DISK, "CDFS" },
191 { ID_NOT_REALLY_DOS, "NO DOS" },
192 { ID_MAC_DISK2, "MAC" },
193 { ID_MNX1_DISK, "Minix" },
194 { ID_QL5A_DISK, "QL720k" },
195 { ID_QL5B_DISK, "QL1.4M" },
196 { ID_CPM_DISK, "CP/M" },
197 { ID_ZXS3_DISK, "+3Dos" },
198 { ID_ZXS0_DISK, "Disciple " },
199 { ID_ZXS1_DISK, "UniDos" },
200 { ID_ZXS2_DISK, "SamDos" },
201 { ID_ZXS4_DISK, "Opus" },
202 { ID_P2A0_DISK, "NETWORK" },
203 { ID_FAT12_DISK, "FAT12" },
204 { ID_FAT16_DISK, "FAT16" },
205 { ID_FAT32_DISK, "FAT32" },
206 { ID_SFS_BE_DISK, "SFS" },
207 { ID_SFS_LE_DISK, "sfs" },
208 { ID_PFS_DISK, "PFS" },
209 { ID_EXT2_DISK, "EXT2" },
210 { 0L, 0L }
214 /****************************************************************************/
216 int UtilityBase_version = 0;
217 int LocaleBase_version = 0;
219 int __nocommandline;
221 int main(void)
223 static struct TagItem loctags[] = { { OC_Version, 1 },
224 { TAG_END , 0 } };
225 cat = OpenCatalogA(NULL, "info_com.catalog", loctags);
226 loc = OpenLocale(NULL);
228 D(bug("Calling doInfo()\n"));
230 doInfo();
232 CloseLocale(loc);
233 CloseCatalog(cat);
235 return RETURN_OK; /* TODO: Fix this */
239 CONST_STRPTR GetStrFromCat(ULONG id, CONST_STRPTR def)
241 if(cat != NULL)
243 def = GetCatalogStr(cat, id, def);
246 return def;
250 void VLPrintf(ULONG id, CONST_STRPTR def, const IPTR* argarray)
252 def = GetStrFromCat(id, def);
253 VPrintf(def, (IPTR *)argarray);
257 BOOL myMatchPatternNoCase(STRPTR *array, STRPTR str)
259 if(*array != NULL)
261 while(*array != NULL)
263 UBYTE matchstr[128];
264 UBYTE name[32];
265 UBYTE *p = *array++;
266 UBYTE len = strlen(p);
268 if(p[len - 1] != ':')
270 CopyMem(p, name, len);
271 name[len] = ':';
272 name[len + 1] = 0;
273 p = name;
276 if(ParsePatternNoCase(p, matchstr, sizeof(matchstr)) != -1)
278 if(MatchPatternNoCase(matchstr, str))
280 return TRUE;
285 return FALSE;
288 return TRUE;
292 BOOL ScanDosList(STRPTR *filter)
294 struct InfoDosNode *idn = 0L;
295 struct DosList *ndl, *dl;
296 STRPTR *strray = NULL, dummy = NULL;
297 BOOL err = FALSE;
299 D(bug("Entered ScanDosList()\n"));
301 if (filter == NULL) filter = &dummy;
303 if(*filter != NULL)
305 strray = AllocPooled(Pool, sizeof(STRPTR)*MAX_MULTIARGS);
307 if(strray != NULL)
309 STRPTR *p = filter;
310 LONG i = 0;
312 while(*p)
313 strray[i++] = *p++;
315 while(i < MAX_MULTIARGS)
316 strray[i++] = NULL;
318 else
319 return FALSE;
322 /* lock list of devices & vols */
323 dl = ndl = LockDosList(LDF_ASSIGNS | LDF_VOLUMES | LDF_DEVICES | LDF_READ);
325 if(strray != NULL)
327 STRPTR *p = strray;
329 while(*p)
330 p++;
332 while((ndl = NextDosEntry(ndl, LDF_ASSIGNS | LDF_VOLUMES | LDF_READ)) != NULL)
334 TEXT name[108];
335 STRPTR taskName = NULL; /* Initialized to avoid a warning */
337 __sprintf(name, "%b:", ndl->dol_Name);
339 if ((ndl->dol_Type > DLT_VOLUME) || !(myMatchPatternNoCase(strray, name)))
341 continue;
344 switch (ndl->dol_Type)
346 case DLT_VOLUME:
347 taskName = ((struct Task *)ndl->dol_Task->mp_SigTask)->tc_Node.ln_Name;
349 D(bug("Found volume %s\n", taskName));
350 break;
352 case DLT_DIRECTORY:
354 struct AssignList *al = ndl->dol_misc.dol_assign.dol_List;
356 taskName = ((struct Task *)((struct FileLock *)BADDR(ndl->dol_Lock))->fl_Task->mp_SigTask)->tc_Node.ln_Name;
358 D(bug("Found directory %s\n", taskName));
360 while(al != NULL)
362 *p++ = ""; // TODO!!! ((struct Task *)((struct FileLock *)BADDR(al->al_Lock))->fl_Task->mp_SigTask)->tc_Node.ln_Name;
363 al = al->al_Next;
366 break;
369 *p++ = taskName;
372 else
373 strray = filter;
375 ndl = dl;
377 while((ndl = NextDosEntry(ndl, LDF_VOLUMES | LDF_DEVICES | LDF_READ)) != NULL)
379 UBYTE len = 0;
380 UBYTE type = ndl->dol_Type;
381 UBYTE name[108];
383 /* do not start non-started handlers or open CON: or RAW: windows.. */
384 if(type == DLT_DEVICE && !ndl->dol_Task)
385 continue;
387 __sprintf(name, "%b:", ndl->dol_Name);
388 D(bug("Found name %s\n", name));
390 if((type == DLT_DEVICE) && (myMatchPatternNoCase(strray, name) == FALSE))
392 int i;
394 D(bug("Failure! -- name = %s, strray = %p\n", name, (void *)strray));
396 for (i = 0; strray[i] != NULL; i++)
398 D(bug("Strray %i = %s\n", i, strray[i]));
401 continue;
404 idn = (struct InfoDosNode *)AllocPooled(Pool, sizeof(struct InfoDosNode));
406 if(idn == NULL)
408 err = TRUE;
409 break;
412 idn->Task = ndl->dol_Task;
413 idn->IsVolume = type == DLT_VOLUME;
415 while((idn->Name[len] = name[len]))
416 len++;
418 if(type == DLT_VOLUME)
420 idn->VolumeDate = ((struct DeviceList *)ndl)->dl_VolumeDate;
421 idn->Name[len - 1] = '\0'; /* remove ':' */
423 else
425 BPTR ptr = ndl->dol_misc.dol_handler.dol_Startup;
426 struct FileSysStartupMsg *fssm = NULL;
428 if (IsFileSystem(idn->Name))
430 // Only filesystems have a valid FileSysStartupMsg
431 fssm = (struct FileSysStartupMsg *)BADDR(ptr);
434 idn->DosType = ID_DOS_DISK;
436 // DLT_DEVICE
437 if (len > MaxLen)
438 MaxLen = len;
440 if (fssm)
442 struct DosEnvec *de;
443 de = (struct DosEnvec *)BADDR(fssm->fssm_Environ);
445 if (de && (de->de_TableSize & 0xffffff00) == 0)
446 if (de->de_DosType)
447 idn->DosType = de->de_DosType;
451 /* kinda insert sort */
453 struct InfoDosNode *work = head;
454 struct InfoDosNode *prev = NULL;
456 while((work != NULL) && (Stricmp(idn->Name, work->Name) > 0))
458 prev = work;
459 work = work->Next;
462 if(prev != NULL)
463 prev->Next = idn;
464 else
465 head = idn;
467 idn->Next = work;
471 /* unlock list of devices and volumes */
472 UnLockDosList(LDF_ASSIGNS | LDF_VOLUMES | LDF_DEVICES | LDF_READ);
474 // strray freed at DeletePool
476 return !err;
480 void PrintNum(ULONG num)
482 /* MBytes ? */
483 if(num > 1023)
485 ULONG x, xx;
486 char fmt = 'M';
488 /* GBytes ? */
489 if(num > 0xfffff)
491 num >>= 10;
492 fmt = 'G';
495 num = ExtUDivMod32(UMult32(num, 100) >> 10, 100, &x);
497 /* round */
498 x = ExtUDivMod32(x, 10, &xx);
500 if(xx > 4)
502 if(++x > 9)
504 x = 0;
505 num++;
509 IPTR args[] = {num, x, fmt};
510 VLPrintf(BIGNUMFMT, "%5ld.%ld%lc", args);
512 else
514 IPTR args[] = { num };
515 VLPrintf(SMALLNUMFMT, "%7ldK", args);
520 STRPTR GetFSysStr(ULONG DiskType)
522 struct DiskTypeList *dtlptr = dtl;
524 STRPTR ptr = NULL;
526 do {
527 if(dtlptr->id == DiskType)
529 ptr = dtlptr->str;
530 break;
532 } while(*((ULONG *)dtlptr++));
534 if(ptr == NULL)
536 static TEXT buffer[5];
538 ptr = (STRPTR)buffer;
539 *((ULONG *)ptr) = AROS_LONG2BE(DiskType);
541 if(ptr[3] < ' ')
542 ptr[3] += '0';
544 ptr[4] = '\0';
547 return ptr;
551 enum
553 ARG_DISKS,
554 ARG_VOLS,
555 ARG_ALL,
556 ARG_BLOCKS,
557 ARG_DEVS,
558 NOOFARGS
562 void doInfo()
564 struct RDArgs *rdargs;
565 struct Process *proc;
566 struct Window *win;
567 struct InfoDosNode *idn;
569 struct InfoData *id = AllocVec(sizeof(struct InfoData), MEMF_ANY);
571 IPTR args[] = { (IPTR)FALSE,
572 (IPTR)FALSE,
573 (IPTR)FALSE,
574 (IPTR)FALSE,
575 (IPTR)NULL };
577 CONST_STRPTR unit = GetStrFromCat(UNIT, "Unit");
579 if(id == NULL)
581 PrintFault(ERROR_NO_FREE_STORE, NULL);
582 return;
585 Pool = CreatePool(MEMF_ANY, 1024, 1024);
587 if(Pool == NULL)
589 PrintFault(ERROR_NO_FREE_STORE, NULL);
590 return; /* ??? */
593 D(bug("Calling ReadArgs()\n"));
595 /* read arguments */
596 rdargs = ReadArgs("DISKS/S,VOLS=VOLUMES/S,ALL/S,BLOCKS/S,DEVICES/M",
597 args, NULL);
599 if(rdargs != NULL)
601 BOOL disks = (BOOL)args[ARG_DISKS];
602 BOOL vols = (BOOL)args[ARG_VOLS];
603 BOOL showall = (BOOL)args[ARG_ALL];
604 BOOL blocks = (BOOL)args[ARG_BLOCKS];
605 STRPTR *devs = (STRPTR *)args[ARG_DEVS];
607 if (devs && (*devs == NULL)) devs = NULL;
609 /* If nothing is specified, show everything we got */
610 if(devs == NULL && !disks && !vols)
612 vols = TRUE;
613 disks = TRUE;
616 /* check pattern strings */
618 if(devs != NULL)
620 STRPTR *p = devs;
622 while(*p != NULL)
624 TEXT matchstr[128];
626 if(ParsePatternNoCase(*p, matchstr, sizeof(matchstr)) == -1)
628 PrintFault(IoErr(), *p);
629 goto end;
632 p++;
636 /* avoid requesters */
637 proc = (struct Process *)FindTask(NULL);
638 win = (struct Window *)proc->pr_WindowPtr;
639 proc->pr_WindowPtr = (struct Window *)~0;
641 MaxLen = strlen(unit);
643 D(bug("Calling ScanDosList()\n"));
645 /* scan doslist */
646 if(ScanDosList(devs))
648 CONST_STRPTR dstate[3] = { GetStrFromCat(READONLY, "read only"),
649 GetStrFromCat(VALIDATING, "validating"),
650 GetStrFromCat(READWRITE, "read/write") };
651 STRPTR datetimeFmt = NULL;
652 BOOL first = TRUE;
653 TEXT nfmtstr[16];
654 TEXT buf[64];
656 D(bug("Printing stuff\n"));
658 /* get datetimefmt string */
659 if(loc && (GetVar("info_datetime", buf, sizeof(buf), 0L) > 0L))
661 datetimeFmt = buf;
664 /* calc format string for 'Unit' */
665 __sprintf(nfmtstr, "%%-%lds", MaxLen);
667 /* show device infomation */
668 if(devs != NULL || disks || !vols)
670 for(idn = head; idn; idn = idn->Next)
672 BPTR lock;
673 STRPTR name = idn->Name;
675 D(bug("Got name = %s\n", name));
677 if(!idn->IsVolume && IsFileSystem(name))
679 BOOL gotinfo = FALSE;
680 /* if first device to print, print title */
681 if(first || blocks)
683 if(!first)
684 Printf("\n");
686 D(bug("Printing device\n"));
688 VLPrintf(~0, nfmtstr, (IPTR*) &unit);
689 VLPrintf(DEVTITLE, " Size Used Free Full Errs State Type Name\n", NULL);
691 first = FALSE;
694 VLPrintf(~0, nfmtstr, (IPTR*) &name);
696 D(bug("Locking \"%s\"\n", name));
697 lock = Lock(name, SHARED_LOCK);
699 D(bug("Lock = %p\n", (APTR)lock));
701 if(lock != BNULL)
703 D(bug("Got lock on %s\n", name));
705 if(Info(lock, id) == DOSTRUE)
707 D(bug("Calling NameFromLock()\n"));
709 if(NameFromLock(lock, name, 108L))
711 LONG len = strlen(name) - 1;
713 if(name[len] == ':')
715 name[len] = '\0';
719 gotinfo = TRUE;
721 UnLock(lock);
723 } else if (idn->Task) {
724 name = NULL;
725 D(bug("Calling ACTION_DISK_INFO\n"));
726 if (DoPkt(idn->Task, ACTION_DISK_INFO, (SIPTR)MKBADDR(id), (SIPTR)BNULL, (SIPTR)BNULL, (SIPTR)BNULL, (SIPTR)BNULL)) {
727 gotinfo = TRUE;
731 if (gotinfo) {
732 ULONG x, y;
734 D(bug("Got info on %s\n", name));
736 if (id->id_DiskType == ID_NO_DISK_PRESENT) {
737 VLPrintf(~0, " No disk present\n", NULL);
738 } else if (id->id_DiskType == ID_NOT_REALLY_DOS) {
739 VLPrintf(~0, " Not a DOS disk\n", NULL);
740 } else if (id->id_DiskType == ID_UNREADABLE_DISK) {
741 VLPrintf(~0, " Unreadable disk\n", NULL);
742 } else {
743 x = ComputeKBytes(id->id_NumBlocks, id->id_BytesPerBlock);
744 y = ComputeKBytes(id->id_NumBlocksUsed, id->id_BytesPerBlock);
746 PrintNum(x);
747 PrintNum(y);
748 PrintNum(x - y);
750 if(x > 0xfffff)
752 x >>= 10;
753 y >>= 10;
756 if(x)
758 x = ExtUDivMod32(UDivMod32(UMult32(y, 1000), x), 10, &y);
760 if(y > 4)
761 x++;
763 else
764 x = 0;
766 // y = ((struct DeviceList *)BADDR(id->id_VolumeNode))->dl_DiskType;
768 // if(!y)
769 y = id->id_DiskType;
771 if((idn->DosType & ID_DOS_DISK) != ID_DOS_DISK)
772 y = idn->DosType;
775 IPTR args[] = {
777 id->id_NumSoftErrors,
778 ((id->id_DiskState >= ID_WRITE_PROTECTED) && (id->id_DiskState <= ID_VALIDATED)) ?
779 (IPTR) dstate[id->id_DiskState - ID_WRITE_PROTECTED] : (IPTR) "",
780 (IPTR) GetFSysStr(y),
781 (IPTR) name};
782 VLPrintf(DEVFMTSTR, "%4ld%% %4ld %-11s%-8s%s\n", args);
785 if(blocks)
787 IPTR args[] = {
788 id->id_NumBlocks,
789 id->id_NumBlocksUsed,
790 id->id_NumBlocks-id->id_NumBlocksUsed,
791 id->id_BytesPerBlock};
792 VLPrintf(BLOCKSSTR,
793 "\nTotal blocks: %-10ld Blocks used: %ld\n"
794 " Blocks free: %-10ld Blocksize: %ld\n",
795 args);
799 else
801 D(bug("Info failure\n"));
802 VLPrintf(~0, "\n", NULL);
806 LONG err = IoErr();
808 /* just ignore PIPEFS */
809 if (err == ERROR_ACTION_NOT_KNOWN)
810 if (strcmp(name, "PIPEFS:") == 0)
811 err = 0;
813 if (err && showall)
815 VLPrintf(~0, nfmtstr, (IPTR*) &name);
816 PrintFault(err, NULL);
823 /* show volumes */
824 if(vols || (!devs && !disks))
826 if(!first)
827 PutStr("\n");
829 VLPrintf(DISKSTITLE, "Volumes\n", NULL);
831 for(MaxLen = 15, idn = head; idn; idn = idn->Next)
833 if(idn->IsVolume)
835 LONG len = strlen(idn->Name);
837 if(len > MaxLen)
838 MaxLen = len;
842 __sprintf(nfmtstr, "%%-%lds%%-10s", MaxLen+1);
844 for(idn = head; idn; idn = idn->Next)
846 if(idn->IsVolume)
848 IPTR args[] = {
849 (IPTR) idn->Name,
850 (IPTR) GetStrFromCat(MOUNTEDSTR, "[Mounted]")};
851 // idn->Task ? GetStrFromCat(MOUNTEDSTR, "[Mounted]") : ""); TODO
852 VLPrintf(VOLNAMEFMTSTR, nfmtstr, args);
854 if(datetimeFmt)
856 UBYTE datestr[128];
857 static struct Hook hook;
859 memset(&hook, 0, sizeof(struct Hook));
861 hook.h_SubEntry = (HOOKFUNC)FmtProcedure;
862 hook.h_Data = datestr;
864 FormatDate(loc, datetimeFmt, &idn->VolumeDate, &hook);
866 PutStr(datestr);
868 else
870 TEXT StrDay[LEN_DATSTRING];
871 TEXT StrDate[LEN_DATSTRING];
872 TEXT StrTime[LEN_DATSTRING];
874 struct DateTime dt;
876 dt.dat_Flags = DTF_SUBST;
877 dt.dat_Format = FORMAT_DOS;
878 dt.dat_StrDay = StrDay;
879 dt.dat_StrDate = StrDate;
880 dt.dat_StrTime = StrTime;
881 dt.dat_Stamp = idn->VolumeDate;
883 if(DateToStr(&dt))
885 if(Strnicmp(StrDate, StrDay, strlen(StrDay)) == 0)
887 dt.dat_Flags = 0L;
888 DateToStr(&dt);
891 IPTR args[] = {(IPTR) StrDay, (IPTR) StrDate, (IPTR) StrTime};
892 VLPrintf(DATEFMTSTR, "created %.3s, %-10s %s", args);
896 PutStr("\n");
901 else
903 PrintFault( ERROR_NO_FREE_STORE, NULL);
906 /* reset window pointer of our process */
907 proc->pr_WindowPtr = win;
909 /* free args */
910 FreeArgs(rdargs);
914 end: /* free allocated memory */
915 FreeVec(id);
916 DeletePool(Pool);
920 ULONG ComputeKBytes(ULONG a, ULONG b)
922 // UQUAD result = UMult64(a, b);
924 UQUAD result = (UQUAD)a * b;
926 return (ULONG)(result >> 10);
930 void FmtProcedure(struct Hook *hook, char a, struct Locale *locale)
932 *((STRPTR)hook->h_Data) = a;
933 hook->h_Data = (STRPTR) hook->h_Data + 1;
937 ULONG ExtUDivMod32(ULONG a, ULONG b, ULONG *mod)
939 *mod = a % b;
941 return a/b;