1368c31abSDavid du Colombier #include "stdinc.h"
2368c31abSDavid du Colombier #include "dat.h"
3368c31abSDavid du Colombier #include "fns.h"
4368c31abSDavid du Colombier
5368c31abSDavid du Colombier typedef struct AHash AHash;
6368c31abSDavid du Colombier
7368c31abSDavid du Colombier /*
8368c31abSDavid du Colombier * hash table for finding arena's based on their names.
9368c31abSDavid du Colombier */
10368c31abSDavid du Colombier struct AHash
11368c31abSDavid du Colombier {
12368c31abSDavid du Colombier AHash *next;
13368c31abSDavid du Colombier Arena *arena;
14368c31abSDavid du Colombier };
15368c31abSDavid du Colombier
16368c31abSDavid du Colombier enum
17368c31abSDavid du Colombier {
18*588d0145SDavid du Colombier AHashSize = 512,
19*588d0145SDavid du Colombier Emergency = 0, /* flag: performing emergency surgery */
20368c31abSDavid du Colombier };
21368c31abSDavid du Colombier
22368c31abSDavid du Colombier static AHash *ahash[AHashSize];
23368c31abSDavid du Colombier
24368c31abSDavid du Colombier static u32int
hashstr(char * s)25368c31abSDavid du Colombier hashstr(char *s)
26368c31abSDavid du Colombier {
27368c31abSDavid du Colombier u32int h;
28368c31abSDavid du Colombier int c;
29368c31abSDavid du Colombier
30368c31abSDavid du Colombier h = 0;
31368c31abSDavid du Colombier for(; c = *s; s++){
32368c31abSDavid du Colombier c ^= c << 6;
33368c31abSDavid du Colombier h += (c << 11) ^ (c >> 1);
34368c31abSDavid du Colombier c = *s;
35368c31abSDavid du Colombier h ^= (c << 14) + (c << 7) + (c << 4) + c;
36368c31abSDavid du Colombier }
37368c31abSDavid du Colombier return h;
38368c31abSDavid du Colombier }
39368c31abSDavid du Colombier
40368c31abSDavid du Colombier int
addarena(Arena * arena)41368c31abSDavid du Colombier addarena(Arena *arena)
42368c31abSDavid du Colombier {
43368c31abSDavid du Colombier AHash *a;
44368c31abSDavid du Colombier u32int h;
45368c31abSDavid du Colombier
46368c31abSDavid du Colombier h = hashstr(arena->name) & (AHashSize - 1);
47368c31abSDavid du Colombier a = MK(AHash);
48368c31abSDavid du Colombier if(a == nil)
49368c31abSDavid du Colombier return -1;
50368c31abSDavid du Colombier a->arena = arena;
51368c31abSDavid du Colombier a->next = ahash[h];
52368c31abSDavid du Colombier ahash[h] = a;
53368c31abSDavid du Colombier return 0;
54368c31abSDavid du Colombier }
55368c31abSDavid du Colombier
56368c31abSDavid du Colombier Arena*
findarena(char * name)57368c31abSDavid du Colombier findarena(char *name)
58368c31abSDavid du Colombier {
59368c31abSDavid du Colombier AHash *a;
60368c31abSDavid du Colombier u32int h;
61368c31abSDavid du Colombier
62368c31abSDavid du Colombier h = hashstr(name) & (AHashSize - 1);
63368c31abSDavid du Colombier for(a = ahash[h]; a != nil; a = a->next)
64368c31abSDavid du Colombier if(strcmp(a->arena->name, name) == 0)
65368c31abSDavid du Colombier return a->arena;
66368c31abSDavid du Colombier return nil;
67368c31abSDavid du Colombier }
68368c31abSDavid du Colombier
69368c31abSDavid du Colombier int
delarena(Arena * arena)70368c31abSDavid du Colombier delarena(Arena *arena)
71368c31abSDavid du Colombier {
72368c31abSDavid du Colombier AHash *a, *last;
73368c31abSDavid du Colombier u32int h;
74368c31abSDavid du Colombier
75368c31abSDavid du Colombier h = hashstr(arena->name) & (AHashSize - 1);
76368c31abSDavid du Colombier last = nil;
77368c31abSDavid du Colombier for(a = ahash[h]; a != nil; a = a->next){
78368c31abSDavid du Colombier if(a->arena == arena){
79368c31abSDavid du Colombier if(last != nil)
80368c31abSDavid du Colombier last->next = a->next;
81368c31abSDavid du Colombier else
82368c31abSDavid du Colombier ahash[h] = a->next;
83368c31abSDavid du Colombier free(a);
84368c31abSDavid du Colombier return 0;
85368c31abSDavid du Colombier }
86368c31abSDavid du Colombier last = a;
87368c31abSDavid du Colombier }
88368c31abSDavid du Colombier return -1;
89368c31abSDavid du Colombier }
90368c31abSDavid du Colombier
91368c31abSDavid du Colombier ArenaPart*
initarenapart(Part * part)92368c31abSDavid du Colombier initarenapart(Part *part)
93368c31abSDavid du Colombier {
94368c31abSDavid du Colombier AMapN amn;
95368c31abSDavid du Colombier ArenaPart *ap;
96368c31abSDavid du Colombier ZBlock *b;
97368c31abSDavid du Colombier u32int i;
98368c31abSDavid du Colombier int ok;
99368c31abSDavid du Colombier
100368c31abSDavid du Colombier b = alloczblock(HeadSize, 0, 0);
101368c31abSDavid du Colombier if(b == nil || readpart(part, PartBlank, b->data, HeadSize) < 0){
102368c31abSDavid du Colombier seterr(EAdmin, "can't read arena partition header: %r");
103368c31abSDavid du Colombier return nil;
104368c31abSDavid du Colombier }
105368c31abSDavid du Colombier
106368c31abSDavid du Colombier ap = MKZ(ArenaPart);
107368c31abSDavid du Colombier if(ap == nil){
108368c31abSDavid du Colombier freezblock(b);
109368c31abSDavid du Colombier return nil;
110368c31abSDavid du Colombier }
111368c31abSDavid du Colombier ap->part = part;
112368c31abSDavid du Colombier ok = unpackarenapart(ap, b->data);
113368c31abSDavid du Colombier freezblock(b);
114368c31abSDavid du Colombier if(ok < 0){
115368c31abSDavid du Colombier freearenapart(ap, 0);
116368c31abSDavid du Colombier return nil;
117368c31abSDavid du Colombier }
118368c31abSDavid du Colombier
119368c31abSDavid du Colombier ap->tabbase = (PartBlank + HeadSize + ap->blocksize - 1) & ~(ap->blocksize - 1);
120368c31abSDavid du Colombier if(ap->version != ArenaPartVersion){
121368c31abSDavid du Colombier seterr(ECorrupt, "unknown arena partition version %d", ap->version);
122368c31abSDavid du Colombier freearenapart(ap, 0);
123368c31abSDavid du Colombier return nil;
124368c31abSDavid du Colombier }
125368c31abSDavid du Colombier if(ap->blocksize & (ap->blocksize - 1)){
126368c31abSDavid du Colombier seterr(ECorrupt, "illegal non-power-of-2 block size %d\n", ap->blocksize);
127368c31abSDavid du Colombier freearenapart(ap, 0);
128368c31abSDavid du Colombier return nil;
129368c31abSDavid du Colombier }
130368c31abSDavid du Colombier if(ap->tabbase >= ap->arenabase){
131368c31abSDavid du Colombier seterr(ECorrupt, "arena partition table overlaps with arena storage");
132368c31abSDavid du Colombier freearenapart(ap, 0);
133368c31abSDavid du Colombier return nil;
134368c31abSDavid du Colombier }
135368c31abSDavid du Colombier ap->tabsize = ap->arenabase - ap->tabbase;
136368c31abSDavid du Colombier partblocksize(part, ap->blocksize);
137368c31abSDavid du Colombier ap->size = ap->part->size & ~(u64int)(ap->blocksize - 1);
138368c31abSDavid du Colombier
139368c31abSDavid du Colombier if(readarenamap(&amn, part, ap->tabbase, ap->tabsize) < 0){
140368c31abSDavid du Colombier freearenapart(ap, 0);
141368c31abSDavid du Colombier return nil;
142368c31abSDavid du Colombier }
143368c31abSDavid du Colombier ap->narenas = amn.n;
144368c31abSDavid du Colombier ap->map = amn.map;
145368c31abSDavid du Colombier if(okamap(ap->map, ap->narenas, ap->arenabase, ap->size, "arena table") < 0){
146*588d0145SDavid du Colombier if(!Emergency){
147368c31abSDavid du Colombier freearenapart(ap, 0);
148368c31abSDavid du Colombier return nil;
149368c31abSDavid du Colombier }
150*588d0145SDavid du Colombier /* else keep on, for emergency use */
151*588d0145SDavid du Colombier }
152368c31abSDavid du Colombier
153368c31abSDavid du Colombier ap->arenas = MKNZ(Arena*, ap->narenas);
154368c31abSDavid du Colombier for(i = 0; i < ap->narenas; i++){
155b8a11165SDavid du Colombier debugarena = i;
156368c31abSDavid du Colombier ap->arenas[i] = initarena(part, ap->map[i].start, ap->map[i].stop - ap->map[i].start, ap->blocksize);
157368c31abSDavid du Colombier if(ap->arenas[i] == nil){
158368c31abSDavid du Colombier seterr(ECorrupt, "%s: %r", ap->map[i].name);
159*588d0145SDavid du Colombier if(!Emergency){
160368c31abSDavid du Colombier freearenapart(ap, 1);
161368c31abSDavid du Colombier return nil;
162*588d0145SDavid du Colombier }else{
163*588d0145SDavid du Colombier /* keep on, for emergency use */
164*588d0145SDavid du Colombier ap->narenas = i;
165*588d0145SDavid du Colombier break;
166*588d0145SDavid du Colombier }
167368c31abSDavid du Colombier }
168368c31abSDavid du Colombier if(namecmp(ap->map[i].name, ap->arenas[i]->name) != 0){
169368c31abSDavid du Colombier seterr(ECorrupt, "arena name mismatches with expected name: %s vs. %s",
170368c31abSDavid du Colombier ap->map[i].name, ap->arenas[i]->name);
171368c31abSDavid du Colombier freearenapart(ap, 1);
172368c31abSDavid du Colombier return nil;
173368c31abSDavid du Colombier }
174368c31abSDavid du Colombier if(findarena(ap->arenas[i]->name)){
175368c31abSDavid du Colombier seterr(ECorrupt, "duplicate arena name %s in %s",
176368c31abSDavid du Colombier ap->map[i].name, ap->part->name);
177368c31abSDavid du Colombier freearenapart(ap, 1);
178368c31abSDavid du Colombier return nil;
179368c31abSDavid du Colombier }
180368c31abSDavid du Colombier }
181368c31abSDavid du Colombier
182b8a11165SDavid du Colombier for(i = 0; i < ap->narenas; i++) {
183b8a11165SDavid du Colombier debugarena = i;
184368c31abSDavid du Colombier addarena(ap->arenas[i]);
185b8a11165SDavid du Colombier }
186b8a11165SDavid du Colombier debugarena = -1;
187368c31abSDavid du Colombier
188368c31abSDavid du Colombier return ap;
189368c31abSDavid du Colombier }
190368c31abSDavid du Colombier
191368c31abSDavid du Colombier ArenaPart*
newarenapart(Part * part,u32int blocksize,u32int tabsize)192368c31abSDavid du Colombier newarenapart(Part *part, u32int blocksize, u32int tabsize)
193368c31abSDavid du Colombier {
194368c31abSDavid du Colombier ArenaPart *ap;
195368c31abSDavid du Colombier
196368c31abSDavid du Colombier if(blocksize & (blocksize - 1)){
197368c31abSDavid du Colombier seterr(ECorrupt, "illegal non-power-of-2 block size %d\n", blocksize);
198368c31abSDavid du Colombier return nil;
199368c31abSDavid du Colombier }
200368c31abSDavid du Colombier ap = MKZ(ArenaPart);
201368c31abSDavid du Colombier if(ap == nil)
202368c31abSDavid du Colombier return nil;
203368c31abSDavid du Colombier
204368c31abSDavid du Colombier ap->version = ArenaPartVersion;
205368c31abSDavid du Colombier ap->part = part;
206368c31abSDavid du Colombier ap->blocksize = blocksize;
207368c31abSDavid du Colombier partblocksize(part, blocksize);
208368c31abSDavid du Colombier ap->size = part->size & ~(u64int)(blocksize - 1);
209368c31abSDavid du Colombier ap->tabbase = (PartBlank + HeadSize + blocksize - 1) & ~(blocksize - 1);
210368c31abSDavid du Colombier ap->arenabase = (ap->tabbase + tabsize + blocksize - 1) & ~(blocksize - 1);
211368c31abSDavid du Colombier ap->tabsize = ap->arenabase - ap->tabbase;
212368c31abSDavid du Colombier ap->narenas = 0;
213368c31abSDavid du Colombier
214368c31abSDavid du Colombier if(wbarenapart(ap) < 0){
215368c31abSDavid du Colombier freearenapart(ap, 0);
216368c31abSDavid du Colombier return nil;
217368c31abSDavid du Colombier }
218368c31abSDavid du Colombier
219368c31abSDavid du Colombier return ap;
220368c31abSDavid du Colombier }
221368c31abSDavid du Colombier
222368c31abSDavid du Colombier int
wbarenapart(ArenaPart * ap)223368c31abSDavid du Colombier wbarenapart(ArenaPart *ap)
224368c31abSDavid du Colombier {
225368c31abSDavid du Colombier ZBlock *b;
226368c31abSDavid du Colombier
227368c31abSDavid du Colombier if(okamap(ap->map, ap->narenas, ap->arenabase, ap->size, "arena table") < 0)
228368c31abSDavid du Colombier return -1;
229368c31abSDavid du Colombier b = alloczblock(HeadSize, 1, 0);
230368c31abSDavid du Colombier if(b == nil)
231368c31abSDavid du Colombier /* ZZZ set error message? */
232368c31abSDavid du Colombier return -1;
233368c31abSDavid du Colombier
234368c31abSDavid du Colombier if(packarenapart(ap, b->data) < 0){
235368c31abSDavid du Colombier seterr(ECorrupt, "can't make arena partition header: %r");
236368c31abSDavid du Colombier freezblock(b);
237368c31abSDavid du Colombier return -1;
238368c31abSDavid du Colombier }
239368c31abSDavid du Colombier if(writepart(ap->part, PartBlank, b->data, HeadSize) < 0 ||
240368c31abSDavid du Colombier flushpart(ap->part) < 0){
241368c31abSDavid du Colombier seterr(EAdmin, "can't write arena partition header: %r");
242368c31abSDavid du Colombier freezblock(b);
243368c31abSDavid du Colombier return -1;
244368c31abSDavid du Colombier }
245368c31abSDavid du Colombier freezblock(b);
246368c31abSDavid du Colombier
247368c31abSDavid du Colombier return wbarenamap(ap->map, ap->narenas, ap->part, ap->tabbase, ap->tabsize);
248368c31abSDavid du Colombier }
249368c31abSDavid du Colombier
250368c31abSDavid du Colombier void
freearenapart(ArenaPart * ap,int freearenas)251368c31abSDavid du Colombier freearenapart(ArenaPart *ap, int freearenas)
252368c31abSDavid du Colombier {
253368c31abSDavid du Colombier int i;
254368c31abSDavid du Colombier
255368c31abSDavid du Colombier if(ap == nil)
256368c31abSDavid du Colombier return;
257368c31abSDavid du Colombier if(freearenas){
258368c31abSDavid du Colombier for(i = 0; i < ap->narenas; i++){
259368c31abSDavid du Colombier if(ap->arenas[i] == nil)
260368c31abSDavid du Colombier continue;
261368c31abSDavid du Colombier delarena(ap->arenas[i]);
262368c31abSDavid du Colombier freearena(ap->arenas[i]);
263368c31abSDavid du Colombier }
264368c31abSDavid du Colombier }
265368c31abSDavid du Colombier free(ap->map);
266368c31abSDavid du Colombier free(ap->arenas);
267368c31abSDavid du Colombier free(ap);
268368c31abSDavid du Colombier }
269368c31abSDavid du Colombier
270368c31abSDavid du Colombier int
okamap(AMap * am,int n,u64int start,u64int stop,char * what)271368c31abSDavid du Colombier okamap(AMap *am, int n, u64int start, u64int stop, char *what)
272368c31abSDavid du Colombier {
273368c31abSDavid du Colombier u64int last;
274368c31abSDavid du Colombier u32int i;
275368c31abSDavid du Colombier
276368c31abSDavid du Colombier last = start;
277368c31abSDavid du Colombier for(i = 0; i < n; i++){
278368c31abSDavid du Colombier if(am[i].start < last){
279368c31abSDavid du Colombier if(i == 0)
280368c31abSDavid du Colombier seterr(ECorrupt, "invalid start address in %s", what);
281368c31abSDavid du Colombier else
282368c31abSDavid du Colombier seterr(ECorrupt, "overlapping ranges in %s", what);
283368c31abSDavid du Colombier return -1;
284368c31abSDavid du Colombier }
285368c31abSDavid du Colombier if(am[i].stop < am[i].start){
286368c31abSDavid du Colombier seterr(ECorrupt, "invalid range in %s", what);
287368c31abSDavid du Colombier return -1;
288368c31abSDavid du Colombier }
289368c31abSDavid du Colombier last = am[i].stop;
290368c31abSDavid du Colombier }
291368c31abSDavid du Colombier if(last > stop){
292368c31abSDavid du Colombier seterr(ECorrupt, "invalid ending address in %s", what);
293368c31abSDavid du Colombier return -1;
294368c31abSDavid du Colombier }
295368c31abSDavid du Colombier return 0;
296368c31abSDavid du Colombier }
297368c31abSDavid du Colombier
298368c31abSDavid du Colombier int
maparenas(AMap * am,Arena ** arenas,int n,char * what)299368c31abSDavid du Colombier maparenas(AMap *am, Arena **arenas, int n, char *what)
300368c31abSDavid du Colombier {
301368c31abSDavid du Colombier u32int i;
302368c31abSDavid du Colombier
303368c31abSDavid du Colombier for(i = 0; i < n; i++){
304368c31abSDavid du Colombier arenas[i] = findarena(am[i].name);
305368c31abSDavid du Colombier if(arenas[i] == nil){
306368c31abSDavid du Colombier seterr(EAdmin, "can't find arena '%s' for '%s'\n", am[i].name, what);
307368c31abSDavid du Colombier return -1;
308368c31abSDavid du Colombier }
309368c31abSDavid du Colombier }
310368c31abSDavid du Colombier return 0;
311368c31abSDavid du Colombier }
312368c31abSDavid du Colombier
313368c31abSDavid du Colombier int
readarenamap(AMapN * amn,Part * part,u64int base,u32int size)314368c31abSDavid du Colombier readarenamap(AMapN *amn, Part *part, u64int base, u32int size)
315368c31abSDavid du Colombier {
316368c31abSDavid du Colombier IFile f;
317368c31abSDavid du Colombier u32int ok;
318368c31abSDavid du Colombier
319368c31abSDavid du Colombier if(partifile(&f, part, base, size) < 0)
320368c31abSDavid du Colombier return -1;
321368c31abSDavid du Colombier ok = parseamap(&f, amn);
322368c31abSDavid du Colombier freeifile(&f);
323368c31abSDavid du Colombier return ok;
324368c31abSDavid du Colombier }
325368c31abSDavid du Colombier
326368c31abSDavid du Colombier int
wbarenamap(AMap * am,int n,Part * part,u64int base,u64int size)327368c31abSDavid du Colombier wbarenamap(AMap *am, int n, Part *part, u64int base, u64int size)
328368c31abSDavid du Colombier {
329368c31abSDavid du Colombier Fmt f;
330368c31abSDavid du Colombier ZBlock *b;
331368c31abSDavid du Colombier
332368c31abSDavid du Colombier b = alloczblock(size, 1, part->blocksize);
333368c31abSDavid du Colombier if(b == nil)
334368c31abSDavid du Colombier return -1;
335368c31abSDavid du Colombier
336368c31abSDavid du Colombier fmtzbinit(&f, b);
337368c31abSDavid du Colombier
338368c31abSDavid du Colombier if(outputamap(&f, am, n) < 0){
339368c31abSDavid du Colombier seterr(ECorrupt, "arena set size too small");
340368c31abSDavid du Colombier freezblock(b);
341368c31abSDavid du Colombier return -1;
342368c31abSDavid du Colombier }
343368c31abSDavid du Colombier if(writepart(part, base, b->data, size) < 0 || flushpart(part) < 0){
344368c31abSDavid du Colombier seterr(EAdmin, "can't write arena set: %r");
345368c31abSDavid du Colombier freezblock(b);
346368c31abSDavid du Colombier return -1;
347368c31abSDavid du Colombier }
348368c31abSDavid du Colombier freezblock(b);
349368c31abSDavid du Colombier return 0;
350368c31abSDavid du Colombier }
351368c31abSDavid du Colombier
352368c31abSDavid du Colombier /*
353368c31abSDavid du Colombier * amap: n '\n' amapelem * n
354368c31abSDavid du Colombier * n: u32int
355368c31abSDavid du Colombier * amapelem: name '\t' astart '\t' astop '\n'
356368c31abSDavid du Colombier * astart, astop: u64int
357368c31abSDavid du Colombier */
358368c31abSDavid du Colombier int
parseamap(IFile * f,AMapN * amn)359368c31abSDavid du Colombier parseamap(IFile *f, AMapN *amn)
360368c31abSDavid du Colombier {
361368c31abSDavid du Colombier AMap *am;
362368c31abSDavid du Colombier u64int v64;
363368c31abSDavid du Colombier u32int v;
364368c31abSDavid du Colombier char *s, *t, *flds[4];
365368c31abSDavid du Colombier int i, n;
366368c31abSDavid du Colombier
367368c31abSDavid du Colombier /*
368368c31abSDavid du Colombier * arenas
369368c31abSDavid du Colombier */
370368c31abSDavid du Colombier if(ifileu32int(f, &v) < 0){
371368c31abSDavid du Colombier seterr(ECorrupt, "syntax error: bad number of elements in %s", f->name);
372368c31abSDavid du Colombier return -1;
373368c31abSDavid du Colombier }
374368c31abSDavid du Colombier n = v;
375368c31abSDavid du Colombier if(n > MaxAMap){
37668860d28SDavid du Colombier seterr(ECorrupt, "illegal number of elements %d in %s",
37768860d28SDavid du Colombier n, f->name);
378368c31abSDavid du Colombier return -1;
379368c31abSDavid du Colombier }
380368c31abSDavid du Colombier am = MKNZ(AMap, n);
381368c31abSDavid du Colombier if(am == nil){
382368c31abSDavid du Colombier fprint(2, "out of memory\n");
383368c31abSDavid du Colombier return -1;
384368c31abSDavid du Colombier }
385368c31abSDavid du Colombier for(i = 0; i < n; i++){
386368c31abSDavid du Colombier s = ifileline(f);
387368c31abSDavid du Colombier if(s)
388368c31abSDavid du Colombier t = estrdup(s);
389368c31abSDavid du Colombier else
390368c31abSDavid du Colombier t = nil;
391368c31abSDavid du Colombier if(s == nil || getfields(s, flds, 4, 0, "\t") != 3){
392368c31abSDavid du Colombier fprint(2, "early eof after %d of %d, %s:#%d: %s\n", i, n, f->name, f->pos, t);
393368c31abSDavid du Colombier free(t);
394368c31abSDavid du Colombier return -1;
395368c31abSDavid du Colombier }
396368c31abSDavid du Colombier free(t);
397368c31abSDavid du Colombier if(nameok(flds[0]) < 0)
398368c31abSDavid du Colombier return -1;
399368c31abSDavid du Colombier namecp(am[i].name, flds[0]);
400368c31abSDavid du Colombier if(stru64int(flds[1], &v64) < 0){
401368c31abSDavid du Colombier seterr(ECorrupt, "syntax error: bad arena base address in %s", f->name);
402368c31abSDavid du Colombier free(am);
403368c31abSDavid du Colombier return -1;
404368c31abSDavid du Colombier }
405368c31abSDavid du Colombier am[i].start = v64;
406368c31abSDavid du Colombier if(stru64int(flds[2], &v64) < 0){
407368c31abSDavid du Colombier seterr(ECorrupt, "syntax error: bad arena size in %s", f->name);
408368c31abSDavid du Colombier free(am);
409368c31abSDavid du Colombier return -1;
410368c31abSDavid du Colombier }
411368c31abSDavid du Colombier am[i].stop = v64;
412368c31abSDavid du Colombier }
413368c31abSDavid du Colombier
414368c31abSDavid du Colombier amn->map = am;
415368c31abSDavid du Colombier amn->n = n;
416368c31abSDavid du Colombier return 0;
417368c31abSDavid du Colombier }
418368c31abSDavid du Colombier
419368c31abSDavid du Colombier int
outputamap(Fmt * f,AMap * am,int n)420368c31abSDavid du Colombier outputamap(Fmt *f, AMap *am, int n)
421368c31abSDavid du Colombier {
422368c31abSDavid du Colombier int i;
423368c31abSDavid du Colombier
424368c31abSDavid du Colombier if(fmtprint(f, "%ud\n", n) < 0)
425368c31abSDavid du Colombier return -1;
426368c31abSDavid du Colombier for(i = 0; i < n; i++)
427368c31abSDavid du Colombier if(fmtprint(f, "%s\t%llud\t%llud\n", am[i].name, am[i].start, am[i].stop) < 0)
428368c31abSDavid du Colombier return -1;
429368c31abSDavid du Colombier return 0;
430368c31abSDavid du Colombier }
431