#include "unalf.h" #include "addrs.h" static const char *monthnames[] = { "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???", "???", "???", }; u16 getword(int offs) { return mem[offs] | (mem[offs + 1] << 8); } unsigned int getquad(int offs) { return getword(offs) | ((getword(offs + 2) << 16)); } /* see Arcinfo for details */ void format_msdos_time(char *buf) { u16 t, hour, min; char ampm; t = getword(alf_hdr_time0); /* don't bother with seconds (arc doesn't print them either) */ hour = t >> 11; min = (t >> 5) & 0x3f; /* midnight is 12:00a (unlike arc, which uses 0:00a). noon is 12:00p (same as arc). could just use a 24h clock like unzip does, but AM/PM are more intuitive to me. */ ampm = (hour > 11 ? 'p' : 'a'); hour %= 12; /* midnight and noon print as 12, not 0 */ if(hour == 0) hour = 12; snprintf(buf, 7, "%2d:%02d%c", hour, min, ampm); } /* see Arcinfo for details */ void format_msdos_date(char *buf) { u16 d, year, month, day; d = getword(alf_hdr_date0); /* year actually ranges 1980 to 2107... */ year = (d >> 9) + 1980; year %= 100; /* ...but only print last 2 digits */ /* valid months range 1 to 12. values 0, 13, 14, 15 are possible but invalid (print as ???) */ month = (d >> 5) & 0x0f; /* valid day range is 1 to 31. 0 is invalid, print as-is. */ day = d & 0x1f; snprintf(buf, 10, "%2d %3s %02d", day, monthnames[month], year); } /* small files may be "compressed" larger than the original, so this has to return a signed type. */ static int comp_percent(unsigned int orig, unsigned int comp) { if(orig == 0) return 0; /* no division by zero please */ return 100 - (int)((float)comp / (float)orig * 100.0); } /* output similar to "arc v", except we omit the compression type column since there's only one type. also, don't call the checksum a CRC, it isn't. */ void list_alf(void) { unsigned int c = 0, orig_size, comp_size, total_osize = 0, total_csize = 0; char buf[100]; extern char *out_filename; if(opts.verbose_list) { puts("Name Length Size now Comp Date Time CkSum"); puts("============ ======== ======== ==== ========= ====== ====="); } while(read_alf_header()) { c++; orig_size = getquad(alf_hdr_origsize0); comp_size = getquad(alf_hdr_compsize0); out_filename = (char *)(mem + alf_hdr_filename); if(!opts.verbose_list) fix_filename(); total_osize += orig_size; total_csize += comp_size; if(opts.verbose_list) { printf("%-12s ", out_filename); printf("%8d ", orig_size); printf("%8d ", comp_size); printf("%3d%% ", comp_percent(orig_size, comp_size)); format_msdos_date(buf); printf("%9s ", buf); format_msdos_time(buf); printf("%6s ", buf); printf(" %04x", getword(alf_hdr_cksum_l)); putchar('\n'); } else { if(file_wanted(out_filename)) printf("%s\n", out_filename); } if(fseek(in_file, comp_size, SEEK_CUR) != 0) { fprintf(stderr, "%s: fatal: seek failed on input!\n", self); exit(1); } } if(opts.verbose_list) { fputs(" ==== ======== ======== ====\nTotal ", stdout); printf("%4d ", c); printf("%8d ", total_osize); printf("%8d ", total_csize); printf("%3d%% ", comp_percent(total_osize, total_csize)); putchar('\n'); } }