aboutsummaryrefslogtreecommitdiff
path: root/src/listalf.c
blob: 051f2fe890b5886472b38791b2e41f8c33f413dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <stdio.h>
#include <stdlib.h>
#include <f65.h>
#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 prints as 12pm, not 12am... but 0:01 (1 min past
	   midnight) prints as 12:01am */
	if(hour == 0 && min == 0) hour = 24;

	ampm = (hour > 11 ? 'p' : 'a');
	hour %= 12;

	/* midnight and noon print as 12, not 0 */
	if(hour == 0) hour = 12;

	sprintf(buf, "%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;

	sprintf(buf, "%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];
	char *filename;

	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);
		filename = (char *)(mem + alf_hdr_filename);

		total_osize += orig_size;
		total_csize += comp_size;

		printf("%-12s  ", 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');

		if(fseek(in_file, comp_size, SEEK_CUR) != 0) {
			fputs(self, stderr);
			perror(": fseek");
			exit(1);
		}
	}

	fputs("        ====  ========  ========  ====\nTotal   ", stdout);
	printf("%4d  ", c);
	printf("%8d  ", total_osize);
	printf("%8d  ", total_csize);
	printf("%3d%%  ", comp_percent(total_osize, total_csize));
	putchar('\n');
}