1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1998-2013 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <glenn.s.fowler@gmail.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21
22 /*
23 * partition support
24 */
25
26 static const char usage[] =
27 "[-1i?\n@(#)$Id: pz library 2.4 (AT&T Research) 2011-03-07 $\n]"
28 "[a:append]"
29 "[c:comment]:[text]"
30 "[x:crc]"
31 "[d:debug]#[level]"
32 "[D:dump]"
33 "[G!:gzip]"
34 "[i:include]:[file]"
35 "[l:library]:[library]"
36 "[n:name]:[name]"
37 "[X:prefix?]:[count[*terminator]]]"
38 "[O:sort]"
39 "[P!:pzip]"
40 "[Q:regress]"
41 "[r:row]#[row-size]"
42 "[S:split]:?[pattern]"
43 "[s:summary]"
44 "[T:test]#[mask]"
45 "[v:verbose]"
46 ;
47
48 #include "pzlib.h"
49
50 #define VECTOR(z,p,n) (((z)->flags&PZ_OVERSIZE)?(p)->row:(n))
51
52 /*
53 * return partition pointer given name
54 */
55
56 Pzpart_t*
pzpartget(Pz_t * pz,const char * name)57 pzpartget(Pz_t* pz, const char* name)
58 {
59 if (!name || !*name || !pz->partdict)
60 return pz->mainpart;
61 pz->flags &= ~PZ_MAINONLY;
62 return (Pzpart_t*)dtmatch(pz->partdict, name);
63 }
64
65 /*
66 * partition iterator
67 * return the next partition after pp
68 * first call should set pp to 0
69 * 0 returned after all partitions visited
70 */
71
72 Pzpart_t*
pzpartnext(Pz_t * pz,Pzpart_t * pp)73 pzpartnext(Pz_t* pz, Pzpart_t* pp)
74 {
75 if (pz->partdict)
76 return pp ? (Pzpart_t*)dtnext(pz->partdict, pp) : (Pzpart_t*)dtfirst(pz->partdict);
77 return pp ? (Pzpart_t*)0 : pz->mainpart;
78 }
79
80 /*
81 * set the current partition to pp
82 * old partition returned
83 */
84
85 Pzpart_t*
pzpartset(Pz_t * pz,Pzpart_t * pp)86 pzpartset(Pz_t* pz, Pzpart_t* pp)
87 {
88 Pzpart_t* op;
89
90 pz->flags &= ~PZ_MAINONLY;
91 if (pzsync(pz))
92 return 0;
93 op = pz->part;
94 pz->part = pp;
95 return op;
96 }
97
98 /*
99 * parse a column range at s
100 * return
101 * -1 error
102 * 0 not a range
103 * 1 ok
104 */
105
106 static int
range(Pz_t * pz,register Pzpart_t * pp,char * s,char ** p,int * beg,int * end)107 range(Pz_t* pz, register Pzpart_t* pp, char* s, char** p, int* beg, int* end)
108 {
109 int n;
110 int m;
111 char* e;
112
113 for (; isspace(*s) || *s == ','; s++);
114 if (*s == '-')
115 n = 0;
116 else
117 {
118 n = (int)strtol(s, &e, 10);
119 if (s == e)
120 {
121 if (p)
122 *p = e;
123 return 0;
124 }
125 if (pp && n >= pp->row)
126 {
127 if (pz->disc->errorf)
128 (*pz->disc->errorf)(pz, pz->disc, 2, "column %d is larger than row %d", n, pp->row);
129 return -1;
130 }
131 for (s = e; isspace(*s); s++);
132 }
133 if (*s == '-')
134 {
135 if (!*++s || isspace(*s) || *s == ',')
136 {
137 e = s;
138 m = (pp ? pp->row : INT_MAX) - 1;
139 }
140 else
141 {
142 m = (int)strtol(s, &e, 10);
143 if (m < n || pp && m >= pp->row)
144 {
145 if (pz->disc->errorf)
146 (*pz->disc->errorf)(pz, pz->disc, 2, "invalid column range %d-%d", n, m);
147 return -1;
148 }
149 }
150 }
151 else
152 m = n;
153 if (p)
154 {
155 for (s = e; isspace(*s) || *s == ','; s++);
156 *p = s;
157 }
158 if (beg)
159 *beg = n;
160 if (end)
161 *end = m;
162 return 1;
163 }
164
165 /*
166 * parse a character value at s
167 */
168
169 static int
value(Pz_t * pz,char * s,char ** p)170 value(Pz_t* pz, char* s, char** p)
171 {
172 char* e;
173 int q;
174 int v;
175
176 for (; isspace(*s); s++);
177 if (!(q = *s++) || ((v = chresc(s, &e)), s == e))
178 {
179 if (pz->disc->errorf)
180 (*pz->disc->errorf)(pz, pz->disc, 2, "value expected");
181 return -1;
182 }
183 s = e;
184 if (*s++ != q)
185 {
186 if (pz->disc->errorf)
187 (*pz->disc->errorf)(pz, pz->disc, 2, "unbalanced %c quote in value", q);
188 return -1;
189 }
190 if (*p)
191 *p = s;
192 return v;
193 }
194
195 /*
196 * add fixed column range value to pz
197 */
198
199 static int
fixed(Pz_t * pz,register Pzpart_t * pp,int n,int m,int k)200 fixed(Pz_t* pz, register Pzpart_t* pp, int n, int m, int k)
201 {
202 int i;
203 int v;
204
205 if (!pp->value)
206 {
207 if (!(pp->value = vmnewof(pz->vm, 0, int, pp->row, 0)))
208 return pznospace(pz);
209 for (i = 0; i < pp->row; i++)
210 pp->value[i] = -1;
211 }
212 v = k < 0 ? ' ' : k;
213 for (; n <= m; n++)
214 {
215 if (pp->value[n] < 0)
216 pp->nfix++;
217 else if (k < 0)
218 continue;
219 pp->value[n] = v;
220 }
221 return 0;
222 }
223
224 /*
225 * initialize the partition map from pp.{<map,nmap>,<grp,ngrp>}
226 */
227
228 int
pzpartmap(Pz_t * pz,register Pzpart_t * pp)229 pzpartmap(Pz_t* pz, register Pzpart_t* pp)
230 {
231 int i;
232 int j;
233 int k;
234
235 k = 0;
236 for (i = 0; i < pp->ngrp; i++)
237 for (j = 0; j < pp->grp[i]; j++)
238 {
239 if (k >= pp->nmap)
240 {
241 if (pz->disc->errorf)
242 (*pz->disc->errorf)(pz, pz->disc, 2, "%s: invalid group", pz->path);
243 return -1;
244 }
245 pp->lab[k] = i;
246 pp->inc[k++] = pp->grp[i];
247 }
248 if (k != pp->nmap)
249 {
250 if (pz->disc->errorf)
251 (*pz->disc->errorf)(pz, pz->disc, 2, "%s: invalid group", pz->path);
252 return -1;
253 }
254 memset(pp->low, 1, pp->row);
255 for (i = 0; i < pp->nmap; i++)
256 pp->low[pp->map[i]] = 0;
257 for (i = 0; i < pp->nfix; i++)
258 pp->low[pp->fix[i]] = 0;
259 if ((pz->flags & PZ_READ) && pp->value)
260 for (i = j = 0; i < pp->nmap; i++)
261 if (pp->value[i] < 0)
262 pp->map[j++] = pp->map[i];
263 pp->flags |= PZ_UPDATE;
264 return 0;
265 }
266
267 /*
268 * initialize the partition workspace
269 */
270
271 int
pzpartinit(Pz_t * pz,Pzpart_t * pp,const char * name)272 pzpartinit(Pz_t* pz, Pzpart_t* pp, const char* name)
273 {
274 char* s;
275 int i;
276 int j;
277 int k;
278 size_t m;
279 size_t n;
280
281 m = 0;
282 if (!(pz->flags & PZ_FORCE) || (pz->flags & PZ_SPLIT))
283 {
284 if (!pp->row)
285 {
286 if (pz->disc->errorf)
287 (*pz->disc->errorf)(pz, pz->disc, 2, "%s: partition header corrupted", pz->path);
288 return -1;
289 }
290 if (!pp->name)
291 {
292 if (!name)
293 sfprintf(pz->tmp, "%s:%d:%d", PZ_PART_SUF, pp->row, pp->nmap);
294 else
295 {
296 if (s = strrchr(name, '/'))
297 name = (const char*)s + 1;
298 if ((s = strrchr(name, '.')) && streq(s + 1, PZ_PART_SUF))
299 n = s - (char*)name;
300 else
301 n = strlen(name);
302 sfprintf(pz->tmp, "%.*s", n, name);
303 }
304 if (!(s = sfstruse(pz->tmp)) || !(pp->name = vmstrdup(pz->vm, s)))
305 return -1;
306 }
307 if (!pp->nmap)
308 {
309 pp->nmap = pp->row;
310 if (!(pp->map = vmnewof(pz->vm, pp->map, size_t, VECTOR(pz, pp, pp->nmap), 0)))
311 return pznospace(pz);
312 for (i = 0; i < pp->nmap; i++)
313 pp->map[i] = i;
314 }
315 if (!pp->ngrp)
316 {
317 pp->ngrp = 1;
318 if (!(pp->grp = vmnewof(pz->vm, pp->grp, size_t, VECTOR(pz, pp, pp->ngrp), 0)))
319 return pznospace(pz);
320 pp->grp[0] = pp->row;
321 }
322 pp->loq = ((pz->win / 8 / pp->row) + 8) * pp->row;
323 k = VECTOR(pz, pp, pp->nmap);
324 if (!(pp->low = vmnewof(pz->vm, 0, unsigned char, pp->row, 0)) ||
325 !(pp->mix = vmnewof(pz->vm, 0, unsigned char*, k, 0)) ||
326 !(pp->inc = vmnewof(pz->vm, 0, size_t, k, 0)) ||
327 !(pp->lab = vmnewof(pz->vm, 0, size_t, k, 0)))
328 return pznospace(pz);
329 if (pp->nfix)
330 {
331 if (!(pp->fix = vmnewof(pz->vm, 0, size_t, VECTOR(pz, pp, pp->nfix), 0)))
332 return pznospace(pz);
333 for (i = k = 0; i < pp->row; i++)
334 if (pp->value[i] >= 0)
335 pp->fix[k++] = i;
336 }
337 if (pzpartmap(pz, pp))
338 return -1;
339 if (!(j = pp->nmap))
340 j = 1;
341 k = pp->row * j;
342 pp->col = ((pz->win / k) * k) / j;
343
344 /*
345 * allocate the global tables
346 */
347
348 if (pp->row > pz->mrow)
349 {
350 m = pz->mrow = roundof(pp->row, 1024);
351 n = ((pz->win / 8 / m) + 8 ) * m;
352 if (!(pz->val = vmnewof(pz->vm, pz->val, unsigned char, n, 0)) ||
353 !(pz->pat = vmnewof(pz->vm, pz->pat, unsigned char, m, 0)))
354 return pznospace(pz);
355 }
356 }
357 if (pz->win > pz->mwin)
358 {
359 if (pz->disc->errorf)
360 (*pz->disc->errorf)(pz, pz->disc, -1, "%s: pzpartinit: win=%I*u mwin=%I*u buf=%p", pz->path, sizeof(pz->win), pz->win, sizeof(pz->mwin), pz->mwin, pz->buf);
361 pz->mwin = roundof(pz->win, 32);
362 n = pz->mwin;
363 if (pz->flags & PZ_WRITE)
364 n *= 2;
365 if (!(pz->buf = vmnewof(pz->vm, pz->buf, unsigned char, n, 0)))
366 return pznospace(pz);
367 if (pz->flags & PZ_WRITE)
368 pz->wrk = pz->buf + pz->mwin;
369 }
370 if (m && !(pz->flags & PZ_WRITE) && !(pz->wrk = vmnewof(pz->vm, pz->wrk, unsigned char, m, 0)))
371 return pznospace(pz);
372
373 /*
374 * the discipline functions may change the partition name
375 */
376
377 n = pp->nfix;
378 pz->part = pp;
379 if (pz->options && pzoptions(pz, pp, pz->options, 0))
380 return -1;
381 if (pz->disc->eventf && (*pz->disc->eventf)(pz, PZ_PARTITION, pp, 0, pz->disc) < 0)
382 return -1;
383 if (pp->flags & PZ_VARIABLE)
384 return 0;
385 if (pp->nfix != n)
386 {
387 if (!(pp->fix = vmnewof(pz->vm, pp->fix, size_t, VECTOR(pz, pp, pp->nfix), 0)))
388 return pznospace(pz);
389 for (i = k = 0; i < pp->row; i++)
390 if (pp->value[i] >= 0)
391 pp->low[pp->fix[k++] = i] = 0;
392 }
393
394 /*
395 * update the partition dictionary
396 * no dictionary if there's only one part
397 */
398
399 if (pz->mainpart)
400 {
401 if (!pz->partdict)
402 {
403 pz->partdisc.key = offsetof(Pzpart_t, name);
404 pz->partdisc.size = -1;
405 pz->partdisc.link = offsetof(Pzpart_t, link);
406 if (!(pz->partdict = dtopen(&pz->partdisc, Dtoset)))
407 {
408 if (pz->disc->errorf)
409 (*pz->disc->errorf)(pz, pz->disc, 2, "partition dictionary open error");
410 return -1;
411 }
412 dtinsert(pz->partdict, pz->mainpart);
413 }
414 dtinsert(pz->partdict, pp);
415 }
416 else
417 {
418 pz->mainpart = pp;
419 if ((pz->flags & (PZ_DUMP|PZ_VERBOSE)) && !(pz->flags & PZ_SPLIT))
420 pzheadprint(pz, sfstderr, 0);
421 }
422 if ((pz->flags & PZ_DUMP) && !(pz->flags & PZ_SPLIT))
423 pzpartprint(pz, pp, sfstderr);
424 return 0;
425 }
426
427 /*
428 * parse the run time options
429 */
430
431 int
pzoptions(register Pz_t * pz,register Pzpart_t * pp,char * options,int must)432 pzoptions(register Pz_t* pz, register Pzpart_t* pp, char* options, int must)
433 {
434 register char* s = options;
435 char* e;
436 char* b;
437 int i;
438 int k;
439 int n;
440 int r;
441 int x;
442 int skip;
443 Sfio_t* sp;
444 Pzpart_t* opp;
445
446 optget(NiL, usage);
447 skip = 0;
448 for (;;)
449 {
450 for (; isspace(*s) || *s == ','; s++);
451 if (!*s)
452 break;
453 switch (range(pz, pp, s, &e, &n, &x))
454 {
455 case -1:
456 return -1;
457 case 1:
458 s = e;
459 if (*s++ != '=')
460 s = "";
461 if ((k = value(pz, s, &e)) < 0)
462 return -1;
463 s = e;
464 if (pp && fixed(pz, pp, n, x, k))
465 return -1;
466 continue;
467 }
468 b = s;
469 opt_info.offset = 0;
470 switch (optstr(s, NiL))
471 {
472 case 0:
473 break;
474 case '#':
475 skip = !streq(opt_info.name, "pzip");
476 continue;
477 default:
478 if (pz->disc->errorf)
479 (*pz->disc->errorf)(pz, pz->disc, -2, "pzoptions: %-.*s", opt_info.offset, s);
480 s += opt_info.offset;
481 if (skip)
482 continue;
483
484 /*
485 * the discipline gets the first crack
486 *
487 * -1 error
488 * 0 noticed but not consumed
489 * 1 consumed
490 */
491
492 if (pz->disc->eventf)
493 {
494 opp = pz->part;
495 pz->part = pp;
496 x = (*pz->disc->eventf)(pz, PZ_OPTION, opt_info.argv[1] + 2, 0, pz->disc);
497 pz->part = opp;
498 if (x < 0)
499 return -1;
500 }
501 else
502 x = 0;
503 if (!x)
504 {
505 x = 2;
506 switch (optstr(NiL, usage))
507 {
508 case 'a':
509 if (opt_info.num)
510 pz->flags |= PZ_APPEND;
511 else
512 pz->flags &= ~PZ_APPEND;
513 break;
514 case 'c':
515 if (!pz->disc->comment && !(pz->disc->comment = vmstrdup(pz->vm, opt_info.arg)))
516 return pznospace(pz);
517 break;
518 case 'x':
519 if (opt_info.num)
520 pz->flags |= PZ_CRC;
521 else
522 pz->flags &= ~PZ_CRC;
523 break;
524 case 'd':
525 error_info.trace = -opt_info.num;
526 break;
527 case 'D':
528 if (opt_info.num)
529 pz->flags |= PZ_DUMP;
530 else
531 pz->flags &= ~PZ_DUMP;
532 break;
533 case 'G':
534 if (!opt_info.num)
535 pz->flags |= PZ_NOGZIP;
536 else
537 pz->flags &= ~PZ_NOGZIP;
538 break;
539 case 'i':
540 if (pz->pin && (sp = pzfind(pz, opt_info.arg, PZ_PART_SUF, "r")))
541 {
542 sfstack(pz->pin, sp);
543 return 0;
544 }
545 break;
546 case 'l':
547 if (!pz->pin || !sfstacked(pz->pin))
548 {
549 if (i = pz->options == options)
550 pz->options = 0;
551 r = pzlib(pz, opt_info.arg, 0);
552 if (pz->disc->errorf)
553 (*pz->disc->errorf)(pz, pz->disc, -2, "pzlib: %s status=%d", opt_info.arg, r);
554 if (i)
555 pz->options = options;
556 if (r < 0)
557 return -1;
558 }
559 break;
560 case 'n':
561 pz->partname = vmstrdup(pz->vm, opt_info.arg);
562 break;
563 case 'X':
564 if (pz->prefix.count = strton(opt_info.arg, &e, NiL, 0))
565 {
566 pz->prefix.terminator = -1;
567 if (*e == 'x' || *e == 'X' || *e == '*' || *e == '-')
568 e++;
569 if (*e == 'l' || *e == 'L')
570 pz->prefix.terminator = '\n';
571 else
572 {
573 if (*e == '"' || *e == '\'')
574 {
575 pz->prefix.terminator = chresc(e + 1, &e);
576 for (s = e; *s && !isspace(*s) && *s != ','; s++);
577 }
578 else if (*e)
579 {
580 pz->prefix.count = 0;
581 if (pz->disc->errorf)
582 (*pz->disc->errorf)(pz, pz->disc, 2, "%s: prefix expression expected", opt_info.arg);
583 return -1;
584 }
585 }
586 }
587 else if (e > opt_info.arg)
588 pz->prefix.skip = 1;
589 break;
590 case 'O':
591 if (opt_info.num)
592 pz->flags |= PZ_SORT;
593 else
594 pz->flags &= ~PZ_SORT;
595 break;
596 case 'P':
597 if (!opt_info.num)
598 pz->flags |= PZ_NOPZIP;
599 else
600 pz->flags &= ~PZ_NOPZIP;
601 break;
602 case 'Q':
603 if (opt_info.num)
604 pz->flags |= PZ_REGRESS;
605 else
606 pz->flags &= ~PZ_REGRESS;
607 break;
608 case 'r':
609 pz->row = opt_info.num;
610 break;
611 case 'S':
612 if (opt_info.num)
613 {
614 pz->flags |= PZ_FORCE|PZ_SPLIT|PZ_SECTION;
615 if (opt_info.arg)
616 pz->split.match = vmstrdup(pz->vm, opt_info.arg);
617 }
618 else
619 pz->flags &= ~PZ_SPLIT;
620 break;
621 case 's':
622 if (opt_info.num)
623 pz->flags |= PZ_SUMMARY;
624 else
625 pz->flags &= ~PZ_SUMMARY;
626 break;
627 case 'T':
628 pz->test |= opt_info.num;
629 break;
630 case 'v':
631 if (opt_info.num)
632 pz->flags |= PZ_VERBOSE;
633 else
634 pz->flags &= ~PZ_VERBOSE;
635 break;
636 case '?':
637 error(ERROR_USAGE|4, "%s", opt_info.arg);
638 return -1;
639 case ':':
640 if (must && !(pz->flags & PZ_PUSHED))
641 {
642 if (pz->disc->errorf)
643 (*pz->disc->errorf)(pz, pz->disc, 2, "%s", opt_info.arg);
644 return -1;
645 }
646 x = 0;
647 break;
648 }
649 }
650
651 /*
652 * save consumed options for the header and
653 * clear so they are not processed again
654 */
655
656 if (must >= 0 && (x > 1 || x && must))
657 {
658 if (pz->det)
659 {
660 if (sfstrtell(pz->det))
661 sfputc(pz->det, ' ');
662 sfwrite(pz->det, b, s - b);
663 }
664 memset(b, ' ', s - b);
665 }
666 continue;
667 }
668 break;
669 }
670 return 0;
671 }
672
673 static char*
partline(Pz_t * pz,Sfio_t * sp)674 partline(Pz_t* pz, Sfio_t* sp)
675 {
676 char* s;
677
678 if ((s = sfgetr(sp, '\n', 1)) && pz->disc->errorf)
679 error_info.line++;
680 return s;
681 }
682
683 /*
684 * parse and load a partition file
685 */
686
687 int
pzpartition(register Pz_t * pz,const char * partition)688 pzpartition(register Pz_t* pz, const char* partition)
689 {
690 register Pzpart_t* pp;
691 int i;
692 int k;
693 int m;
694 char* s;
695 char* e;
696 char* t;
697 char* np;
698 int n;
699 int g;
700 int gi;
701 int x;
702 int* cv;
703 int* ce;
704 int* cp;
705 int* gv;
706 int* hv;
707 int line;
708 long f;
709 char* file;
710 Sfio_t* sp;
711 Vmalloc_t* vm;
712 char buf[PATH_MAX];
713
714 if (pz->disc->errorf)
715 {
716 file = error_info.file;
717 line = error_info.line;
718 }
719 sp = 0;
720 vm = 0;
721 if (!(s = (char*)partition))
722 {
723 if (pz->disc->errorf)
724 (*pz->disc->errorf)(pz, pz->disc, 2, "partition file omitted");
725 goto bad;
726 }
727 if (s[0] == '/' && s[i=strlen(s)-1] == '/')
728 {
729 if (streq(s, "/") || streq(s, "//") || streq(s, "/gzip/"))
730 n = sfsprintf(buf, sizeof(buf), "nopzip\n1\n0-0\n");
731 else
732 {
733 n = (int)strtol(s + 1, &e, 10);
734 if (e[0] == '/' && !e[1])
735 n = sfsprintf(buf, sizeof(buf), "%d\n0-%d\n", n, n - 1);
736 else
737 {
738 n = sfsprintf(buf, sizeof(buf), "%.*s\n", i - 1, s + 1);
739 for (s = buf; *s; s++)
740 if (isspace(*s) || *s == ',')
741 *s = '\n';
742 }
743 }
744 if (!(sp = sfstropen()) || sfstrbuf(sp, buf, n, 0))
745 {
746 if (pz->disc->errorf)
747 (*pz->disc->errorf)(pz, pz->disc, 2, "%s: string stream open error", s);
748 goto bad;
749 }
750 }
751 else
752 {
753 /*
754 * consume url-ish options
755 */
756
757 if ((e = strchr(s, '?')) || (e = strchr(s, '#')))
758 {
759 if (!(t = vmoldof(pz->vm, 0, char, e - s, 1)))
760 goto bad;
761 memcpy(t, s, e - s);
762 t[e - s] = 0;
763 s = t;
764 if (*e == '#' && !(pz->partname = vmstrdup(pz->vm, e + 1)) || *e == '?' && pzoptions(pz, NiL, e + 1, 1))
765 goto bad;
766 }
767 if (!(sp = pzfind(pz, s, PZ_PART_SUF, "r")))
768 goto bad;
769 }
770 if (pz->disc->errorf)
771 {
772 error_info.file = s;
773 error_info.line = 0;
774 }
775 if (!(vm = vmopen(Vmdcheap, Vmlast, 0)))
776 {
777 if (pz->disc->errorf)
778 (*pz->disc->errorf)(pz, pz->disc, ERROR_SYSTEM|2, "partition temporary vmalloc region open error");
779 goto bad;
780 }
781 np = 0;
782 pp = 0;
783 s = "";
784 pz->pin = sp;
785 do
786 {
787 vmclear(vm);
788 do
789 {
790 if (*s != '"' && !(s = partline(pz, sp)))
791 {
792 if (pz->disc->errorf)
793 (*pz->disc->errorf)(pz, pz->disc, 2, "invalid partition file");
794 goto bad;
795 }
796 for (; isspace(*s); s++);
797 if (*s == '"')
798 {
799 if (np)
800 {
801 if (pz->disc->errorf)
802 (*pz->disc->errorf)(pz, pz->disc, 2, "%s: partition already named", np);
803 goto bad;
804 }
805 for (e = ++s; *s && *s != '"'; s++);
806 if (!*s)
807 {
808 if (pz->disc->errorf)
809 (*pz->disc->errorf)(pz, pz->disc, 2, "unbalanced \" in partition name");
810 goto bad;
811 }
812 *s++ = 0;
813 if (!(np = vmstrdup(pz->vm, e)))
814 goto bad;
815 for (; isspace(*s); s++);
816 }
817 if (isalpha(*s))
818 {
819 if (pzoptions(pz, pp, s, 1))
820 goto bad;
821 s = "";
822 }
823 } while (!(n = strtol(s, &t, 10)));
824 if (*t == '@')
825 {
826 switch (m = strtol(t + 1, &t, 10))
827 {
828 case 1:
829 m = 0;
830 break;
831 case 2:
832 m = 1;
833 break;
834 case 4:
835 m = 2;
836 break;
837 case 8:
838 m = 3;
839 break;
840 default:
841 if (pz->disc->errorf)
842 (*pz->disc->errorf)(pz, pz->disc, 2, "%s: %d: invalid size -- power of 2 from 1..8 expected", s, m);
843 goto bad;
844 }
845 n |= (m << 14);
846 f = PZ_VARIABLE;
847 }
848 else
849 f = 0;
850 if (pz->flags & PZ_ROWONLY)
851 {
852 if (!np || !pz->partname || streq(np, pz->partname))
853 {
854 vmclose(vm);
855 pz->row = n;
856 return 0;
857 }
858 np = 0;
859 do
860 {
861 if (!(s = partline(pz, sp)))
862 {
863 if (pz->disc->errorf)
864 (*pz->disc->errorf)(pz, pz->disc, 2, "%s: partition not found", pz->partname);
865 goto bad;
866 }
867 for (; isspace(*s); s++);
868 } while (*s != '"');
869 continue;
870 }
871 if (!(pp = vmnewof(pz->vm, 0, Pzpart_t, 1, 0)))
872 goto nope;
873 pp->row = n;
874 pp->flags = f;
875 if (np)
876 {
877 pp->name = np;
878 np = 0;
879 }
880 if (!(cv = vmnewof(vm, 0, int, (pp->row + 1) * 4, 0)))
881 goto nope;
882 cp = cv;
883 ce = hv = cv + (pp->row + 1) * 2;
884 gv = hv + pp->row + 1;
885 m = 0;
886 g = 0;
887 for (s = t; isspace(*s); s++);
888 if (*s != '-')
889 s = partline(pz, sp);
890 for (; s; s = partline(pz, sp))
891 {
892 for (; isspace(*s); s++);
893 if (*s == '"')
894 break;
895 else if (isalpha(*s))
896 {
897 if (pzoptions(pz, pp, s, 1))
898 goto bad;
899 continue;
900 }
901 gi = 0;
902 for (;;)
903 {
904 if (range(pz, pp, s, &e, &n, &x) <= 0)
905 {
906 if (*e && *e != '#')
907 goto bad;
908 break;
909 }
910 s = e;
911 if (*s == '=')
912 {
913 if ((k = value(pz, ++s, &e)) < 0)
914 return -1;
915 s = e;
916 if (fixed(pz, pp, n, x, k))
917 goto bad;
918 continue;
919 }
920 if (cp >= ce)
921 {
922 if (pz->disc->errorf)
923 (*pz->disc->errorf)(pz, pz->disc, 2, "too many columns");
924 goto bad;
925 }
926 for (; n <= x; n++)
927 if (!pp->value || pp->value[n] < 0)
928 {
929 if (hv[n])
930 {
931 if (pz->disc->errorf)
932 (*pz->disc->errorf)(pz, pz->disc, 2, "column %d already specified", n);
933 goto bad;
934 }
935 hv[n] = 1;
936 *cp++ = n;
937 gv[m] = g;
938 m++;
939 gi = 1;
940 }
941 }
942 if (gi)
943 {
944 if (cp >= ce)
945 {
946 if (pz->disc->errorf)
947 (*pz->disc->errorf)(pz, pz->disc, 2, "too many columns");
948 goto bad;
949 }
950 *cp++ = -1;
951 g += gi;
952 }
953 }
954 if (cp >= ce)
955 {
956 if (pz->disc->errorf)
957 (*pz->disc->errorf)(pz, pz->disc, 2, "too many columns");
958 goto bad;
959 }
960 *cp++ = -1;
961
962 /*
963 * allocate the map data and work space
964 */
965
966 pp->nmap = m;
967 if (!(pp->ngrp = g))
968 pp->ngrp = 1;
969 if (!(pp->map = vmnewof(pz->vm, 0, size_t, VECTOR(pz, pp, pp->nmap), 0)) ||
970 !(pp->grp = vmnewof(pz->vm, 0, size_t, VECTOR(pz, pp, pp->ngrp), 0)))
971 goto nope;
972 m = 0;
973 cp = cv;
974 g = 0;
975 k = 0;
976 while ((i = *cp++) >= 0)
977 do
978 {
979 if (g != gv[m])
980 {
981 pp->grp[g] = k;
982 g = gv[m];
983 k = 0;
984 }
985 pp->map[m] = i;
986 k++;
987 m++;
988 } while ((i = *cp++) >= 0);
989 pp->grp[g] = k;
990 if (pzpartinit(pz, pp, partition))
991 goto bad;
992 } while (s);
993 sfclose(sp);
994 sp = 0;
995 vmclose(vm);
996 vm = 0;
997 if (pz->partname)
998 {
999 if (!(pp = pzpartget(pz, pz->partname)))
1000 {
1001 if (pz->disc->errorf)
1002 (*pz->disc->errorf)(pz, pz->disc, 2, "%s: partition not found", pz->partname);
1003 goto bad;
1004 }
1005 pz->flags |= PZ_MAINONLY;
1006 pz->part = pz->mainpart = pp;
1007 }
1008 if (pz->disc->errorf)
1009 {
1010 error_info.file = file;
1011 error_info.line = line;
1012 }
1013 pz->pin = 0;
1014 return 0;
1015 nope:
1016 pznospace(pz);
1017 bad:
1018 pz->pin = 0;
1019 if (sp)
1020 sfclose(sp);
1021 if (vm)
1022 vmclose(vm);
1023 if (pz->disc->errorf)
1024 {
1025 error_info.file = file;
1026 error_info.line = line;
1027 }
1028 return -1;
1029 }
1030
1031 /*
1032 * allocate and read an array from the input partition header
1033 */
1034
1035 static int
array(register Pz_t * pz,Pzpart_t * pp,size_t ** pv,size_t * pn,size_t check)1036 array(register Pz_t* pz, Pzpart_t* pp, size_t** pv, size_t* pn, size_t check)
1037 {
1038 register size_t n;
1039 register size_t m;
1040 register size_t* v;
1041
1042 n = sfgetu(pz->io);
1043 if (check && n > check)
1044 return -1;
1045 if (pv)
1046 {
1047 if (!n)
1048 v = 0;
1049 else if (!(v = vmnewof(pz->vm, *pv, size_t, VECTOR(pz, pp, n), 0)))
1050 return pznospace(pz);
1051 *pv = v;
1052 if (pn)
1053 *pn = n;
1054 while (n--)
1055 {
1056 m = sfgetu(pz->io);
1057 if (check && m >= check)
1058 return -1;
1059 *v++ = m;
1060 }
1061 }
1062 else
1063 while (n--)
1064 {
1065 m = sfgetu(pz->io);
1066 if (check && m >= check)
1067 return -1;
1068 }
1069 return 0;
1070 }
1071
1072 /*
1073 * allocate and read a buffer from the input partition header
1074 */
1075
1076 static int
buffer(register Pz_t * pz,Pzpart_t * pp,char ** pv,size_t * pn)1077 buffer(register Pz_t* pz, Pzpart_t* pp, char** pv, size_t* pn)
1078 {
1079 register size_t n;
1080 register char* v;
1081
1082 if (!(n = sfgetu(pz->io)))
1083 {
1084 if (pz->disc->errorf)
1085 (*pz->disc->errorf)(pz, pz->disc, 2, "%s: partition header corrupted", pz->path);
1086 return -1;
1087 }
1088 if (pv)
1089 {
1090 if (!(v = vmnewof(pz->vm, *pv, char, n, 0)))
1091 return pznospace(pz);
1092 *pv = v;
1093 if (pn)
1094 *pn = n;
1095 sfread(pz->io, v, n);
1096 }
1097 else
1098 sfseek(pz->io, (Sflong_t)n, SEEK_CUR);
1099 return 0;
1100 }
1101
1102 /*
1103 * read a pz partition header(s) from pz->io
1104 */
1105
1106 int
pzpartread(register Pz_t * pz)1107 pzpartread(register Pz_t* pz)
1108 {
1109 register Pzpart_t* pp;
1110 register int i;
1111 Pzpart_t* po;
1112
1113 if (pz->major > 1)
1114 {
1115 if (!(i = sfgetc(pz->io)))
1116 return 0;
1117 if (i == EOF)
1118 return -1;
1119 sfungetc(pz->io, i);
1120 }
1121 if (!(pp = vmnewof(pz->vm, 0, Pzpart_t, 1, 0)))
1122 return pznospace(pz);
1123 if (pz->major == 1)
1124 {
1125 pp->row = sfgetu(pz->io);
1126 pp->col = sfgetu(pz->io);
1127 pz->win = sfgetu(pz->io);
1128 }
1129 po = 0;
1130 for (;;)
1131 {
1132 switch (i = sfgetc(pz->io))
1133 {
1134 case EOF:
1135 goto bad;
1136 case 0:
1137 if (!po && pzpartinit(pz, pp, NiL))
1138 return -1;
1139 break;
1140 case PZ_HDR_comment:
1141 buffer(pz, pp, (char**)&pz->disc->comment, NiL);
1142 continue;
1143 case PZ_HDR_fix:
1144 if (array(pz, pp, &pp->fix, &pp->nfix, pp->row))
1145 goto bad;
1146 if (!pp->value)
1147 {
1148 if (!(pp->value = vmnewof(pz->vm, 0, int, pp->row, 0)))
1149 return pznospace(pz);
1150 for (i = 0; i < pp->row; i++)
1151 pp->value[i] = -1;
1152 }
1153 for (i = 0; i < pp->nfix; i++)
1154 if (pp->value[pp->fix[i]] < 0)
1155 pp->value[pp->fix[i]] = ' ';
1156 continue;
1157 case PZ_HDR_grp:
1158 if (array(pz, pp, &pp->grp, &pp->ngrp, pp->row + 1))
1159 goto bad;
1160 continue;
1161 case PZ_HDR_map:
1162 if (array(pz, pp, &pp->map, &pp->nmap, pp->row))
1163 goto bad;
1164 continue;
1165 case PZ_HDR_options:
1166 buffer(pz, pp, (char**)&pz->headoptions, NiL);
1167 continue;
1168 case PZ_HDR_prefix:
1169 buffer(pz, pp, &pz->prefix.data, &pz->prefix.count);
1170 pz->prefix.terminator = -1;
1171 continue;
1172 case PZ_HDR_part:
1173 if (pp->row)
1174 {
1175 if (!po && pzpartinit(pz, pp, NiL))
1176 return -1;
1177 if (pp = pz->freepart)
1178 pz->freepart = 0;
1179 else if (!(pp = vmnewof(pz->vm, 0, Pzpart_t, 1, 0)))
1180 return pznospace(pz);
1181 }
1182 buffer(pz, pp, (char**)&pp->name, NiL);
1183 pp->row = sfgetu(pz->io);
1184 pp->col = sfgetu(pz->io);
1185 if (pz->partdict && (po = (Pzpart_t*)dtsearch(pz->partdict, pp)) || (po = pz->mainpart) && streq(pp->name, po->name))
1186 {
1187 if (pp->row != po->row || pp->col != po->col)
1188 {
1189 if (pz->disc->errorf)
1190 (*pz->disc->errorf)(pz, pz->disc, 1, "%s: %s: partition redefinition ignored", pz->path, pp->name);
1191 }
1192 else if (pz->flags & PZ_DUMP)
1193 sfprintf(sfstderr, "\n# %s benign redefinition\n", pp->name);
1194 vmfree(pz->vm, pp->name);
1195 pz->freepart = pp;
1196 pp->name = 0;
1197 pp = po;
1198 for (;;)
1199 {
1200 switch (i = sfgetc(pz->io))
1201 {
1202 case EOF:
1203 break;
1204 case 0:
1205 case PZ_HDR_part:
1206 sfungetc(pz->io, i);
1207 break;
1208 default:
1209 if (PZ_HDR_ARR(i))
1210 array(pz, pp, NiL, NiL, 0);
1211 else if (PZ_HDR_BUF(i))
1212 buffer(pz, pp, NiL, NiL);
1213 else
1214 goto bad;
1215 continue;
1216 }
1217 break;
1218 }
1219 }
1220 else
1221 po = 0;
1222 continue;
1223 case PZ_HDR_split:
1224 array(pz, pp, &pz->split.data, &pz->split.size, 0);
1225 pz->split.flags |= PZ_SPLIT_INFLATE;
1226 pz->flags |= PZ_SECTION;
1227 continue;
1228 default:
1229 if (PZ_HDR_ARR(i))
1230 array(pz, pp, NiL, NiL, 0);
1231 else if (PZ_HDR_BUF(i))
1232 buffer(pz, pp, NiL, NiL);
1233 else
1234 goto bad;
1235 continue;
1236 }
1237 break;
1238 }
1239 return 0;
1240 bad:
1241 if (pz->disc->errorf)
1242 (*pz->disc->errorf)(pz, pz->disc, 2, "%s: partition header corrupted", pz->path);
1243 return -1;
1244 }
1245
1246 /*
1247 * write any new pz partition headers to op
1248 */
1249
1250 int
pzpartwrite(Pz_t * pz,Sfio_t * op)1251 pzpartwrite(Pz_t* pz, Sfio_t* op)
1252 {
1253 register Pzpart_t* pp;
1254 register int i;
1255 register size_t m;
1256 int all;
1257
1258 if (pz->flags & PZ_MAINONLY)
1259 {
1260 pz->flags &= ~PZ_MAINONLY;
1261 all = 0;
1262 pp = pz->mainpart;
1263 }
1264 else if (pz->partdict)
1265 {
1266 all = 1;
1267 pp = (Pzpart_t*)dtfirst(pz->partdict);
1268 }
1269 else
1270 {
1271 all = 0;
1272 pp = pz->part;
1273 }
1274 while (pp)
1275 {
1276 if ((pp->flags & (PZ_UPDATE|PZ_HEAD)) == PZ_UPDATE)
1277 {
1278 pp->flags |= PZ_HEAD;
1279 sfputc(op, PZ_HDR_part);
1280 m = strlen(pp->name) + 1;
1281 sfputu(op, m);
1282 sfwrite(op, pp->name, m);
1283 sfputu(op, pp->row);
1284 sfputu(op, pp->col);
1285 if (pp->nmap != pp->row || pp->ngrp != 1)
1286 {
1287 sfputc(op, PZ_HDR_map);
1288 sfputu(op, pp->nmap);
1289 for (i = 0; i < pp->nmap; i++)
1290 sfputu(op, pp->map[i]);
1291 sfputc(op, PZ_HDR_grp);
1292 sfputu(op, pp->ngrp);
1293 for (i = 0; i < pp->ngrp; i++)
1294 sfputu(op, pp->grp[i]);
1295 }
1296 if (pp->nfix)
1297 {
1298 sfputc(op, PZ_HDR_fix);
1299 sfputu(op, pp->nfix);
1300 for (i = 0; i < pp->nfix; i++)
1301 sfputu(op, pp->fix[i]);
1302 }
1303 if ((pz->split.flags & (PZ_SPLIT_DEFLATE|PZ_SPLIT_HEADER)) == PZ_SPLIT_DEFLATE)
1304 {
1305 pz->split.flags |= PZ_SPLIT_HEADER;
1306 sfputc(op, PZ_HDR_split);
1307 sfputu(op, 0);
1308 }
1309 }
1310 if (!all)
1311 break;
1312 pp = (Pzpart_t*)dtnext(pz->partdict, pp);
1313 }
1314 sfputc(op, 0);
1315 return 0;
1316 }
1317
1318 /*
1319 * pretty print pp on op
1320 */
1321
1322 int
pzpartprint(Pz_t * pz,register Pzpart_t * pp,register Sfio_t * op)1323 pzpartprint(Pz_t* pz, register Pzpart_t* pp, register Sfio_t* op)
1324 {
1325 register int i;
1326 register int j;
1327 register int g;
1328 register char* s;
1329 char esc[2];
1330
1331 sfprintf(op, "\n\"%s\"\n", pp->name);
1332 sfprintf(op, "\n%I*u\t# high frequency %I*u\n", sizeof(pp->row), pp->row, sizeof(pp->nmap), pp->nmap);
1333 if (pp->nfix)
1334 {
1335 sfprintf(op, "\n");
1336 esc[1] = 0;
1337 for (i = 0; i < pp->nfix; i++)
1338 {
1339 for (j = i + 1; j < pp->nfix && pp->fix[j] == pp->fix[j - 1] + 1 && pp->value[pp->fix[j]] == pp->value[pp->fix[j - 1]]; j++);
1340 sfprintf(op, "%I*u", sizeof(pp->fix[i]), pp->fix[i]);
1341 if (j > (i + 2))
1342 {
1343 i = j - 1;
1344 sfprintf(op, "-%I*u", sizeof(pp->fix[i]), pp->fix[i]);
1345 }
1346 s = fmtesc((esc[0] = pp->value[pp->fix[i]], esc));
1347 j = *s == '\'' ? '"' : '\'';
1348 sfprintf(op, "=%c%s%c\n", j, s, j);
1349 }
1350 }
1351 g = -1;
1352 for (i = 0; i < pp->nmap; i++)
1353 {
1354 if (g != pp->lab[i])
1355 {
1356 g = pp->lab[i];
1357 sfprintf(op, "\n");
1358 }
1359 else
1360 sfprintf(op, " ");
1361 for (j = i + 1; j < pp->nmap && pp->map[j] == pp->map[j - 1] + 1 && pp->lab[j] == g; j++);
1362 sfprintf(op, "%I*u", sizeof(pp->map[i]), pp->map[i]);
1363 if (j > (i + 2))
1364 {
1365 i = j - 1;
1366 sfprintf(op, "-%I*u", sizeof(pp->map[i]), pp->map[i]);
1367 }
1368 }
1369 sfprintf(op, "\n");
1370 return sferror(op) ? -1 : 0;
1371 }
1372