|
|
1.1 root 1: /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */
2: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */
3: /* The copyright notice does not imply actual or intended publication. */
4: /* AUTHORS: */
5: /* H. S. Baird - ATT-BL MH - first versions */
6:
7: /* Text.c - functions for Document-image file ("dim" file) handling
8:
9: General Introduction
10: --------------------
11:
12: Dim files describe a document as a collection of records of these types:
13: Page full page
14: Block block (often a column) of text
15: Txtln line of text
16: Word word
17: Char character, isolated symbol, `graph'
18: Interp interpretation of a character (result of classification)
19: Sfeats scalar features of a character
20: Shapes local shape features of a character
21: Bfeats binary indicator features of a character
22: Blob connected component (maximal subset of 8-connected black pixels)
23: Lag line-adjacency graph of runs
24: Run horizontal run of black pixels
25: Pixel bilevel (black/white) picture element (symbols are expected to
26: be black against a white background); usually square
27:
28: They may be organized hierarchically --
29: a Page may own : Blocks, Txtlns, Words, Chars, & Blobs
30: a Block may own : Blocks, Txtlns, Words, Chars, & Blobs
31: a Txtln may own : Txtlns, Words, Chars, & Blobs
32: a Word may own : Words, Chars & Blobs
33: a Char may own : Blobs, Interps, Sfeats, Shapes, & Bfeats
34: a Blob may own : Runs (variously represented)
35: a Run owns : black Pixels
36: Note that the hierarchy is strict except that Blocks, Txtlns, & Words may
37: own records of their own type. This serves several functions:
38: -- a Block may own other Blocks, conventionally nested within it, to
39: represent a physical or logical page layout decomposition;
40: -- a Txtln may have alternative interpretations & segmentations into Words;
41: -- a Word may have alternative segmentations into Chars.
42:
43: For each record type R, there should exist these data-structures:
44: R struct
45: Init_R #define'd initialization string
46: empty_R an extern ``empty'' (initialized) instance of R
47: Also there are library functions (in which _R is spelled in lower-case):
48: R *alloc_R() allocate memory and initialize to ``empty''
49: free_R(R *) free memory (only of record R, not what it owns)
50: free_R_etc(R *,ids) free R and what it owns (as specified by `ids')
51: R *dup_R(R *) return distinct copy, with duplicated contents
52: R *dup_R_etc(R *,ids) return distinct copy, duplicated contents & parts
53: char *R_toa(R *) convert to printable ASCII string
54: frdb_R(FILE *, R *) fread R (binary) from file thru pointer
55: frdb_R_etc(",",ids) fread R (binary) and what it owns (as specified)
56: fwrb_R(FILE *, R *) fwrite R (binary) to file thru pointer
57: fwrb_R_etc(",",ids) fwrite R (binary) and what it owns (as specified)
58: (some of these may be unimplemented if they haven't yet been needed)
59:
60: I/O conventions:
61: -- frd?_... return one of:
62: 1 normal & successful
63: 0 EOF
64: <0 I/O errors
65: Quite a few functions don't obey this rule yet.
66: Many intermediate fns that don't directly perform I/O
67: don't bother passing back status from fns they call.
68: Those that perform I/O directly often complain to stderr and exit(2).
69: The situation is fairly chaotic, and has already caused bugs.
70:
71: Generally:
72: -- An `etc' argument is a set of Ident bits specifying a set of record types;
73: it is passed along unchanged in calls to other _etc functions.
74: -- `fwrb_R_etc' fns obey the `etc' instructions carefully, writing only those
75: record types specified
76: -- `frdb_R_etc' fns mostly ignore `etc', blindly reading everything they
77: see (since they aren't clever enough to skip past yet); however, the
78: Blob-reading fns look at the Runs_?? bits to select a main memory
79: format for Runs
80: -- `frdb_R_etc' uses alloc_Y to allocate all new Y
81: -- `fwrb_R_etc', however, does NOT free anything: this must be done explicitly
82: afterwards.
83:
84: Ownership of a set of records is implemented by two fields in the owner record:
85: (1) a count of the number of members, and (2) either a ``set'' or a ``list''
86: pointer:
87: set: to a NULL-terminated array of pointers to records
88: list: to the first in a singly-linked, NULL-terminated, chain
89: sets are used for sets of Blocks, Txtlns, Words, Chars, and Blobs
90: lists are used for Interpl, and for Blobs owned by Chars, since they tend
91: to be fewer
92:
93: Blobs and Runs are treated more elaborately than other records. Blobs are
94: collected in lists when owned by Chars, but in sets otherwise --
95: the motivation was that the Char lists are usually very short, and the malloc
96: overhead of creating them might be unpleasant -- however, maintaining two
97: kinds of sets has caused other headaches; it might be good someday to
98: abolish lists in favor of sets throughout.
99: Runs can often be compressed to about half the usual size by using char
100: fields instead of shorts, and this is done automatically when writing to files. There is both a set and a list form of Run.
101:
102: The peripheral file format is:
103: - deliberately decoupled from the internal (main memory) format: i.e.
104: the main memory structs can be (and are) changed frequently for
105: purposes of experimentation without forcing frequent reformatting
106: of the (by now large) backlog of archived files (particularly the
107: character image databases). To bring such files up-to-date, the program
108: `renew' should be used: it must be edited to reflect changes since
109: the last overhaul of the file format.
110: - designed to be ``scannable'': that is, one can skip rapidly from record
111: to record (using the Ident headers) without minding the hierarchy.
112: This is most useful for the graphics editor "met", where it permits
113: quick response at the outset. It is also used widely in the
114: off-line training programs, where main memory is at a premium.
115: - machine-independent: floating-point representations are forced to
116: fixed point and scaled to integer; all integer representations are
117: written as a sequence of bytes in a fixed order, via putc()/getc().
118: fwrite()/fread() are never used for binary I/O. This seems to work
119: on virtually all UNIX machines. See fioi.h.
120:
121: CCITT Group 4 encodings have been implemented and are available
122: as a peripheral file format for Blobs. They offer a large compression
123: factor (x8) over RunF and RunFS records, and the CPU overhead is not
124: excessive. It turns out that the connectivity information represented
125: explicitly in Run records but lost in ccitt-g4 can be recovered in linear
126: time and space (see fix_lag()); in practice the extra recovery time is
127: negligible and the extra space is 0. This is possible because Blobs are
128: known to be connected: if not, then (I suspect that) superlinear time is
129: required in general to recover the lag.
130:
131: */
132:
133: #include <stdio.h>
134: #include <math.h>
135: #define LIBC_INCL 1
136: #include "CPU.h"
137: #include "stdocr.h"
138: #include "rle.h"
139: #include "Text.h"
140: #include "bitio.h"
141: #include "CCITT.h"
142:
143: long fseek(),lseek();
144:
145: #define dbg_fwrb T /* failsafe consistency checking */
146: #define dbg_frdb T /* failsafe consistency checking */
147: #define dbg_fwrb_runs F /* announce no. bytes used to write each Blob's Runs */
148: #define dbg_frdb_runs F /* announce no. bytes used to write each Blob's Runs */
149:
150: /* return ASCII string describing ident bits */
151: char *ident_toa(id)
152: Ident id;
153: { static char s[80];
154: s[0]='\0';
155: if((id&IsALL)==IsALL) strcat(s,"ALL");
156: else {
157: if(id&IsPage) {
158: strcat(s,"PG");
159: if(id&(Page_label)) {
160: strcat(s,".");
161: if(id&Page_label) strcat(s,"l");
162: };
163: }
164: if(id&IsBlock) {
165: strcat(s,"BK");
166: if(id&(Block_wst|Block_label)) {
167: strcat(s,".");
168: if(id&Block_wst) strcat(s,"w");
169: if(id&Block_label) strcat(s,"l");
170: };
171: };
172: if(id&IsTxtln) {
173: strcat(s,"TL");
174: if(id&(Txtln_basl|Txtln_size|Txtln_label)) {
175: strcat(s,".");
176: if(id&Txtln_basl) strcat(s,"b");
177: if(id&Txtln_size) strcat(s,"s");
178: if(id&Txtln_label) strcat(s,"l");
179: };
180: };
181: if(id&IsWord) {
182: strcat(s,"WD");
183: if(id&(Word_spelled|Word_label)) {
184: strcat(s,".");
185: if(id&Word_spelled) strcat(s,"s");
186: if(id&Word_label) strcat(s,"l");
187: };
188: };
189: if(id&IsWordInterp) {
190: strcat(s,"WI");
191: if(id&(Word_spelled|Word_numeric|Word_initcap|Word_allcaps|Word_hyphens|Word_slashes|Word_termhyp|Word_endsent)) {
192: strcat(s,".");
193: if(id&Word_spelled) strcat(s,"s");
194: if(id&Word_numeric) strcat(s,"n");
195: if(id&Word_initcap) strcat(s,"i");
196: if(id&Word_allcaps) strcat(s,"a");
197: if(id&Word_hyphens) strcat(s,"-");
198: if(id&Word_slashes) strcat(s,"/");
199: if(id&Word_termhyp) strcat(s,"h");
200: if(id&Word_endsent) strcat(s,".");
201: };
202: };
203: if(id&IsChar) {
204: strcat(s,"CH");
205: if(id&(Char_spelled|Char_confused|Char_termhyp|Char_omit|Char_label|Char_ranparms)) {
206: strcat(s,".");
207: if(id&Char_spelled) strcat(s,"s");
208: if(id&Char_confused) strcat(s,"c");
209: if(id&Char_termhyp) strcat(s,"h");
210: if(id&Char_omit) strcat(s,"o");
211: if(id&Char_label) strcat(s,"l");
212: if(id&Char_ranparms) strcat(s,"r");
213: if(id&Char_split) strcat(s,"S");
214: if(id&Char_merged) strcat(s,"M");
215: };
216: };
217: if(id&IsInterp) {
218: strcat(s,"IN");
219: if(id&Interp_spelled) {
220: strcat(s,".s");
221: };
222: };
223: if(id&IsBlob) {
224: strcat(s,"BB");
225: if( id&(Blob_lm|Blob_rm|Blob_tm|Blob_bm
226: |Blob_chopt|Blob_chopb|Blob_chopl|Blob_chopr
227: |Blob_small|Blob_local)
228: ) {
229: strcat(s,".");
230: if(id&(Blob_tm|Blob_bm|Blob_lm|Blob_rm)) {
231: if(id&Blob_lm) strcat(s,"l");
232: if(id&Blob_rm) strcat(s,"r");
233: if(id&Blob_tm) strcat(s,"t");
234: if(id&Blob_bm) strcat(s,"b");
235: };
236: if(id&(Blob_chopt|Blob_chopb|Blob_chopl|Blob_chopr)) {
237: if(id&Blob_chopl) strcat(s,"L");
238: if(id&Blob_chopr) strcat(s,"R");
239: if(id&Blob_chopt) strcat(s,"T");
240: if(id&Blob_chopb) strcat(s,"B");
241: };
242: if(id&Blob_small) strcat(s,"s");
243: if(id&Blob_local) strcat(s,"o");
244: };
245: }
246: };
247: return(s);
248: }
249:
250: /* convert a conventional character-code to a record type */
251: Ident cto_ident(c)
252: char c;
253: { Ident type;
254: switch(c) {
255: case 'b':
256: type=IsBlob; break;
257: case 'B': case 'k':
258: type=IsBlock; break;
259: case 'c':
260: type=IsChar; break;
261: case 'i':
262: type=IsInterp; break;
263: case 'p': case 'P':
264: type=IsPage; break;
265: case 'r':
266: type=IsRun; break;
267: case 't': case 'l':
268: type=IsTxtln; break;
269: case 'w':
270: type=IsWord; break;
271: case 'y':
272: type=IsBdy; break;
273: };
274: return(type);
275: }
276:
277: Ident cto_flag(c,type)
278: char c;
279: Ident type;
280: { Ident flag;
281: flag = IsNONE;
282: if(type&IsPage) {
283: switch(c) {
284: case 'l': flag |= Page_label; break;
285: };
286: }
287: else if(type&IsBlock) {
288: switch(c) {
289: case 'w': flag |= Block_wst; break;
290: case 'l': flag |= Block_label; break;
291: };
292: }
293: else if(type&IsTxtln) {
294: switch(c) {
295: case 'b': flag |= Txtln_basl; break;
296: case 's': flag |= Txtln_size; break;
297: case 'l': flag |= Txtln_label; break;
298: };
299: }
300: else if(type&IsWord) {
301: switch(c) {
302: case 's': flag |= Word_spelled; break;
303: case 'n': flag |= Word_numeric; break;
304: case 'i': flag |= Word_initcap; break;
305: case 'a': flag |= Word_allcaps; break;
306: case '-': flag |= Word_hyphens; break;
307: case '/': flag |= Word_slashes; break;
308: case 'h': flag |= Word_termhyp; break;
309: case '.': flag |= Word_endsent; break;
310: case 'l': flag |= Word_label; break;
311: };
312: }
313: else if(type&IsChar) {
314: switch(c) {
315: case 's': flag |= Char_spelled; break;
316: case 'c': flag |= Char_confused; break;
317: case 'h': flag |= Char_termhyp; break;
318: case 'o': flag |= Char_omit; break;
319: case 'l': flag |= Char_label; break;
320: case 'r': flag |= Char_ranparms; break;
321: case 'S': flag |= Char_split; break;
322: case 'M': flag |= Char_merged; break;
323: };
324: }
325: else if(type&IsBlob) {
326: switch(c) {
327: case 'B': flag |= Blob_chopb; break;
328: case 'L': flag |= Blob_chopl; break;
329: case 'R': flag |= Blob_chopr; break;
330: case 'T': flag |= Blob_chopt; break;
331: case 'b': flag |= Blob_bm; break;
332: case 'l': flag |= Blob_lm; break;
333: case 'o': flag |= Blob_local; break;
334: case 'r': flag |= Blob_rm; break;
335: case 's': flag |= Blob_small; break;
336: case 't': flag |= Blob_tm; break;
337: };
338: }
339: else if(type&IsInterp) {
340: switch(c) {
341: case 's': flag |= Interp_spelled; break;
342: };
343: };
344: return(flag);
345: }
346:
347: #if FRDI
348: /* read only the Ident of the next record; if EOF, return 0 */
349: Ident frdb_ident(fp)
350: FILE *fp;
351: { Ident ident;
352: ident = frdi_Ident(fp);
353: #if dbg_frdb_toa
354: err("frdb_ident: %s",ident_toa(ident));
355: #endif
356: if(feof(fp)) return(0);
357: else return(ident);
358: }
359: #else
360: /* read only the Ident of the next record; return 0 iff EOF */
361: Ident frdb_ident(fp)
362: FILE *fp;
363: { Ident ident;
364: int stat;
365: if((stat=fread(&ident,sizeof(Ident),1,fp))!=1) {
366: if(stat==0) return(0);
367: else abort("frdb_ident: can't fread, status %d",stat);
368: };
369: if( Readvax ) ident = swapintin(ident);
370: #if dbg_frdb_toa
371: err("frdb_ident: %s",ident_toa(ident));
372: #endif
373: if(feof(fp)) return(0);
374: else return(ident);
375: }
376: #endif
377:
378: #if FRDI
379: /* read label into malloc space */
380: char *frdb_label(f)
381: FILE *f;
382: { register char *res;
383: res=frdi_str(f);
384: #if dbg_frdb_toa
385: err("frdb_label: \"%s\"",res);
386: #endif
387: return(res);
388: }
389: #else
390: /* read label into malloc space */
391: char *frdb_label(fp)
392: FILE *fp;
393: { static char s[MAX_LABEL_LEN];
394: char *c,*ce,*l;
395: int ch;
396: ce=(c=s)+MAX_LABEL_LEN-1;
397: while((c<ce)&&((ch=getc(fp))!=EOF)&&(ch!='\0')) *(c++) = ch;
398: *c='\0';
399: if(c==ce) {
400: /* label is truncated; find end of it */
401: while(((ch=getc(fp))!=EOF)&&(ch!='\0')) ;
402: };
403: if((l=strdup(s))==NULL)
404: abort("frdb_label: can't dup char *s[%d]",strlen(s));
405: #if dbg_frdb_toa
406: err("frdb_label: \"%s\"",l);
407: #endif
408: return(l);
409: }
410: #endif
411:
412: /* skip label */
413: fskb_label(fp)
414: FILE *fp;
415: { int ch;
416: while(((ch=getc(fp))!=EOF)&&(ch!='\0')&&(ch!='\n')) ;
417: if(ch==EOF) return(0); else return(1);
418: }
419:
420: /* Skip the REST of this record (the Ident is assumed to have been read),
421: and return the Ident of the next record in the file;
422: else return:
423: 0 EOF
424: -1 I/O error
425: -2 not one of: Page, Block, Txtln, Char, Interp
426: */
427: char *pp_toa(ppp)
428: Pp *ppp;
429: { static char s[30];
430: sprintf(s,"(%0.2f,%0.2f)",ppp->x,ppp->y);
431: return(s);
432: }
433:
434: /* return integer string in the range 00-99 */
435: char *merit_toa(m)
436: Merit m;
437: { static char s[3];
438: int im;
439: im = (int)(m * 100);
440: if(im>99) im=99; else if(im<0) im=0;
441: if(im<10) {
442: s[0] = '0';
443: sprintf(s+1,"%d",im);
444: }
445: else sprintf(s,"%2d",im);
446: s[3] = '\0';
447: return(s);
448: }
449:
450: char *pts_toa(p)
451: Pts p;
452: { static char s[10];
453: sprintf(s,"%g",((int)((p*10.0)+0.5))/10.0);
454: return(s);
455: }
456:
457: Bdy *alloc_bdy()
458: { Bdy *p;
459: if((p=(Bdy *)malloc(sizeof(Bdy)))==NULL)
460: abort("alloc_bdy: can't malloc");
461: else { *p = empty_Bdy;
462: return(p);
463: };
464: }
465:
466: Bdys *alloc_bdys()
467: { Bdys *p;
468: if((p=(Bdys *)malloc(sizeof(Bdys)))==NULL)
469: abort("alloc_bdys: can't malloc");
470: else { *p = empty_Bdys;
471: return(p);
472: };
473: }
474:
475: char *bdyedge_toa(bep)
476: BdyEdge *bep;
477: { static char s[80];
478: char aps[20];
479: strcpy(aps,sp_toa(bep->ap));
480: sprintf(s,"%s,%s p%d c%s a%0.2f",
481: aps, sp_toa(bep->bp),
482: bep->per,
483: pp_toa(&(bep->ctr)),
484: (bep->ang/PI)*180.0);
485: return(s);
486: }
487:
488: free_bdyedges(besp)
489: BdyEdges *besp;
490: { register BdyEdge *bep,**bepp;
491: if(besp->pa!=NULL) {
492: if(besp->mny>0) {
493: for(bep= *(bepp=besp->pa); bep!=NULL; bep= *(++bepp))
494: free(bep);
495: };
496: free(besp->pa);
497: };
498: *besp = empty_BdyEdges;
499: }
500:
501: /* Skip past the "TYPE=document-image\n\n" (or "TYPE=dim\n\n") ASCII header from
502: file *fp, read and check the Doc record, and, if all's well, return 1.
503: If an immediate EOF, return 0. If not EOF, and no "TYPE=" header,
504: leave fp as it was, and return -1. If a malformed "TYPE=" header, leave fp
505: as it was, and return -2. */
506: int skip_type(fp)
507: FILE *fp;
508: { int ich,stat;
509: long seek;
510: #define MAX_TYPE_HDR_LEN (100)
511: char type_eq[MAX_TYPE_HDR_LEN+1];
512: register char *pcp,*ccp,*ecp;
513: int version;
514:
515: seek = ftell(fp);
516: /* test for EOF */
517: if(feof(fp) || (ich=getc(fp))==EOF)
518: /* premature EOF*/ return(0);
519: if((type_eq[0]=ich)!='T') {
520: /* no "TYPE=" header */
521: ungetc(ich,fp); /* fast, guaranteed push-back */
522: return(-1);
523: };
524: /* try to read the rest of "TYPE=" */
525: for(ecp=(ccp=type_eq+1)+4; ccp<ecp; ccp++) {
526: if(feof(fp) || (ich=getc(fp))==EOF) {
527: /* no "TYPE=" header */
528: fseek(fp,seek,0);
529: return(-1);
530: }
531: else *ccp=ich;
532: }
533: *ccp='\0';
534: /* check for "TYPE=" so far */
535: if(strcmp(type_eq,"TYPE=")==0) {
536: /* read rest of ASCII header */
537: ccp=(pcp=type_eq+3)+1; ecp=type_eq+MAX_TYPE_HDR_LEN;
538: do { ccp++; pcp++;
539: if((ich=getc(fp))==EOF) {
540: /* malformed "TYPE=" header */
541: fseek(fp,seek,0);
542: return(-2);
543: }
544: else *ccp=ich;
545: }
546: while(ccp<ecp && (*ccp!='\n'||*pcp!='\n'));
547: if(ccp==ecp) {
548: /* malformed "TYPE=" header */
549: fseek(fp,seek,0);
550: return(-2);
551: };
552: *pcp='\0';
553: /* check that it is "TYPE=document-image\n\n" or "TYPE=dim\n\n" */
554: if(strcmp(type_eq,"TYPE=document-image")!=0
555: && strcmp(type_eq,"TYPE=dim")!=0) {
556: /* malformed "TYPE=" header */
557: fseek(fp,seek,0);
558: return(-2);
559: };
560: #if dbg_frdb_toa
561: err("skip_type: \"%s\\n\\n\"",type_eq);
562: #endif
563: return(1); /* normal and successful TYPE= header */
564: }
565: else { /* no "TYPE=" header */
566: fseek(fp,seek,0);
567: return(-1);
568: };
569: }
570:
571: Doc *alloc_doc()
572: { Doc *p;
573: if((p=(Doc *)malloc(sizeof(Doc)))==NULL)
574: abort("alloc_doc: can't malloc");
575: else { *p = empty_Doc;
576: return(p);
577: };
578: }
579:
580: char *doc_toa(p)
581: Doc *p;
582: { static char s[80];
583: sprintf(s,"Doc v%d p%d l%s",
584: p->version,
585: p->ps.mny,
586: (p->l!=NULL)? p->l: "");
587: return(s);
588: }
589:
590: #if FWRI
591: /* write the given doc (record only) */
592: fwrb_doc(f,p)
593: FILE *f;
594: Doc *p;
595: { int stat;
596: fwri_uint1(f,p->version);
597: fwri_uint2(f,p->ps.mny);
598: #if dbg_fwrb_toa
599: err("fwrb_doc: %s",doc_toa(p));
600: #endif
601: if(p->l!=NULL) {
602: fwri_ch(f,'l');
603: fwrb_label(f,p->l);
604: }
605: else fwri_ch(f,'\0');
606: }
607: #else
608: fwrb_doc(f,p)
609: FILE *f;
610: Doc *p;
611: {}
612: #endif
613:
614: #if FRDI
615: /* read a Doc record (only) - it must be next in the file;
616: don't immediately read its parts; return 0 iff immediate EOF.
617: Check for correct version no: if fails, abort. */
618: int frdb_doc(f,p)
619: FILE *f;
620: Doc *p;
621: { char qlabel;
622: *p = empty_Doc;
623: if(feof(f))
624: return(0);
625: p->version=frdi_uint1(f);
626: p->ps.mny=frdi_uint2(f);
627: if((qlabel=frdi_ch(f))=='l')
628: p->l=frdb_label(f);
629: #if dbg_frdb_toa
630: err("frdb_doc: %s",doc_toa(p));
631: #endif
632: if(ferror(f)) return(-errno); else return(1);
633: }
634: #else
635: int frdb_doc(f,p)
636: FILE *f;
637: Doc *p;
638: { return(1);
639: }
640: #endif
641:
642: #if FWRI
643: /* Write the initial Doc record */
644: put_doc(f)
645: FILE *f;
646: { Doc doc;
647: doc = empty_Doc;
648: doc.version = DIM_VERSION;
649: doc.ps.mny = 1;
650: fwrb_doc(f,&doc);
651: }
652: #else
653: put_doc(f)
654: FILE *f;
655: {}
656: #endif
657:
658: #if FRDI
659: /* read, check, discard, and skip past the Doc record */
660: int skip_doc(f)
661: FILE *f;
662: { Doc doc;
663: frdb_doc(f,&doc);
664: if(doc.version!=DIM_VERSION)
665: abort("skip_doc: version %d != DIM_VERSION %d",
666: doc.version,DIM_VERSION);
667: if(doc.l!=NULL) free(doc.l);
668: return(1);
669: }
670: #else
671: int skip_doc(f)
672: FILE *f;
673: { Doc doc;
674: return(1);
675: }
676: #endif
677:
678: Page *alloc_page()
679: { Page *p;
680: if((p=(Page *)malloc(sizeof(Page)))==NULL)
681: abort("alloc_page: can't malloc");
682: alloc_census(Page,1);
683: *p = empty_Page;
684: return(p);
685: }
686:
687: char *page_toa(p)
688: Page *p;
689: { static char s[80];
690: sprintf(s,"%s bx%s res%d,%d sk%0.2f,sh%0.2f bk%d l%d c%d b%d",
691: ident_toa(p->ident),
692: bbx_toa(&(p->bx)),
693: p->res_x,p->res_y,
694: (p->skew/PI)*180.0,
695: (p->shear/PI)*180.0,
696: p->bks.mny,p->ls.mny,p->cs.mny,p->bs.mny,
697: (p->l!=NULL)? p->l: "");
698: return(s);
699: }
700:
701: #if FWRI
702: /* write the given page (record only) */
703: fwrb_page(f,p)
704: FILE *f;
705: Page *p;
706: { int stat;
707: #if dbg_fwrb
708: if(f==stdout||f==stderr||ftell(f)<=0L) {
709: fprintf(f,"TYPE=dim\n\n");
710: #if dbg_fwrb_toa
711: err("fwrb_page: \"TYPE=dim\\n\\n\"");
712: #endif
713: put_doc(f);
714: };
715: if((!(p->ident&IsPage))||(p->ident&(IsALL&(~IsPage))))
716: err("fwrb_page: %s",page_toa(p));
717: if(p->ident&Page_label && p->l==NULL) {
718: err("fwrb_page: Page_label set but .l==NULL");
719: p->ident &= ~Page_label;
720: };
721: #endif
722: fwri_Ident(f,p->ident);
723: fwri_Bbx(f,&(p->bx));
724: fwri_int2(f,p->res_x);
725: fwri_int2(f,p->res_y);
726: fwri_Radians(f,p->skew);
727: fwri_Radians(f,p->shear);
728: fwri_uint2(f,p->bks.mny);
729: fwri_uint2(f,p->ls.mny);
730: fwri_uint2(f,p->ws.mny);
731: fwri_uint2(f,p->cs.mny);
732: fwri_uint3(f,p->bs.mny);
733: #if dbg_fwrb_toa
734: err("fwrb_page: %s",page_toa(p));
735: #endif
736: if(p->ident&Page_label) fwrb_label(f,p->l);
737: }
738: #else
739: /* write the given page (record only) */
740: fwrb_page(fp,pp)
741: FILE *fp;
742: Page *pp;
743: { PageF pf;
744: int stat;
745: #if dbg_fwrb
746: if((!(pp->ident&IsPage))||(pp->ident&(IsALL&(~IsPage))))
747: err("fwrb_page: %s",page_toa(pp));
748: #endif
749: memset(&pf,'\0',sizeof(pf));
750: pf.ident = pp->ident;
751: pf.res_x=pp->res_x;
752: pf.res_y=pp->res_y;
753: pf.bx=pp->bx;
754: pf.skew=pp->skew;
755: pf.shear=pp->shear;
756: pf.bkmny=pp->bks.mny;
757: pf.lmny=pp->ls.mny;
758: pf.wmny=pp->ws.mny;
759: pf.cmny=pp->cs.mny;
760: pf.bmny=pp->bs.mny;
761: if(fp==stdout||fp==stderr||ftell(fp)<=0L) {
762: fprintf(fp,"TYPE=document-image\n\n");
763: #if dbg_fwrb_toa
764: err("fwrb_page: \"TYPE=document-image\\n\\n\"");
765: #endif
766: };
767: if((stat=fwrite(&pf,sizeof(PageF),1,fp))!=1)
768: abort("fwrb_page: can't fwrite - status %d",stat);
769: #if dbg_fwrb_toa
770: err("fwrb_page: %s",page_toa(pp));
771: #endif
772: if(pf.ident&Page_label) fwrb_label(fp,pp->l);
773: }
774: #endif
775:
776: /* write a page and its specified parts */
777: fwrb_page_etc(fp,pp,etc)
778: FILE *fp;
779: Page *pp;
780: Ident etc;
781: { static Ident parts = (IsBlock|IsTxtln|IsWord|IsChar|IsBlob);
782: Page pg;
783: if((etc&parts)!=parts) /* write selected parts */ {
784: pg = *pp;
785: if(!(etc&IsBlock)) pg.bks.mny=0;
786: if(!(etc&IsTxtln)) pg.ls.mny=0;
787: if(!(etc&IsWord)) pg.ws.mny=0;
788: if(!(etc&IsChar)) pg.cs.mny=0;
789: if(!(etc&IsBlob)) pg.bs.mny=0;
790: pp = &pg; /* write modified record */
791: };
792: fwrb_page(fp,pp);
793: fwrb_blocks_etc(fp,pp->bks,etc);
794: fwrb_txtlns_etc(fp,pp->ls,etc);
795: fwrb_words_etc(fp,pp->ws,etc);
796: fwrb_chars_etc(fp,pp->cs,etc);
797: fwrb_blobs_etc(fp,pp->bs,etc);
798: }
799:
800: /* write a page and its specified parts, ASCII (INCOMPLETE) */
801: fwra_page_etc(fp,pp,etc)
802: FILE *fp;
803: Page *pp;
804: Ident etc;
805: { static Ident parts = (IsBlock|IsTxtln|IsWord|IsChar|IsBlob);
806: Page pg;
807: if((etc&parts)!=parts) /* write selected parts */ {
808: pg = *pp;
809: if(!(etc&IsBlock)) pg.bks.mny=0;
810: if(!(etc&IsTxtln)) pg.ls.mny=0;
811: if(!(etc&IsWord)) pg.ws.mny=0;
812: if(!(etc&IsChar)) pg.cs.mny=0;
813: if(!(etc&IsBlob)) pg.bs.mny=0;
814: pp = &pg; /* write modified record */
815: };
816: if(etc&IsPage) fwrb_page(fp,pp);
817: fwrb_blocks_etc(fp,pp->bks,etc);
818: fwrb_txtlns_etc(fp,pp->ls,etc);
819: fwrb_words_etc(fp,pp->ws,etc);
820: fwrb_chars_etc(fp,pp->cs,etc);
821: fwrb_blobs_etc(fp,pp->bs,etc);
822: }
823:
824: #if FRDI
825: /* read a Page record (only) - it must be next in the file;
826: don't immediately read its parts; return 0 iff immediate EOF */
827: int frdb_page(f,p)
828: FILE *f;
829: Page *p;
830: { char *pfc; /* for debugging */
831: int stat;
832: switch(skip_type(f)) {
833: case 1: /* "TYPE=" header */
834: skip_doc(f);
835: break;
836: case 0: /* immediate EOF */
837: return(0);
838: break;
839: case -1: /* no "TYPE=" header */
840: break;
841: case -2: /* garbled "TYPE=" header */
842: abort("frdb_page: garbled \"TYPE=\" header");
843: break;
844: };
845: *p = empty_Page;
846: if(feof(f))
847: return(0);
848: p->ident=frdi_Ident(f);
849: frdi_Bbx(f,&(p->bx));
850: p->res_x=frdi_int2(f);
851: p->res_y=frdi_int2(f);
852: p->skew=frdi_Radians(f);
853: p->shear=frdi_Radians(f);
854: p->bks.mny=frdi_uint2(f);
855: p->ls.mny=frdi_uint2(f);
856: p->ws.mny=frdi_uint2(f);
857: p->cs.mny=frdi_uint2(f);
858: p->bs.mny=frdi_uint3(f);
859: #if dbg_frdb
860: if((!(p->ident&IsPage))||(p->ident&(IsALL&(~IsPage))))
861: err("frdb_page: %s",page_toa(p));
862: #endif
863: #if dbg_frdb_toa
864: err("frdb_page: %s",page_toa(p));
865: #endif
866: if(p->ident&Page_label) p->l = frdb_label(f);
867: if(ferror(f)) return(-errno); else return(1);
868: }
869: #else
870: /* read a Page record (only) - it must be next in the file;
871: don't immediately read its parts; return T iff not early EOF */
872: int frdb_page(fp,pp)
873: FILE *fp;
874: Page *pp;
875: { PageF pf;
876: char *pfc; /* for debugging */
877: int stat;
878: if((stat=skip_type(fp))!=1 /* "TYPE=" header */
879: && stat!=-1 /* no "TYPE=" header */ ) {
880: /* premature EOF or error */ return(stat);
881: };
882: if((stat=fread(&pf,sizeof(PageF),1,fp))!=1)
883: /* premature EOF*/ return(stat);
884: pfc = (char *)&pf;
885: *pp = empty_Page;
886: pp->ident=pf.ident;
887: pp->res_x=pf.res_x;
888: pp->res_y=pf.res_y;
889: pp->bx=pf.bx;
890: pp->skew=pf.skew;
891: pp->shear=pf.shear;
892: pp->bks.mny = pf.bkmny; pp->bks.bpa=NULL;
893: pp->ls.mny = pf.lmny; pp->ls.lpa=NULL;
894: pp->ws.mny = pf.wmny; pp->ws.wpa=NULL;
895: pp->cs.mny = pf.cmny; pp->cs.cpa=NULL;
896: pp->bs.mny = pf.bmny; pp->bs.bpa=NULL;
897: #if dbg_frdb_toa
898: err("frdb_page: %s",page_toa(pp));
899: #endif
900: if(pp->ident&Page_label) pp->l = frdb_label(fp);
901: #if dbg_frdb
902: if((!(pp->ident&IsPage))||(pp->ident&(IsALL&(~IsPage))))
903: err("frdb_page: %s",page_toa(pp));
904: #endif
905: return(stat);
906: }
907: #endif
908:
909: /* Read a page and selected parts */
910: int frdb_page_etc(fp,pp,etc)
911: FILE *fp;
912: Page *pp;
913: Ident etc;
914: { int stat;
915: if((etc&IsALL)==IsALL) {
916: long here;
917: /* In order to minimize malloc time to read an often huge file,
918: malloc and then free storage roughly equal to what's needed */
919: if( /* DEFEATED */ F && (here=ftell(fp))>=0 && fseek(fp,0,2)>=0 ) {
920: /* *fp is connected to a file, not a pipe */
921: free(malloc(ftell(fp)));
922: fseek(fp,here,0);
923: };
924: };
925: if((stat=frdb_page(fp,pp))!=1) return(stat);
926: if(etc&IsBlock && pp->bks.mny>0)
927: frdb_blocks_etc(fp,&(pp->bks),etc);
928: else pp->bks = empty_Blocks;
929: if(etc&IsTxtln && pp->ls.mny>0)
930: frdb_txtlns_etc(fp,&(pp->ls),etc);
931: else pp->ls = empty_Txtlns;
932: if(etc&IsWord && pp->ws.mny>0)
933: frdb_words_etc(fp,&(pp->ws),etc);
934: else pp->ws = empty_Words;
935: if(etc&IsChar && pp->cs.mny>0)
936: frdb_chars_etc(fp,&(pp->cs),etc);
937: else pp->cs = empty_Chars;
938: if(etc&IsBlob && pp->bs.mny>0)
939: frdb_blobs_etc(fp,&(pp->bs),etc);
940: else pp->bs = empty_Blobs;
941: return(1/*normal return*/);
942: }
943:
944: free_page_etc(p,etc)
945: Page *p;
946: Ident etc;
947: { free_blocks_etc(&(p->bks),etc);
948: free_txtlns_etc(&(p->ls),etc);
949: free_words_etc(&(p->ws),etc);
950: free_chars_etc(&(p->cs),etc);
951: free_blobs_etc(&(p->bs),etc);
952: if(p->ident&Page_label && p->l!=NULL) {
953: free(p->l); p->l=NULL; p->ident &= ~Page_label;
954: };
955: if(etc&IsPage) {
956: free(p);
957: free_census(Page,1);
958: };
959: }
960:
961: /* return a pointer to a distinct and duplicate copy of record Page *p,
962: created out of malloc space */
963: Page *dup_page(p)
964: Page *p;
965: { Page *dup;
966: dup=alloc_page(); *dup = *p; return(dup);
967: }
968:
969: /* Return a pointer to a distinct and duplicate copy of Page *p, and its parts
970: as specified by `etc', created out of malloc space. */
971: Page *dup_page_etc(p,etc)
972: Page *p;
973: Ident etc;
974: { Page *dup;
975: dup = dup_page(p);
976: if(etc&IsBlob&&dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(p->bs),etc);
977: else dup->bs = empty_Blobs;
978: if(etc&IsChar&&dup->cs.mny>0) dup->cs = *dup_chars_etc(&(p->cs),etc);
979: else dup->cs = empty_Chars;
980: if(etc&IsWord&&dup->ws.mny>0) dup->ws = *dup_words_etc(&(p->ws),etc);
981: else dup->ws = empty_Words;
982: if(etc&IsTxtln&&dup->ls.mny>0) dup->ls = *dup_txtlns_etc(&(p->ls),etc);
983: else dup->ls = empty_Txtlns;
984: if(etc&IsBlock&&dup->bks.mny>0) dup->bks = *dup_blocks_etc(&(p->bks),etc);
985: else dup->bks = empty_Blocks;
986: return(dup);
987: }
988:
989: Block *alloc_block()
990: { Block *p;
991: if((p=(Block *)malloc(sizeof(Block)))==NULL)
992: abort("alloc_block: can't malloc");
993: alloc_census(Block,1);
994: *p = empty_Block;
995: return(p);
996: }
997:
998: char *block_toa(p)
999: Block *p;
1000: { static char s[80];
1001: sprintf(s,"%s bx%s sk%0.2f,sh%0.2f wst%0.2f m%s bk%d l%d w%d c%d b%d",
1002: ident_toa(p->ident),
1003: bbx_toa(&(p->bx)),
1004: p->skew/DtoR,
1005: p->shear/DtoR,
1006: p->wst,
1007: merit_toa(p->m),
1008: p->bks.mny,p->ls.mny,p->ws.mny,p->cs.mny,p->bs.mny,
1009: (p->l!=NULL)? p->l: "");
1010: return(s);
1011: }
1012:
1013: #if FWRI
1014: fwrb_block(f,p)
1015: FILE *f;
1016: Block *p;
1017: { int stat;
1018: #if dbg_fwrb
1019: if((!(p->ident&IsBlock))||(p->ident&(IsALL&(~IsBlock))))
1020: err("fwrb_block: %s",block_toa(p));
1021: if(p->ident&Block_label && p->l==NULL) {
1022: err("fwrb_page: Block_label set but .l==NULL");
1023: p->ident &= ~Block_label;
1024: };
1025: #endif
1026: fwri_Ident(f,p->ident);
1027: fwri_Bbx(f,&(p->bx));
1028: fwri_Radians(f,p->skew);
1029: fwri_Radians(f,p->shear);
1030: fwri_Ems(f,p->wst);
1031: fwri_Merit(f,p->m);
1032: fwri_uint2(f,p->bks.mny);
1033: fwri_uint2(f,p->ls.mny);
1034: fwri_uint2(f,p->ws.mny);
1035: fwri_uint2(f,p->cs.mny);
1036: fwri_uint3(f,p->bs.mny);
1037: #if dbg_fwrb_toa
1038: err("fwrb_block: %s",block_toa(p));
1039: #endif
1040: if(p->ident&Block_label) fwrb_label(f,p->l);
1041: }
1042: #else
1043: fwrb_block(fp,bkp)
1044: FILE *fp;
1045: Block *bkp;
1046: { BlockF bf;
1047: int stat;
1048: #if dbg_fwrb
1049: if((!(bkp->ident&IsBlock))||(bkp->ident&(IsALL&(~IsBlock))))
1050: err("fwrb_block: %s",block_toa(bkp));
1051: #endif
1052: memset(&bf,'\0',sizeof(bf));
1053: bf.ident = bkp->ident;
1054: bf.bx = bkp->bx;
1055: bf.wst = bkp->wst;
1056: bf.skew = bkp->skew;
1057: bf.shear = bkp->shear;
1058: bf.lmny = bkp->ls.mny;
1059: bf.wmny = bkp->ws.mny;
1060: bf.cmny = bkp->cs.mny;
1061: bf.bmny = bkp->bs.mny;
1062: #if dbg_fwrb_toa
1063: err("fwrb_block: %s",block_toa(bkp));
1064: #endif
1065: if((stat=fwrite(&bf,sizeof(BlockF),1,fp))!=1)
1066: abort("fwrb_block: can't fwrite - status %d",stat);
1067: }
1068: #endif
1069:
1070: fwrb_blocks_etc(fp,bks,etc)
1071: FILE *fp;
1072: Blocks bks;
1073: Ident etc;
1074: { register Block *bkp,**bkpp;
1075: if(bks.mny>0) for(bkp= *(bkpp=bks.bpa); bkp!=NULL; bkp= *(++bkpp))
1076: fwrb_block_etc(fp,bkp,etc);
1077: }
1078:
1079: fwrb_block_etc(fp,bkp,etc)
1080: FILE *fp;
1081: Block *bkp;
1082: Ident etc;
1083: { static Ident parts = (IsTxtln|IsWord|IsChar|IsBlob);
1084: Block bk;
1085: if((etc&parts)!=parts) /* write selected parts */ {
1086: bk = *bkp;
1087: if(!(etc&IsTxtln)) bk.ls.mny=0;
1088: if(!(etc&IsWord)) bk.ws.mny=0;
1089: if(!(etc&IsChar)) bk.cs.mny=0;
1090: if(!(etc&IsBlob)) bk.bs.mny=0;
1091: bkp = &bk; /* write modified record */
1092: };
1093: fwrb_block(fp,bkp);
1094: fwrb_txtlns_etc(fp,bkp->ls,etc);
1095: fwrb_words_etc(fp,bkp->ws,etc);
1096: fwrb_chars_etc(fp,bkp->cs,etc);
1097: fwrb_blobs_etc(fp,bkp->bs,etc);
1098: }
1099:
1100: #if FRDI
1101: int frdb_block(f,p)
1102: FILE *f;
1103: Block *p;
1104: { *p = empty_Block;
1105: if(feof(f))
1106: return(0);
1107: p->ident=frdi_Ident(f);
1108: frdi_Bbx(f,&(p->bx));
1109: p->skew=frdi_Radians(f);
1110: p->shear=frdi_Radians(f);
1111: p->wst=frdi_Ems(f);
1112: p->m=frdi_Merit(f);
1113: p->bks.mny=frdi_uint2(f);
1114: p->ls.mny=frdi_uint2(f);
1115: p->ws.mny=frdi_uint2(f);
1116: p->cs.mny=frdi_uint2(f);
1117: p->bs.mny=frdi_uint3(f);
1118: #if dbg_frdb_toa
1119: err("frdb_block: %s",block_toa(p));
1120: #endif
1121: #if dbg_frdb
1122: if((!(p->ident&IsBlock))||(p->ident&(IsALL&(~IsBlock))))
1123: err("frdb_block: %s",block_toa(p));
1124: #endif
1125: if(p->ident&Block_label) p->l = frdb_label(f);
1126: if(ferror(f)) return(-errno); else return(1);
1127: }
1128: #else
1129: int frdb_block(fp,bkp)
1130: FILE *fp;
1131: Block *bkp;
1132: { BlockF bf;
1133: int stat;
1134: if((stat=fread(&bf,sizeof(BlockF),1,fp))!=1)
1135: abort("frdb_block: can't fread - status %d",stat);
1136: *bkp = empty_Block;
1137: bkp->ident = bf.ident;
1138: bkp->bx = bf.bx;
1139: bkp->skew = bf.skew;
1140: bkp->shear = bf.shear;
1141: bkp->wst = bf.wst;
1142: bkp->ls.mny = bf.lmny;
1143: bkp->ws.mny = bf.wmny;
1144: bkp->cs.mny = bf.cmny;
1145: bkp->bs.mny = bf.bmny;
1146: #if dbg_frdb
1147: if((!(bkp->ident&IsBlock))||(bkp->ident&(IsALL&(~IsBlock))))
1148: err("frdb_block: %s",block_toa(bkp));
1149: #endif
1150: #if dbg_frdb_toa
1151: err("frdb_block: %s",block_toa(bkp));
1152: #endif
1153: if(bkp->ident&Block_label) bkp->l = frdb_label(fp);
1154: if(ferror(fp)) return(-errno); else return(1);
1155: }
1156: #endif
1157:
1158: frdb_block_etc(fp,bkp,etc)
1159: FILE *fp;
1160: Block *bkp;
1161: Ident etc;
1162: { BlockF bf;
1163: int stat;
1164: frdb_block(fp,bkp);
1165: if(etc&IsTxtln && bkp->ls.mny>0)
1166: frdb_txtlns_etc(fp,&(bkp->ls),etc);
1167: else bkp->ls = empty_Txtlns;
1168: if(etc&IsWord && bkp->ws.mny>0)
1169: frdb_words_etc(fp,&(bkp->ws),etc);
1170: else bkp->ws = empty_Words;
1171: if(etc&IsChar && bkp->cs.mny>0)
1172: frdb_chars_etc(fp,&(bkp->cs),etc);
1173: else bkp->cs = empty_Chars;
1174: if(etc&IsBlob && bkp->bs.mny>0)
1175: frdb_blobs_etc(fp,&(bkp->bs),etc);
1176: else bkp->bs = empty_Blobs;
1177: if(ferror(fp)) return(-errno); else return(1);
1178: }
1179:
1180: /* read number of blocks, and their parts */
1181: frdb_blocks_etc(fp,bksp,etc)
1182: FILE *fp;
1183: Blocks *bksp;
1184: Ident etc;
1185: { int bi;
1186: register Block *bkp,**bkpp;
1187: if(bksp->mny<=0) {
1188: *bksp = empty_Blocks;
1189: return(1);
1190: };
1191:
1192: if((bkpp=bksp->bpa=(Block **)malloc((bksp->mny+1)*sizeof(Block *)))==NULL)
1193: abort("can't alloc Blocks.bpa array");
1194: for(bi=0; bi<bksp->mny; bi++) {
1195: *(bkpp++) = bkp = alloc_block();
1196: frdb_block_etc(fp,bkp,etc);
1197: };
1198: *bkpp = NULL;
1199: if(ferror(fp)) return(-errno); else return(1);
1200: }
1201:
1202: free_block_etc(p,etc)
1203: Block *p;
1204: Ident etc;
1205: { free_txtlns_etc(&(p->ls),etc);
1206: free_words_etc(&(p->ws),etc);
1207: free_chars_etc(&(p->cs),etc);
1208: free_blobs_etc(&(p->bs),etc);
1209: if(p->ident&Block_label && p->l!=NULL) {
1210: free(p->l); p->l=NULL; p->ident &= ~Block_label;
1211: };
1212: if(etc&IsBlock) {
1213: free(p);
1214: free_census(Block,1);
1215: };
1216: }
1217:
1218: /* Unconditionally free the malloc-space array of pointers, and empty the set.
1219: Don't free the records that it owned.
1220: */
1221: free_blocks(p)
1222: Blocks *p;
1223: { if(p->bpa!=NULL) { free(p->bpa); p->bpa = NULL; }
1224: p->mny = 0;
1225: }
1226:
1227: free_blocks_etc(p,etc)
1228: Blocks *p;
1229: Ident etc;
1230: { register Block *bkp,**bkpp;
1231: if(p->mny>0&&(etc&IsBlock))
1232: for(bkp= *(bkpp=p->bpa); bkp!=NULL; bkp= *(++bkpp))
1233: free_block_etc(bkp,etc);
1234: free_blocks(p);
1235: }
1236:
1237: /* return a pointer to a distinct and duplicate copy of *bkp,
1238: created out of malloc space */
1239: Block *dup_block(bkp)
1240: Block *bkp;
1241: { Block *dup;
1242: dup=alloc_block();
1243: *dup = *bkp;
1244: return(dup);
1245: }
1246:
1247: /* Return a pointer to a distinct and duplicate copy of *bkp, and its parts
1248: as specified by `etc', created out of malloc space. */
1249: Block *dup_block_etc(bkp,etc)
1250: Block *bkp;
1251: Ident etc;
1252: { Block *dup;
1253: dup = dup_block(bkp);
1254: if(etc&IsBlob&&dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(bkp->bs),etc);
1255: else dup->bs = empty_Blobs;
1256: if(etc&IsChar&&dup->cs.mny>0) dup->cs = *dup_chars_etc(&(bkp->cs),etc);
1257: else dup->cs = empty_Chars;
1258: if(etc&IsWord&&dup->ws.mny>0) dup->ws = *dup_words_etc(&(bkp->ws),etc);
1259: else dup->ws = empty_Words;
1260: if(etc&IsTxtln&&dup->ls.mny>0) dup->ls = *dup_txtlns_etc(&(bkp->ls),etc);
1261: else dup->ls = empty_Txtlns;
1262: return(dup);
1263: }
1264:
1265: /* Return a pointer to a distinct local static duplicate of non-empty *bksp.
1266: Its bkpa array is created newly out of malloc space.
1267: If etc&IsBlock, all its Blocks are also duplicated,
1268: else the contents of bkpa point to the old unduplicated Blocks.
1269: */
1270: Blocks *dup_blocks_etc(bksp,etc)
1271: Blocks *bksp;
1272: Ident etc; /* parts to duplicate */
1273: { static Blocks dup;
1274: register Block **bkpp,**dpp;
1275: if((dup.mny = bksp->mny)<=0) dup = empty_Blocks;
1276: else { if((dup.bpa=(Block **)malloc((dup.mny+1)*sizeof(Block *)))==NULL)
1277: abort("can't dup bks.bpa");
1278: for(bkpp=bksp->bpa,dpp=dup.bpa; *bkpp!=NULL; bkpp++,dpp++) {
1279: if(etc&IsBlock) *dpp = dup_block_etc(*bkpp,etc);
1280: else *dpp = *bkpp;
1281: };
1282: *dpp = NULL;
1283: };
1284: return(&dup);
1285: }
1286:
1287: /* Append a block to the end of a blocks set.
1288: Return appended Block *. */
1289: Block *append_block(bkp,bksp)
1290: Block *bkp;
1291: Blocks *bksp;
1292: { register Block *rp,**rpp,**npp;
1293: if(bksp->mny==0) {
1294: if((bksp->bpa=(Block **)malloc(2*sizeof(Block *)))==NULL)
1295: abort("append_block: can't malloc bksp->bpa");
1296: }
1297: else { if((bksp->bpa=(Block **)realloc(
1298: bksp->bpa,
1299: (bksp->mny+2)*sizeof(Block *))
1300: )==NULL)
1301: abort("append_block: can't realloc bksp->bpa");
1302: };
1303: bksp->bpa[bksp->mny] = bkp;
1304: bksp->bpa[++bksp->mny] = NULL;
1305: return(bkp);
1306: }
1307:
1308: /* remove a block from a blocks set */
1309: remove_block(bkp,bksp)
1310: Block *bkp;
1311: Blocks *bksp;
1312: { register Block *rp,**rpp,**npp;
1313: if(bksp->mny==0) err("can't remove Block - Blocks empty");
1314: else { for(rp= *(rpp=bksp->bpa); rp!=NULL; rp= *(++rpp)) if(rp==bkp) break;
1315: if(rp==NULL) err("can't remove Block - not found");
1316: else { /* move later entries up */
1317: npp=rpp+1;
1318: do *(rpp++)= *(npp++); while ((*rpp)!=NULL);
1319: if((--(bksp->mny))==0) {free(bksp->bpa); bksp->bpa=NULL;};
1320: /* don't bother to realloc downwards */
1321: };
1322: };
1323: }
1324:
1325: ConstPitch *alloc_constpitch()
1326: { ConstPitch *p;
1327: if((p=(ConstPitch *)malloc(sizeof(ConstPitch)))==NULL)
1328: abort("can't alloc ConstPitch");
1329: else { *p = empty_ConstPitch;
1330: return(p);
1331: };
1332: }
1333:
1334: char *constpitch_toa(p)
1335: ConstPitch *p;
1336: { static char s[80];
1337: sprintf(s,"{w%.3f,o%d,r%.1f}",
1338: p->w,p->o,p->r);
1339: return(s);
1340: }
1341:
1342: free_constpitch(p)
1343: ConstPitch *p;
1344: { free(p);
1345: }
1346:
1347: Txtln *alloc_txtln()
1348: { Txtln *p;
1349: if((p=(Txtln *)malloc(sizeof(Txtln)))==NULL)
1350: abort("can't alloc Txtln");
1351: alloc_census(Txtln,1);
1352: *p = empty_Txtln;
1353: return(p);
1354: }
1355:
1356: char *txtln_toa(p)
1357: Txtln *p;
1358: { static char s[80];
1359: sprintf(s,"%s bx%s sz%s ba%d cw%s m%s l%d w%d c%d b%d %s",
1360: ident_toa(p->ident),
1361: bbx_toa(&(p->bx)),
1362: pts_toa(p->size),
1363: p->basl,
1364: /** proj omitted **/
1365: ((p->cp!=NULL)? constpitch_toa(p->cp): "0"),
1366: merit_toa(p->m),
1367: p->ls.mny,p->ws.mny,p->cs.mny,p->bs.mny,
1368: (p->l!=NULL)? p->l: "");
1369: return(s);
1370: }
1371:
1372: #if FWRI
1373: fwrb_txtln(f,p)
1374: FILE *f;
1375: Txtln *p;
1376: {
1377: #if dbg_fwrb
1378: if((!(p->ident&IsTxtln))||(p->ident&(IsALL&(~IsTxtln))))
1379: err("fwrb_txtln: %s",txtln_toa(p));
1380: if(p->ident&Txtln_label && p->l==NULL) {
1381: err("fwrb_page: Txtln_label set but .l==NULL");
1382: p->ident &= ~Txtln_label;
1383: };
1384: #endif
1385: fwri_Ident(f,p->ident);
1386: fwri_Bbx(f,&(p->bx));
1387: fwri_Pts(f,p->size);
1388: fwri_Scoor(f,p->basl);
1389: /* fwri_?(f,p->proj); */
1390: /* fwri_ConstPitch(f,p->cp); */
1391: fwri_Merit(f,p->m);
1392: fwri_uint2(f,p->ls.mny);
1393: fwri_uint2(f,p->ws.mny);
1394: fwri_uint2(f,p->cs.mny);
1395: fwri_uint3(f,p->bs.mny);
1396: #if dbg_fwrb_toa
1397: err("fwrb_txtln: %s",txtln_toa(p));
1398: #endif
1399: if(p->ident&Txtln_label) fwrb_label(f,p->l);
1400: }
1401: #else
1402: fwrb_txtln(fp,lp)
1403: FILE *fp;
1404: Txtln *lp;
1405: { TxtlnF lf;
1406: int stat;
1407: #if dbg_fwrb
1408: if((!(lp->ident&IsTxtln))||(lp->ident&(IsALL&(~IsTxtln))))
1409: err("fwrb_txtln: %s",txtln_toa(lp));
1410: #endif
1411: memset(&lf,'\0',sizeof(lf));
1412: lf.ident = lp->ident;
1413: lf.bx = lp->bx;
1414: lf.basl = lp->basl;
1415: lf.size = lp->size;
1416: if(lp->proj!=NULL) lf.pmny = lp->bx.b.y - lp->bx.a.y + 1;
1417: else lf.pmny = 0;
1418: /* ignore lp->cp for now */
1419: lf.wmny = lp->ws.mny;
1420: lf.cmny = lp->cs.mny;
1421: lf.bmny = lp->bs.mny;
1422: if((stat=fwrite(&lf,sizeof(TxtlnF),1,fp))!=1)
1423: abort("can't write TxtlnF, status %d",stat);
1424: #if dbg_fwrb_toa
1425: err("fwrb_txtln: %s",txtln_toa(lp));
1426: #endif
1427: if(lf.ident&Txtln_label) fwrb_label(fp,lp->l);
1428: }
1429: #endif
1430:
1431: fwrb_txtlns_etc(fp,ls,etc)
1432: FILE *fp;
1433: Txtlns ls;
1434: Ident etc;
1435: { register Txtln *lp,**lpp;
1436: if(ls.mny>0) for(lp= *(lpp=ls.lpa); lp!=NULL; lp= *(++lpp))
1437: fwrb_txtln_etc(fp,lp,etc);
1438: }
1439:
1440: fwrb_txtln_etc(fp,lp,etc)
1441: FILE *fp;
1442: Txtln *lp;
1443: Ident etc;
1444: { static Ident parts = (IsWord|IsChar|IsBlob);
1445: Txtln tl;
1446: if((etc&parts)!=parts) /* write selected parts */ {
1447: tl = *lp;
1448: if(!(etc&IsWord)) tl.ws.mny=0;
1449: if(!(etc&IsChar)) tl.cs.mny=0;
1450: if(!(etc&IsBlob)) tl.bs.mny=0;
1451: lp = &tl; /* write modified record */
1452: };
1453: fwrb_txtln(fp,lp);
1454: if(lp->proj!=NULL) {/* write projection array someday */};
1455: fwrb_words_etc(fp,lp->ws,etc);
1456: fwrb_chars_etc(fp,lp->cs,etc);
1457: fwrb_blobs_etc(fp,lp->bs,etc);
1458: }
1459:
1460: #if FRDI
1461: int frdb_txtln(f,p)
1462: FILE *f;
1463: Txtln *p;
1464: { *p = empty_Txtln;
1465: if(feof(f))
1466: return(0);
1467: p->ident=frdi_Ident(f);
1468: frdi_Bbx(f,&(p->bx));
1469: p->size=frdi_Pts(f);
1470: p->basl=frdi_Scoor(f);
1471: /* p->proj=frdi_?(f); */
1472: /* p->cp=frdi_ConstPitch(f); */
1473: p->m=frdi_Merit(f);
1474: p->ls.mny=frdi_uint2(f);
1475: p->ws.mny=frdi_uint2(f);
1476: p->cs.mny=frdi_uint2(f);
1477: p->bs.mny=frdi_uint3(f);
1478: #if dbg_frdb
1479: if((!(p->ident&IsTxtln))||(p->ident&(IsALL&(~IsTxtln))))
1480: err("frdb_txtln: %s",txtln_toa(p));
1481: #endif
1482: #if dbg_frdb_toa
1483: err("frdb_txtln: %s",txtln_toa(p));
1484: #endif
1485: if(p->ident&Txtln_label) p->l = frdb_label(f);
1486: if(ferror(f)) return(-errno); else return(1);
1487: }
1488: #else
1489: int frdb_txtln(fp,lp)
1490: FILE *fp;
1491: Txtln *lp;
1492: { TxtlnF lf;
1493: int stat;
1494: if((stat=fread(&lf,sizeof(TxtlnF),1,fp))!=1)
1495: abort("can't read TxtlnF, status %d",stat);
1496: *lp = empty_Txtln;
1497: lp->ident = lf.ident;
1498: lp->bx = lf.bx;
1499: lp->basl = lf.basl;
1500: lp->size = lf.size;
1501: if(lf.pmny>0) lp->proj=(short *)malloc(lf.pmny);
1502: else lp->proj = NULL;
1503: lp->cp = NULL;
1504: lp->ws.mny = lf.wmny;
1505: lp->cs.mny = lf.cmny;
1506: lp->bs.mny = lf.bmny;
1507: #if dbg_frdb
1508: if((!(lp->ident&IsTxtln))||(lp->ident&(IsALL&(~IsTxtln))))
1509: err("frdb_txtln: %s",txtln_toa(lp));
1510: #endif
1511: #if dbg_frdb_toa
1512: err("frdb_txtln: %s",txtln_toa(lp));
1513: #endif
1514: if(lp->ident&Txtln_label) lp->l = frdb_label(fp);
1515: if(ferror(fp)) return(-errno); else return(1);
1516: }
1517: #endif
1518:
1519: frdb_txtln_etc(fp,lp,etc)
1520: FILE *fp;
1521: Txtln *lp;
1522: Ident etc;
1523: { TxtlnF lf;
1524: int stat;
1525: frdb_txtln(fp,lp);
1526: if(lp->proj!=NULL) {/* read projection array someday */};
1527: if(etc&IsWord && lp->ws.mny>0)
1528: frdb_words_etc(fp,&(lp->ws),etc);
1529: else lp->ws = empty_Words;
1530: if(etc&IsChar && lp->cs.mny>0)
1531: frdb_chars_etc(fp,&(lp->cs),etc);
1532: else lp->cs = empty_Chars;
1533: if(etc&IsBlob && lp->bs.mny>0)
1534: frdb_blobs_etc(fp,&(lp->bs),etc);
1535: else lp->bs = empty_Blobs;
1536: if(ferror(fp)) return(-errno); else return(1);
1537: }
1538:
1539: /* read number of txtlns, and parts */
1540: frdb_txtlns_etc(fp,lsp,etc)
1541: FILE *fp;
1542: Txtlns *lsp;
1543: Ident etc;
1544: { int li;
1545: register Txtln *lp,**lpp;
1546: if(lsp->mny<=0) {
1547: *lsp = empty_Txtlns;
1548: return(1);
1549: };
1550: if((lpp=lsp->lpa=(Txtln **)malloc((lsp->mny+1)*sizeof(Txtln *)))==NULL)
1551: abort("can't alloc Txtlns.lpa array");
1552: for(li=0; li<lsp->mny; li++) {
1553: *(lpp++) = lp = alloc_txtln();
1554: frdb_txtln_etc(fp,lp,etc);
1555: };
1556: *lpp = NULL;
1557: if(ferror(fp)) return(-errno); else return(1);
1558: }
1559:
1560: /* Append a txtln to the end of a txtlns set.
1561: Do NOT maintain Txtlns in order sorted ascending on Txtln.bx.a.y.
1562: Return appended Txtln *. */
1563: Txtln *append_txtln(lp,lsp)
1564: Txtln *lp;
1565: Txtlns *lsp;
1566: { register Txtln *rp,**rpp,**npp;
1567: if(lsp->mny==0) {
1568: if((lsp->lpa=(Txtln **)malloc(2*sizeof(Txtln *)))==NULL)
1569: abort("append_txtln: can't malloc lsp->lpa");
1570: }
1571: else { if((lsp->lpa=(Txtln **)realloc(
1572: lsp->lpa,
1573: (lsp->mny+2)*sizeof(Txtln *))
1574: )==NULL)
1575: abort("append_txtln: can't realloc lsp->lpa");
1576: };
1577: lsp->lpa[lsp->mny] = lp;
1578: lsp->lpa[++lsp->mny] = NULL;
1579: return(lp);
1580: }
1581:
1582: /* remove a txtln from a txtlns set */
1583: remove_txtln(lp,lsp)
1584: Txtln *lp;
1585: Txtlns *lsp;
1586: { register Txtln *rp,**rpp,**npp;
1587: if(lsp->mny==0) err("can't remove Txtln - Txtlns empty");
1588: else { for(rp= *(rpp=lsp->lpa); rp!=NULL; rp= *(++rpp)) if(rp==lp) break;
1589: if(rp==NULL) err("can't remove Txtln - not found");
1590: else { /* move later entries up */
1591: npp=rpp+1;
1592: do *(rpp++)= *(npp++); while ((*rpp)!=NULL);
1593: if((--(lsp->mny))==0) {free(lsp->lpa); lsp->lpa=NULL;};
1594: /* don't bother to realloc downwards */
1595: };
1596: };
1597: }
1598:
1599: free_txtln_etc(p,etc)
1600: Txtln *p;
1601: Ident etc;
1602: { free_words_etc(&(p->ws),etc);
1603: free_chars_etc(&(p->cs),etc);
1604: free_blobs_etc(&(p->bs),etc);
1605: if(p->ident&Txtln_label && p->l!=NULL) {
1606: free(p->l); p->l=NULL; p->ident &= ~Txtln_label;
1607: };
1608: if(etc&IsTxtln) {
1609: if(p->l!=NULL) free(p->l);
1610: free(p);
1611: free_census(Txtln,1);
1612: };
1613: }
1614:
1615: /* Unconditionally free the malloc-space array of pointers, and empty the set.
1616: Don't free the records that it owned.
1617: */
1618: free_txtlns(lsp)
1619: Txtlns *lsp;
1620: { if(lsp->lpa!=NULL) { free(lsp->lpa); lsp->lpa = NULL; }
1621: lsp->mny = 0;
1622: }
1623:
1624: free_txtlns_etc(lsp,etc)
1625: Txtlns *lsp;
1626: Ident etc;
1627: { register Txtln *lp,**lpp;
1628: if(lsp->mny>0&&(etc&IsTxtln))
1629: for(lp= *(lpp=lsp->lpa); lp!=NULL; lp= *(++lpp))
1630: free_txtln_etc(lp,etc);
1631: free_txtlns(lsp);
1632: }
1633:
1634: /* return a pointer to a distinct and duplicate copy of *lp,
1635: created out of malloc space */
1636: Txtln *dup_txtln(lp)
1637: Txtln *lp;
1638: { Txtln *dup;
1639: if((dup=(Txtln *)malloc(sizeof(Txtln)))==NULL)
1640: abort("can't dup Txtln");
1641: alloc_census(Txtln,1);
1642: *dup = *lp;
1643: return(dup);
1644: }
1645:
1646: /* Return a pointer to a distinct and duplicate copy of *lp, and its parts
1647: as specified by `etc', created out of malloc space. */
1648: Txtln *dup_txtln_etc(lp,etc)
1649: Txtln *lp;
1650: Ident etc;
1651: { Txtln *dup;
1652: dup = dup_txtln(lp);
1653: if(etc&IsBlob&&dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(lp->bs),etc);
1654: else dup->bs = empty_Blobs;
1655: if(etc&IsChar&&dup->cs.mny>0) dup->cs = *dup_chars_etc(&(lp->cs),etc);
1656: else dup->cs = empty_Chars;
1657: if(etc&IsWord&&dup->ws.mny>0) dup->ws = *dup_words_etc(&(lp->ws),etc);
1658: else dup->ws = empty_Words;
1659: return(dup);
1660: }
1661:
1662: /* Return a pointer to a distinct local static duplicate of non-empty *lsp.
1663: Its lpa array is created newly out of malloc space.
1664: If etc&IsTxtln, all its Txtlns are also duplicated,
1665: else the contents of lpa point to the old unduplicated Txtlns.
1666: */
1667: Txtlns *dup_txtlns_etc(lsp,etc)
1668: Txtlns *lsp;
1669: Ident etc; /* parts to duplicate */
1670: { static Txtlns dup;
1671: register Txtln **lpp,**dpp;
1672: if((dup.mny = lsp->mny)<=0) dup = empty_Txtlns;
1673: else { if((dup.lpa=(Txtln **)malloc((dup.mny+1)*sizeof(Txtln *)))==NULL)
1674: abort("can't dup ls.lpa");
1675: for(lpp=lsp->lpa,dpp=dup.lpa; *lpp!=NULL; lpp++,dpp++) {
1676: if(etc&IsTxtln) *dpp = dup_txtln_etc(*lpp,etc);
1677: else *dpp = *lpp;
1678: };
1679: *dpp = NULL;
1680: };
1681: return(&dup);
1682: }
1683:
1684: Word *alloc_word()
1685: { Word *p;
1686: if((p=(Word *)malloc(sizeof(Word)))==NULL)
1687: abort("can't alloc Word");
1688: alloc_census(Word,1);
1689: *p = empty_Word;
1690: return(p);
1691: }
1692:
1693: char *word_toa(p)
1694: Word *p;
1695: { static char s[80];
1696: sprintf(s,"%s bx%s ws%0.2f c%d b%d m%s w%d",
1697: ident_toa(p->ident),
1698: bbx_toa(&(p->bx)),
1699: p->wsp,
1700: p->cs.mny,p->bs.mny,merit_toa(p->m),p->ws.mny);
1701: return(s);
1702: }
1703:
1704: /* Are two Words identical? A not quite exhaustively-detailed test. */
1705: boolean eq_word(w1,w2)
1706: Word *w1,*w2;
1707: { register Char **c1,**c2;
1708: if(w1->cs.mny!=w2->cs.mny) return(F);
1709: for(c1=w1->cs.cpa,c2=w2->cs.cpa; *c1!=NULL; c1++,c2++) {
1710: if((*c1)->area!=(*c2)->area) return(F);
1711: if(!bbx_eq(&((*c1)->bx),&((*c2)->bx))) return(F);
1712: if((*c1)->bmny!=(*c2)->bmny) return(F);
1713: };
1714: /* don't bother to compare Blob lists in detail (they aren't
1715: in any particular order). */
1716: return(T);
1717: }
1718:
1719: /* Compute a hash key for this Word that is likely to indicate whether or
1720: not it is geometrically identical to another Word. */
1721: int hash_word(w)
1722: Word *w;
1723: { register int k;
1724: register Char **c;
1725: if(w->cs.mny==0) return(0);
1726: k = w->bx.a.x * w->bx.a.y * w->bx.b.x * w->bx.b.y;
1727: for(c=w->cs.cpa; (*c)!=NULL; c++) {
1728: k += (*c)->bx.a.x * (*c)->bx.a.y * (*c)->bx.b.x
1729: * (*c)->bx.b.y * (*c)->bmny * (*c)->area;
1730: };
1731: return(k);
1732: }
1733:
1734: #if FWRI
1735: fwrb_word(f,p)
1736: FILE *f;
1737: Word *p;
1738: {
1739: #if dbg_fwrb
1740: if((!(p->ident&IsWord))||(p->ident&(IsALL&(~IsWord))))
1741: err("fwrb_word: %s",word_toa(p));
1742: if(p->ident&Word_label && p->l==NULL) {
1743: err("fwrb_page: Word_label set but .l==NULL");
1744: p->ident &= ~Word_label;
1745: };
1746: #endif
1747: fwri_Ident(f,p->ident);
1748: fwri_Bbx(f,&(p->bx));
1749: fwri_int2(f,p->wsp*UCHAR_MAX);
1750: fwri_Merit(f,p->m);
1751: fwri_Prob(f,p->p);
1752: fwri_uint2(f,p->ws.mny);
1753: fwri_uint2(f,p->cs.mny);
1754: fwri_uint3(f,p->bs.mny);
1755: /* fwri_int4(f,p->hash); */
1756: #if dbg_fwrb_toa
1757: err("fwrb_word: %s",word_toa(p));
1758: #endif
1759: if(p->ident&Word_label) fwrb_label(f,p->l);
1760: }
1761: #else
1762: fwrb_word(fp,wp)
1763: FILE *fp;
1764: Word *wp;
1765: { WordF wf;
1766: int stat;
1767: #if dbg_fwrb
1768: if((!(wp->ident&IsWord))||(wp->ident&(IsALL&(~IsWord))))
1769: err("fwrb_word: %s",word_toa(wp));
1770: #endif
1771: memset(&wf,'\0',sizeof(wf));
1772: wf.ident = wp->ident;
1773: wf.bx = wp->bx;
1774: wf.wsp = wp->wsp;
1775: wf.m = wp->m;
1776: wf.wmny = wp->ws.mny;
1777: wf.cmny = wp->cs.mny;
1778: wf.bmny = wp->bs.mny;
1779: if((stat=fwrite(&wf,sizeof(WordF),1,fp))!=1)
1780: abort("can't write WordF, status %d",stat);
1781: #if dbg_fwrb_toa
1782: err("fwrb_word: %s",word_toa(wp));
1783: #endif
1784: if(wf.ident&Word_label) fwrb_label(fp,wp->l);
1785: }
1786: #endif
1787:
1788: fwrb_words_etc(fp,ws,etc)
1789: FILE *fp;
1790: Words ws;
1791: Ident etc;
1792: { register Word *wp,**wpp;
1793: if(ws.mny>0) for(wp= *(wpp=ws.wpa); wp!=NULL; wp= *(++wpp))
1794: fwrb_word_etc(fp,wp,etc);
1795: }
1796:
1797: fwrb_word_etc(fp,wp,etc)
1798: FILE *fp;
1799: Word *wp;
1800: Ident etc;
1801: { static Ident parts = (IsWord|IsChar|IsBlob);
1802: Word wd;
1803: if((etc&parts)!=parts) /* write selected parts */ {
1804: wd = *wp;
1805: if(!(etc&IsWord)) wd.ws.mny=0;
1806: if(!(etc&IsChar)) wd.cs.mny=0;
1807: if(!(etc&IsBlob)) wd.bs.mny=0;
1808: wp = &wd; /* write modified record */
1809: };
1810: fwrb_word(fp,wp);
1811: if(etc&IsWord) fwrb_words_etc(fp,wp->ws,IsALL);
1812: fwrb_chars_etc(fp,wp->cs,etc);
1813: fwrb_blobs_etc(fp,wp->bs,etc);
1814: }
1815:
1816: #if FRDI
1817: int frdb_word(f,p)
1818: FILE *f;
1819: Word *p;
1820: { *p = empty_Word;
1821: if(feof(f))
1822: return(0);
1823: p->ident=frdi_Ident(f);
1824: frdi_Bbx(f,&(p->bx));
1825: p->wsp=frdi_int2(f)/(float)UCHAR_MAX;
1826: p->m=frdi_Merit(f);
1827: p->p=frdi_Prob(f);
1828: p->ws.mny=frdi_uint2(f);
1829: p->cs.mny=frdi_uint2(f);
1830: p->bs.mny=frdi_uint3(f);
1831: /* p->hash=frdi_int4(f); */
1832: #if dbg_frdb
1833: if((!(p->ident&IsWord))||(p->ident&(IsALL&(~IsWord))))
1834: err("frdb_word: %s",word_toa(p));
1835: #endif
1836: #if dbg_frdb_toa
1837: err("frdb_word: %s",word_toa(p));
1838: #endif
1839: if(p->ident&Word_label) p->l = frdb_label(f);
1840: if(ferror(f)) return(-errno); else return(1);
1841: }
1842: #else
1843: int frdb_word(fp,wp)
1844: FILE *fp;
1845: Word *wp;
1846: { WordF wf;
1847: int stat;
1848: if((stat=fread(&wf,sizeof(WordF),1,fp))!=1)
1849: abort("can't read WordF, status %d",stat);
1850: *wp = empty_Word;
1851: wp->ident = wf.ident;
1852: wp->bx = wf.bx;
1853: wp->wsp = wf.wsp;
1854: wp->m = wf.m;
1855: wp->ws.mny = wf.wmny;
1856: wp->cs.mny = wf.cmny;
1857: wp->bs.mny = wf.bmny;
1858: #if dbg_frdb
1859: if((!(wp->ident&IsWord))||(wp->ident&(IsALL&(~IsWord))))
1860: err("frdb_word: %s",word_toa(wp));
1861: #endif
1862: #if dbg_frdb_toa
1863: err("frdb_word: %s",word_toa(wp));
1864: #endif
1865: if(wp->ident&Word_label) wp->l = frdb_label(fp);
1866: if(ferror(fp)) return(-errno); else return(1);
1867: }
1868: #endif
1869:
1870: frdb_word_etc(fp,wp,etc)
1871: FILE *fp;
1872: Word *wp;
1873: Ident etc;
1874: { WordF cf;
1875: int stat;
1876: frdb_word(fp,wp);
1877: frdb_words_etc(fp,&(wp->ws),IsALL); /* rd alternatives entirely, if any */
1878: if(etc&IsChar && wp->cs.mny>0)
1879: frdb_chars_etc(fp,&(wp->cs),etc);
1880: else wp->cs = empty_Chars;
1881: if(etc&IsBlob && wp->bs.mny>0)
1882: frdb_blobs_etc(fp,&(wp->bs),etc);
1883: else wp->bs = empty_Blobs;
1884: if(ferror(fp)) return(-errno); else return(1);
1885: }
1886:
1887: /* read words, and their parts */
1888: frdb_words_etc(fp,wsp,etc)
1889: FILE *fp;
1890: Words *wsp;
1891: Ident etc;
1892: { int wi;
1893: register Word *wp,**wpp;
1894: if(wsp->mny<=0) {
1895: *wsp = empty_Words;
1896: return(1);
1897: };
1898: if((wpp=wsp->wpa=(Word **)malloc((wsp->mny+1)*sizeof(Word *)))==NULL)
1899: abort("can't alloc Words.wpa array");
1900: for(wi=0; wi<wsp->mny; wi++) {
1901: *(wpp++) = wp = alloc_word();
1902: frdb_word_etc(fp,wp,etc);
1903: };
1904: *wpp = NULL;
1905: if(ferror(fp)) return(-errno); else return(1);
1906: }
1907:
1908: /* remove a word from a words set */
1909: remove_word(wp,wsp)
1910: Word *wp;
1911: Words *wsp;
1912: { register Word *rp,**rpp,**npp;
1913: if(wsp->mny==0) err("can't remove Word - Words empty");
1914: else { for(rp= *(rpp=wsp->wpa); rp!=NULL; rp= *(++rpp)) if(rp==wp) break;
1915: if(rp==NULL) err("can't remove Word - not found");
1916: else { /* move later entries up */
1917: npp=rpp+1;
1918: do *(rpp++)= *(npp++); while ((*rpp)!=NULL);
1919: if((--(wsp->mny))==0) {free(wsp->wpa); wsp->wpa=NULL;};
1920: /* don't bother to realloc downwards */
1921: };
1922: };
1923: }
1924:
1925: /* Remove a Word from a Txtln's Words set.
1926: Shrink the Txtln's Bbx if the Word abuts it on the left or right.
1927: Ensure that the first Word in the line has wsp==0.0
1928: BUG: doesn't update wsp of trailing Word */
1929: remove_word_txtln(wp,lp)
1930: Word *wp;
1931: Txtln *lp;
1932: { register Word *cwp,**wpp;
1933: remove_word(wp,&(lp->ws));
1934: if(lp->ws.mny>0) {
1935: if(wp->bx.a.x==lp->bx.a.x || wp->bx.b.x==lp->bx.b.x) {
1936: /* recompute possibly shrunken bx */
1937: lp->bx=empty_Bbx;
1938: for(cwp= *(wpp=lp->ws.wpa); cwp!=NULL; cwp= *(++wpp))
1939: merge_bbx(&(cwp->bx),&(lp->bx));
1940: };
1941: (lp->ws.wpa[0])->wsp=0.0;
1942: };
1943: }
1944:
1945: /* Append a word to the end of a words set.
1946: Do NOT maintain set in order ascending on Word.bx.a.x.
1947: Return the appended Word. */
1948: Word *append_word(wp,wsp)
1949: Word *wp;
1950: Words *wsp;
1951: { if(wsp->mny==0) {
1952: if((wsp->wpa=(Word **)malloc(2*sizeof(Word *)))==NULL)
1953: abort("append_word: can't malloc wsp->wpa");
1954: }
1955: else { if((wsp->wpa=(Word **)realloc(
1956: wsp->wpa,
1957: (wsp->mny+2)*sizeof(Word *))
1958: )==NULL)
1959: abort("append_word: can't realloc wsp->wpa");
1960: };
1961: wsp->wpa[wsp->mny++] = wp;
1962: wsp->wpa[wsp->mny] = NULL;
1963: return(wp);
1964: }
1965:
1966: /* Insert a Word into a Words set. Words is assumed to be sorted ascending
1967: on Word.bx.a.x, and this order is maintained.
1968: Words with equal Word.bx.a.x are stored in the order that they were
1969: inserted: so that the first one inserted remains the first among equals
1970: (this feature is important for certain WordSet applications).
1971: Return inserted (Word *) */
1972: Word *insert_word(wp,wsp)
1973: Word *wp;
1974: Words *wsp;
1975: { register Word **wpp,*nwp,*pwp;
1976: if(wsp->mny==0) {
1977: if((wsp->wpa=(Word **)malloc(2*sizeof(Word *)))==NULL)
1978: abort("insert_word: can't malloc wsp->wpa");
1979: wsp->wpa[wsp->mny] = wp;
1980: }
1981: else { if((wpp=wsp->wpa=(Word **)realloc(
1982: wsp->wpa,
1983: (wsp->mny+2)*sizeof(Word *))
1984: )==NULL)
1985: abort("insert_word: can't realloc wsp->wpa");
1986: while(((*wpp)!=NULL)&&(*wpp)->bx.a.x<=wp->bx.a.x) wpp++;
1987: /* **wpp is now 1st entry > *wp in sorted order; insert
1988: new word just before it */
1989: pwp=wp;
1990: do { nwp= *wpp;
1991: *(wpp++)=pwp;
1992: pwp=nwp;
1993: }
1994: while(pwp!=NULL);
1995: };
1996: wsp->wpa[++wsp->mny] = NULL;
1997: return(wp);
1998: }
1999:
2000: /* Insert a Word into the Words owned by a given Txtln,
2001: maintaining the Txtln's Bbx and sorted order in the Words set.
2002: Return the inserted Word * */
2003: Word *insert_word_txtln(wp,lp)
2004: Word *wp;
2005: Txtln *lp;
2006: { merge_bbx(&(wp->bx),&(lp->bx));
2007: return(insert_word(wp,&(lp->ws)));
2008: }
2009:
2010: /* Free wordinterp and its parts as specified in etc.
2011: Always free its strings (if any).
2012: If etc&IsWordInterp, free the record itself also.
2013: */
2014: free_wordinterp_etc(p,etc)
2015: WordInterp *p;
2016: Ident etc;
2017: { if(p->s!=NULL) { free(p->s); p->s=NULL; };
2018: if(p->pp!=NULL) { free(p->pp); p->pp=NULL; };
2019: if(p->by!=NULL) { free(p->by); p->by=NULL; };
2020: if(p->po!=NULL) { free(p->po); p->po=NULL; };
2021: if(p->ps!=NULL) { free(p->ps); p->ps=NULL; };
2022: if(etc&IsWordInterp) free(p);
2023: }
2024:
2025: /* Duplicate (return ptr to local static copy of) a WordInterp.
2026: Always free its strings (if any).
2027: 'etc' is ignored.
2028: */
2029: WordInterp *dup_wordinterp_etc(p,etc)
2030: WordInterp *p;
2031: Ident etc;
2032: { static WordInterp d;
2033: d = *p;
2034: if(p->s!=NULL) d.s = strdup(p->s);
2035: if(p->pp!=NULL) d.pp = strdup(p->pp);
2036: if(p->by!=NULL) d.by = strdup(p->by);
2037: if(p->po!=NULL) d.po = strdup(p->po);
2038: if(p->ps!=NULL) d.ps = strdup(p->ps);
2039: return(&d);
2040: }
2041:
2042: /* Unconditionally free the malloc-space array of pointers, and empty the set.
2043: Don't free the records that it owned.
2044: */
2045: free_words(wsp)
2046: Words *wsp;
2047: { if(wsp->wpa!=NULL) { free(wsp->wpa); wsp->wpa = NULL; }
2048: wsp->mny = 0;
2049: }
2050:
2051: free_words_etc(wsp,etc)
2052: Words *wsp;
2053: Ident etc;
2054: { register Word *wp,**wpp;
2055: int wi;
2056: if(wsp->mny>0&&(etc&IsWord))
2057: for(wp= *(wpp=wsp->wpa); wp!=NULL; wp= *(++wpp))
2058: free_word_etc(wp,etc);
2059: free_words(wsp);
2060: }
2061:
2062: /* return a pointer to a distinct and duplicate copy of *wp,
2063: created out of malloc space */
2064: Word *dup_word(wp)
2065: Word *wp;
2066: { Word *dup;
2067: if((dup=(Word *)malloc(sizeof(Word)))==NULL)
2068: abort("can't dup Word");
2069: alloc_census(Word,1);
2070: *dup = *wp;
2071: return(dup);
2072: }
2073:
2074: /* Return a pointer to a distinct and duplicate copy of *wp, and ALL it owns,
2075: created out of malloc space. (HOW they are duplicated is controlled by flags
2076: in etc.) */
2077: Word *dup_word_etc(wp,etc)
2078: Word *wp;
2079: Ident etc;
2080: { Word *dup;
2081: dup = dup_word(wp);
2082: if(dup->ws.mny>0) dup->ws = *dup_words_etc(&(wp->ws),etc);
2083: else dup->ws = empty_Words;
2084: if(dup->cs.mny>0) dup->cs = *dup_chars_etc(&(wp->cs),etc);
2085: else dup->cs = empty_Chars;
2086: if(dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(wp->bs),etc);
2087: else dup->bs = empty_Blobs;
2088: return(dup);
2089: }
2090:
2091: /* Return a pointer to a distinct local static duplicate of non-empty *wsp.
2092: Its wpa array is created newly out of malloc space.
2093: If etc&IsWord, all its Words are also duplicated,
2094: else the contents of wpa point to the old unduplicated Words.
2095: */
2096: Words *dup_words_etc(wsp,etc)
2097: Words *wsp;
2098: Ident etc; /* parts to duplicate */
2099: { static Words dup;
2100: register Word **wpp,**dpp;
2101: if((dup.mny=wsp->mny)<=0) dup = empty_Words;
2102: else { if((dup.wpa=(Word **)malloc((dup.mny+1)*sizeof(Word *)))==NULL)
2103: abort("can't dup ws.wpa");
2104: for(wpp=wsp->wpa,dpp=dup.wpa; *wpp!=NULL; wpp++,dpp++) {
2105: if(etc&IsWord) *dpp = dup_word_etc(*wpp,etc);
2106: else *dpp = *wpp;
2107: };
2108: *dpp = NULL;
2109: };
2110: return(&dup);
2111: }
2112:
2113: WordInterp *alloc_wordinterp()
2114: { WordInterp *p;
2115: if((p=(WordInterp *)malloc(sizeof(WordInterp)))==NULL)
2116: abort("can't alloc WordInterp");
2117: else { *p = empty_WordInterp;
2118: return(p);
2119: };
2120: }
2121:
2122: char *wordinterp_toa(p)
2123: WordInterp *p;
2124: { static char s[80];
2125: sprintf(s,"%s %s %s|%s|%s|%s",
2126: ident_toa(p->ident),
2127: ((p->s!=NULL)? p->s: ""),
2128: ((p->pp!=NULL)? p->pp: ""),
2129: ((p->by!=NULL)? p->by: ""),
2130: ((p->po!=NULL)? p->po: ""),
2131: ((p->ps!=NULL)? p->ps: "")
2132: );
2133: return(s);
2134: }
2135:
2136: /* Free Word and its parts, as specified by etc.
2137: Always free the pointer-arrays of ws, cs & bs.
2138: If etc&IsWord, free all Words in ws also.
2139: If etc&IsChar, free all Chars in cs also.
2140: If etc&IsBlob, free all Blobs in bs also.
2141: */
2142: free_word_etc(p,etc)
2143: Word *p;
2144: Ident etc;
2145: #define dbg_fwe (F)
2146: { if(dbg_fwe) {
2147: err("free_word_etc: %s",word_toa(p));
2148: err("free_word_etc: %s",ident_toa(etc));
2149: err_census_all;
2150: };
2151: free_words_etc(&(p->ws),IsALL);
2152: free_chars_etc(&(p->cs),etc);
2153: free_blobs_etc(&(p->bs),etc);
2154: if(p->ident&Word_label && p->l!=NULL) {
2155: free(p->l); p->l=NULL; p->ident &= ~Word_label;
2156: };
2157: if(etc&IsWord) free_word(p);
2158: if(dbg_fwe) err_census_all;
2159: }
2160:
2161: free_word(wp)
2162: Word *wp;
2163: { free(wp);
2164: free_census(Word,1);
2165: }
2166:
2167: fwrb_sfeats(fp,sfv)
2168: FILE *fp;
2169: SFv sfv;
2170: { register Pval *vp,*vq;
2171: for(vq=(vp=sfv)+SF_MNY; vp<vq; vp++)
2172: fwri_int3(fp,USHRT_MAX*(*vp)+0.5);
2173: #if dbg_fwrb_toa
2174: /** err("fwrb_sfeats: %s",sfeats_toa(sfv)); **/
2175: #endif
2176: }
2177:
2178: int frdb_sfeats(fp,sfv)
2179: FILE *fp;
2180: SFv sfv;
2181: { register Pval *vp,*vq;
2182: for(vq=(vp=sfv)+SF_MNY; vp<vq; vp++)
2183: *vp = frdi_int3(fp)/((Pval)USHRT_MAX);
2184: #if dbg_frdb_toa
2185: /** err("frdb_sfeats: %s",sfeats_toa(sfv)); **/
2186: #endif
2187: }
2188:
2189: /* return ptr to local static copy of Shapes of given size */
2190: Shapes *alloc_shapes(mny)
2191: int mny;
2192: { static Shapes shs;
2193: shs.mny = shs.alloc = mny;
2194: if((shs.sa=(Nb_s *)malloc(shs.alloc*sizeof(Nb_s)))==NULL)
2195: abort("can't alloc Shapes.sa[%d]",shs.alloc);
2196: return(&shs);
2197: }
2198:
2199: fwrb_shapes(fp,p)
2200: FILE *fp;
2201: Shapes *p; /* on entry, p->mny has already been written */
2202: { int dim;
2203: register Nb_s *sp,*sq;
2204: register Pval *vp;
2205: if(p->mny>0&&p->sa!=NULL) {
2206: for(sq=(sp=p->sa)+p->mny; sp<sq; sp++) {
2207: dim=Sh_dim[sp->t&(~Sh_tiny)];
2208: fwri_uint1(fp,(sp->t&0x7F)|((sp->t&Sh_tiny)?0x80:0x00));
2209: fwri_int2(fp,(*(vp=sp->p))*SHRT_MAX);
2210: if(dim>1) { fwri_int2(fp,(*(++vp))*SHRT_MAX);
2211: if(dim>2) { fwri_int2(fp,(*(++vp))*SHRT_MAX);
2212: if(dim>3) { fwri_int2(fp,(*(++vp))*SHRT_MAX);
2213: } } };
2214: };
2215: };
2216: #if dbg_fwrb_toa
2217: /** err("fwrb_shapes: %s",shapes_toa(p)); **/
2218: #endif
2219: }
2220:
2221: int frdb_shapes(fp,p)
2222: FILE *fp;
2223: Shapes *p; /* on entry, p->mny has already been read */
2224: { register Nb_s *sp,*sq;
2225: register Pval *vp;
2226: uint1 ui1;
2227: int dim;
2228:
2229: if(p->mny>0) {
2230: *p = *alloc_shapes(p->mny);
2231: for(sq=(sp=p->sa)+p->mny; sp<sq; sp++) {
2232: ui1 = frdi_uint1(fp);
2233: sp->t = ui1&0x7F|((ui1&0x80)?Sh_tiny:0);
2234: dim=Sh_dim[sp->t&(~Sh_tiny)];
2235: *(vp=sp->p) = ((float)frdi_int2(fp))/SHRT_MAX;
2236: if(dim>1) { *(++vp) = ((float)frdi_int2(fp))/SHRT_MAX;
2237: if(dim>2) { *(++vp) = ((float)frdi_int2(fp))/SHRT_MAX;
2238: if(dim>3) { *(++vp) = ((float)frdi_int2(fp))/SHRT_MAX;
2239: } } };
2240: };
2241: }
2242: else { p->alloc = 0;
2243: if(p->sa!=NULL) free(p->sa);
2244: p->sa = NULL;
2245: };
2246: #if dbg_frdb_toa
2247: /** err("frdb_shapes: %s",shapes_toa(p)); **/
2248: #endif
2249: }
2250:
2251: fwra_shapes_etc(fp,p,t)
2252: FILE *fp;
2253: Shapes *p;
2254: char *t; /* string of shape types (empty => all) */
2255: { Nb_s *s;
2256: int i,j;
2257: char a[80],f[10];
2258: for(i=0,s=p->sa; i<p->mny; i++,s++) {
2259: if(t[0]=='\0'||strchr(t,Sh_nam[s->t&(~Sh_tiny)])!=NULL) {
2260: sprintf(a,"%c%c ",
2261: Sh_nam[s->t&(~Sh_tiny)],
2262: (s->t&Sh_tiny)?'\'':' '
2263: );
2264: for(j=0;j<Sh_dim[s->t&(~Sh_tiny)];j++) {
2265: sprintf(f," %0.3f",s->p[j]);
2266: strcat(a,f);
2267: };
2268: fprintf(fp,"%s\n",a);
2269: };
2270: };
2271: }
2272:
2273: err_shapes(shp)
2274: Shapes *shp;
2275: { int si,di;
2276: Nb_s *sp;
2277: fprintf(stderr,"shapes %d:\n",shp->mny);
2278: for(si=0,sp=shp->sa; si<shp->mny; si++,sp++) {
2279: fprintf(stderr," %c",Sh_nam[sp->t]);
2280: for(di=0; di<Sh_dim[sp->t]; di++)
2281: fprintf(stderr," %6.3f",sp->p[di]);
2282: fprintf(stderr,"\n");
2283: };
2284: }
2285:
2286: /* Unconditionally free the malloc-space array of pointers, and empty the set.
2287: Don't free the records that it owned.
2288: */
2289: free_shapes(shp)
2290: Shapes *shp;
2291: { if(shp->sa!=NULL) {
2292: if(shp->alloc<=0) abort("can't free unalloc'ed shapes");
2293: else { free(shp->sa); shp->sa=NULL; };
2294: };
2295: shp->mny = shp->alloc = 0;
2296: }
2297:
2298: /* functions for RanParms */
2299:
2300: RanParms *alloc_ranparms()
2301: { RanParms *rp;
2302: if((rp=(RanParms *)malloc(sizeof(RanParms)))==NULL)
2303: abort("alloc_ranparms: can't alloc");
2304: *rp = empty_RanParms;
2305: return(rp);
2306: }
2307:
2308: free_ranparms(ran)
2309: RanParms *ran;
2310: { free(ran);
2311: }
2312:
2313: RanParms *dup_ranparms(p)
2314: RanParms *p;
2315: { RanParms *dup;
2316: dup = alloc_ranparms();
2317: *dup = *p;
2318: return(dup);
2319: }
2320:
2321: char *ranparms_toa(ran,select)
2322: RanParms *ran;
2323: char *select; /* a string, subset of: "*rpabejkstxy" if "*" or "" ALL */
2324: { static char s[200];
2325: char p[20];
2326: char *cp;
2327: static char select_all[] = "abejkprstxy";
2328: s[0]='\0';
2329: if(select[0]=='*'||select[0]=='\0') select=select_all;
2330: for(cp=select; *cp!='\0'; cp++) {
2331: switch(*cp) {
2332: case 'a': sprintf(p,"a%0.3f ",ran->skew/DtoR); strcat(s,p); break;
2333: case 'b': sprintf(p,"b%0.3f ",ran->bhgt); strcat(s,p); break;
2334: case 'e': sprintf(p,"e%0.3f ",ran->blur); strcat(s,p); break;
2335: case 'j': sprintf(p,"j%0.3f ",ran->jitter); strcat(s,p); break;
2336: case 'k': sprintf(p,"k%0.3f ",ran->kern); strcat(s,p); break;
2337: case 'p': sprintf(p,"p%g ",ran->size); strcat(s,p); break;
2338: case 'r': sprintf(p,"r%d,%d ",ran->res_x,ran->res_y); strcat(s,p); break;
2339: case 's': sprintf(p,"s%0.4f ",ran->speckle); strcat(s,p); break;
2340: case 't': sprintf(p,"t%0.3f ",ran->thresh); strcat(s,p); break;
2341: case 'x': sprintf(p,"x%0.3f ",ran->xscale); strcat(s,p); break;
2342: case 'y': sprintf(p,"y%0.3f ",ran->yscale); strcat(s,p); break;
2343: };
2344: };
2345: return(s);
2346: }
2347:
2348: RanParms *ato_ranparms(s)
2349: char *s;
2350: { static RanParms ran;
2351: char *f,n,*v;
2352: #define TOKEN_SEP "=, \n"
2353: f=strtok(s,TOKEN_SEP);
2354: while(f!=NULL&&strlen(f)>0) {
2355: n=f[0]; v=f+1;
2356: switch(n) {
2357: case 'r': /* res */
2358: ran.res_x = atoi(v);
2359: v=strtok((char *)0,TOKEN_SEP);
2360: ran.res_y = atoi(v);
2361: break;
2362: case 'p': ran.size = atof(v); break;
2363: case 'a': ran.skew = atof(v)*DtoR; break;
2364: case 'b': ran.bhgt = atof(v); break;
2365: case 'e': ran.blur = atof(v); break;
2366: case 'j': ran.jitter = atof(v); break;
2367: case 'k': ran.kern = atof(v); break;
2368: case 's': ran.speckle = atof(v); break;
2369: case 't': ran.thresh = atof(v); break;
2370: case 'x': ran.xscale = atof(v); break;
2371: case 'y': ran.yscale = atof(v); break;
2372: };
2373: f=strtok((char *)0,TOKEN_SEP);
2374: };
2375: return(&ran);
2376: }
2377:
2378: #if FWRI
2379: fwrb_ranparms(f,p)
2380: FILE *f;
2381: RanParms *p;
2382: { fwri_int2(f,p->res_x);
2383: fwri_int2(f,p->res_y);
2384: fwri_Pts(f,p->size);
2385: fwri_Radians(f,p->skew);
2386: fwri_Ems(f,p->bhgt);
2387: fwri_int3(f,p->blur*10000.0);
2388: fwri_int3(f,p->jitter*10000.0);
2389: fwri_int3(f,p->kern*10000.0);
2390: fwri_int3(f,p->speckle*10000.0);
2391: fwri_int3(f,p->thresh*10000.0);
2392: fwri_int3(f,p->xscale*10000.0);
2393: fwri_int3(f,p->yscale*10000.0);
2394: #if dbg_fwrb_toa
2395: err("fwrb_ranparms: %s",ranparms_toa(p));
2396: #endif
2397: }
2398: #else
2399: fwrb_ranparms(f,p)
2400: FILE *f;
2401: RanParms *p;
2402: { if((fwrite(p,sizeof(RanParms),1,f))!=1) return(0);
2403: #if dbg_fwrb_toa
2404: err("fwrb_ranparms: %s",ranparms_toa(p));
2405: #endif
2406: }
2407: #endif
2408:
2409: #if FRDI
2410: int frdb_ranparms(f,p)
2411: FILE *f;
2412: RanParms *p;
2413: { *p = empty_RanParms;
2414: if(feof(f))
2415: return(0);
2416: p->res_x=frdi_int2(f);
2417: p->res_y=frdi_int2(f);
2418: p->size=frdi_Pts(f);
2419: p->skew=frdi_Radians(f);
2420: p->bhgt=frdi_Ems(f);
2421: p->blur=frdi_int3(f)/10000.0;
2422: p->jitter=frdi_int3(f)/10000.0;
2423: p->kern=frdi_int3(f)/10000.0;
2424: p->speckle=frdi_int3(f)/10000.0;
2425: p->thresh=frdi_int3(f)/10000.0;
2426: p->xscale=frdi_int3(f)/10000.0;
2427: p->yscale=frdi_int3(f)/10000.0;
2428: #if dbg_frdb_toa
2429: err("frdb_ranparms: %s",ranparms_toa(p));
2430: #endif
2431: if(ferror(f)) return(-errno); else return(1);
2432: }
2433: #else
2434: int frdb_ranparms(fp,ran)
2435: FILE *fp;
2436: RanParms *ran;
2437: { if((fread(ran,sizeof(RanParms),1,fp))<1) return(0);
2438: #if dbg_frdb_toa
2439: err("frdb_ranparms: %s",ranparms_toa(ran));
2440: #endif
2441: }
2442: #endif
2443:
2444: Char *alloc_char()
2445: { Char *p;
2446: if((p=(Char *)malloc(sizeof(Char)))==NULL)
2447: abort("can't alloc Char");
2448: alloc_census(Char,1);
2449: *p = empty_Char;
2450: return(p);
2451: }
2452:
2453: char *char_toa(cp)
2454: Char *cp;
2455: { static char s[100],bfs[24];
2456: if(cp->bfsp==NULL) strcpy(bfs,"0");
2457: else if(cp->bfsp->bm.n==0) strcpy(bfs,"0");
2458: else if(cp->bfsp->bm.mny==0) sprintf(bfs,"%d",cp->bfsp->bm.n);
2459: else sprintf(bfs,"%d,%d",cp->bfsp->bm.n,cp->bfsp->bm.mny);
2460: sprintf(s,"%s bx%s w%d,h%d cs%d bl%d ar%d pe%d sf%d sh%d bf%s i%d",
2461: ident_toa(cp->ident),
2462: bbx_toa(&(cp->bx)),
2463: bbx_wid(&cp->bx),bbx_hgt(&cp->bx),
2464: cp->csp,
2465: cp->bmny,
2466: cp->area,cp->per,
2467: (cp->sfv==NULL)? 0: 1,
2468: cp->sh.mny,
2469: bfs,
2470: cp->il.mny
2471: );
2472: return(s);
2473: }
2474:
2475: /* compute the centroid of the Char (offset from bx.a) */
2476: Pp *char_centroid(cp)
2477: Char *cp;
2478: { static Pp c;
2479: Pp *bc; /* blob centroid */
2480: Blob *bp;
2481: int bi;
2482: c.x = c.y = 0.0;
2483: for(bi=0, bp=cp->fi; bi<cp->bmny; bi++, bp=bp->n) {
2484: bc = blob_centroid(bp);
2485: c.x += bp->area * (bc->x + (cp->bx.a.x - cp->bx.a.x));
2486: c.y += bp->area * (bc->y + (cp->bx.a.y - cp->bx.a.y));
2487: };
2488: c.x /= cp->area;
2489: c.y /= cp->area;
2490: return(&c);
2491: }
2492:
2493: #if FWRI
2494: fwrb_char(f,p)
2495: FILE *f;
2496: Char *p;
2497: {
2498: #if dbg_fwrb
2499: if((!(p->ident&IsChar))||(p->ident&(IsALL&(~IsChar))))
2500: err("fwrb_char: %s",char_toa(p));
2501: if(p->ident&Char_label && p->l==NULL) {
2502: err("fwrb_page: Char_label set but .l==NULL");
2503: p->ident &= ~Char_label;
2504: };
2505: if(p->ident&Char_ranparms && p->rp==NULL) {
2506: err("fwrb_page: Char_ranparms set but .rp==NULL");
2507: p->ident &= ~Char_ranparms;
2508: };
2509: #endif
2510: fwri_Ident(f,p->ident);
2511: fwri_Bbx(f,&(p->bx));
2512: fwri_Scoor(f,p->csp);
2513: fwri_uint4(f,p->area);
2514: fwri_uint4(f,p->per);
2515: fwri_Scoor(f,p->basl);
2516: fwri_uint3(f,p->bmny);
2517: fwri_uint2(f,p->il.mny);
2518: fwri_uint1(f,(p->sfv!=NULL)?SF_MNY:0);
2519: fwri_uint2(f,p->sh.mny);
2520: fwri_uint2(f,(p->bfsp!=NULL)?p->bfsp->bm.n:0);
2521: #if dbg_fwrb_toa
2522: err("fwrb_char: %s",char_toa(p));
2523: #endif
2524: if(p->ident&Char_label) fwrb_label(f,p->l);
2525: if(p->ident&Char_ranparms) fwrb_ranparms(f,p->rp);
2526: }
2527: #else
2528: fwrb_char(fp,cp)
2529: FILE *fp;
2530: Char *cp;
2531: { CharF cf;
2532: int stat;
2533: #if dbg_fwrb
2534: if((!(cp->ident&IsChar))||(cp->ident&(IsALL&(~IsChar))))
2535: err("fwrb_char: %s",char_toa(cp));
2536: #endif
2537: memset(&cf,'\0',sizeof(cf));
2538: if(cp->ident&Char_ranparms && cp->rp==NULL)
2539: cp->ident &= ~Char_ranparms;
2540: cf.ident = cp->ident | IsChar;
2541: cf.bx = cp->bx;
2542: cf.csp = cp->csp;
2543: cf.area = cp->area;
2544: cf.per = cp->per;
2545: /* basl omitted */
2546: cf.bmny = cp->bmny;
2547: cf.imny = cp->il.mny;
2548: cf.sfmny = (cp->sfv!=NULL)?SF_MNY:0;
2549: cf.shmny = cp->sh.mny;
2550: if(cp->bfsp!=NULL) cf.bfmny = cp->bfsp->bm.n; else cf.bfmny=0;
2551: if((stat=fwrite(&cf,sizeof(CharF),1,fp))!=1)
2552: abort("can't write CharF, status %d",stat);
2553: #if dbg_fwrb_toa
2554: err("fwrb_char: %s",char_toa(cp));
2555: #endif
2556: if(cf.ident&Char_ranparms) fwrb_ranparms(fp,cp->rp);
2557: if(cf.ident&Char_label) fwrb_label(fp,cp->l);
2558: }
2559: #endif
2560:
2561: fwrb_chars_etc(fp,cs,etc)
2562: FILE *fp;
2563: Chars cs;
2564: Ident etc;
2565: { register Char *cp,**cpp;
2566: if(cs.mny>0) for(cp= *(cpp=cs.cpa); cp!=NULL; cp= *(++cpp))
2567: fwrb_char_etc(fp,cp,etc);
2568: }
2569:
2570: fwrb_char_etc(fp,cp,etc)
2571: FILE *fp;
2572: Char *cp;
2573: Ident etc;
2574: { static Ident parts = (IsInterp|IsBlob|IsShapes|IsBfeats|IsSfeats);
2575: Char ch;
2576: if((etc&parts)!=parts) /* write selected parts */ {
2577: ch = *cp;
2578: if(!(etc&IsInterp)) ch.il.mny=0;
2579: if(!(etc&IsBlob)) ch.bmny=0;
2580: if(!(etc&IsSfeats)) ch.sfv = NULL;
2581: if(!(etc&IsShapes)) ch.sh = empty_Shapes;
2582: if(!(etc&IsBfeats)) ch.bfsp = NULL;
2583: cp = &ch; /* write modified record */
2584: };
2585: fwrb_char(fp,cp);
2586: if(cp->sfv!=NULL) fwrb_sfeats(fp,cp->sfv);
2587: if(cp->sh.mny>0) fwrb_shapes(fp,&(cp->sh));
2588: #if CPU!=CRAY
2589: if(cp->bfsp!=NULL) fwrb_bfeats(fp,cp->bfsp);
2590: #endif
2591: fwrb_interpl_etc(fp,cp->il,etc);
2592: if(cp->bmny>0) fwrb_blobl_etc(fp,cp->bmny,cp->fi,etc);
2593: }
2594:
2595: #if FRDI
2596: int frdb_char(f,p)
2597: FILE *f;
2598: Char *p;
2599: { int sf_mny,bf_mny;
2600: *p = empty_Char;
2601: if(feof(f))
2602: return(0);
2603: p->ident=frdi_Ident(f);
2604: frdi_Bbx(f,&(p->bx));
2605: p->csp=frdi_Scoor(f);
2606: p->area=frdi_uint4(f);
2607: p->per=frdi_uint4(f);
2608: p->basl=frdi_Scoor(f);
2609: p->bmny=frdi_uint3(f);
2610: p->il.mny=frdi_uint2(f);
2611: if((sf_mny=frdi_uint1(f))>0) {
2612: if((p->sfv=(Pval *)malloc(sf_mny*sizeof(Pval)))==NULL)
2613: abort("frdb_char: can't alloc p->sfv[%d]",sf_mny);
2614: memset(p->sfv,'\0',sf_mny*sizeof(Pval));
2615: };
2616: p->sh.mny=frdi_uint2(f);
2617: if((bf_mny=frdi_uint2(f))>0) {
2618: p->bfsp = alloc_bfeats(bf_mny,0);
2619: };
2620: #if dbg_frdb
2621: if((!(p->ident&IsChar))||(p->ident&(IsALL&(~IsChar))))
2622: err("frdb_char: %s",char_toa(p));
2623: #endif
2624: #if dbg_frdb_toa
2625: err("frdb_char: %s",char_toa(p));
2626: #endif
2627: if(p->ident&Char_label) p->l = frdb_label(f);
2628: if(p->ident&Char_ranparms) {
2629: p->rp = alloc_ranparms();
2630: frdb_ranparms(f,p->rp);
2631: };
2632: if(ferror(f)) return(-errno); else return(1);
2633: }
2634: #else
2635: int frdb_char(fp,cp)
2636: FILE *fp;
2637: Char *cp;
2638: { CharF cf;
2639: int stat;
2640: if((stat=fread(&cf,sizeof(CharF),1,fp))!=1)
2641: abort("frdb_char: can't read CharF, status %d",stat);
2642: *cp = empty_Char;
2643: cp->ident = cf.ident;
2644: cp->bx = cf.bx;
2645: cp->csp = cf.csp;
2646: cp->area = cf.area;
2647: cp->per = cf.per;
2648: cp->basl = 0;
2649: cp->bmny = cf.bmny;
2650: cp->il.mny = cf.imny;
2651: if(cf.sfmny>0) {
2652: if((cp->sfv=(Pval *)malloc(SF_MNY*sizeof(Pval)))==NULL)
2653: abort("frdb_char: can't alloc cp->sfv[%d]",SF_MNY);
2654: memset(cp->sfv,'\0',SF_MNY*sizeof(Pval));
2655: }
2656: else cp->sfv = NULL;
2657: cp->sh.mny = cf.shmny;
2658: #if CPU!=CRAY
2659: #if dbg_frdb
2660: if((!(cp->ident&IsChar))||(cp->ident&(IsALL&(~IsChar))))
2661: err("frdb_char: %s",char_toa(cp));
2662: #endif
2663: #endif
2664: #if dbg_frdb_toa
2665: err("frdb_char: %s",char_toa(cp));
2666: #endif
2667: if(cp->ident&Char_ranparms) {
2668: cp->rp = alloc_ranparms();
2669: frdb_ranparms(fp,cp->rp);
2670: };
2671: if(cp->ident&Char_label) cp->l = frdb_label(fp);
2672: #if CPU!=CRAY
2673: if(cf.bfmny>0) cp->bfsp = alloc_bfeats(cf.bfmny,0);
2674: else
2675: #endif
2676: cp->bfsp = NULL;
2677: if(ferror(fp)) return(-errno); else return(1);
2678: }
2679: #endif
2680:
2681: frdb_char_etc(fp,cp,etc)
2682: FILE *fp;
2683: Char *cp;
2684: Ident etc;
2685: { frdb_char(fp,cp);
2686: if(cp->sfv!=NULL) frdb_sfeats(fp,cp->sfv);
2687: if(cp->sh.mny>0) frdb_shapes(fp,&(cp->sh));
2688: #if CPU!=CRAY
2689: if(cp->bfsp!=NULL) {
2690: frdb_bfeats(fp,cp->bfsp);
2691: };
2692: #endif
2693: if(cp->il.mny>0) {
2694: frdb_interpl_etc(fp,&(cp->il),etc);
2695: /**if(!(etc&IsInterp)) free_interpl_etc(&(cp->il),IsALL);**/
2696: };
2697: if(etc&IsBlob && cp->bmny>0)
2698: frdb_blobl_etc(fp,cp->bmny,&(cp->fi),etc);
2699: else { cp->bmny = 0; cp->fi = NULL; };
2700: if(ferror(fp)) return(-errno); else return(1);
2701: }
2702:
2703: /* read a set of chars, and parts */
2704: frdb_chars_etc(fp,csp,etc)
2705: FILE *fp;
2706: Chars *csp;
2707: Ident etc;
2708: { int ci;
2709: register Char *cp,**cpp;
2710: if(csp->mny<=0) {
2711: *csp = empty_Chars;
2712: return(1);
2713: };
2714: if((cpp=csp->cpa=(Char **)malloc((csp->mny+1)*sizeof(Char *)))==NULL)
2715: abort("frdb_chars_etc: can't alloc Chars.cpa array");
2716: for(ci=0; ci<csp->mny; ci++) {
2717: *(cpp++) = cp = alloc_char();
2718: frdb_char_etc(fp,cp,etc);
2719: };
2720: *cpp = NULL;
2721: if(ferror(fp)) return(-errno); else return(1);
2722: }
2723:
2724: /* return a pointer to a distinct and duplicate copy of *cp;
2725: it is created out of malloc space.
2726: RanParms & label are treated as an integral part of the Char. */
2727: Char *dup_char(cp)
2728: Char *cp;
2729: { Char *dup;
2730: if((dup=(Char *)malloc(sizeof(Char)))==NULL)
2731: abort("can't dup Char");
2732: alloc_census(Char,1);
2733: *dup = *cp;
2734: if(dup->ident&Char_label && dup->l!=NULL)
2735: dup->l = strdup(cp->l);
2736: else {dup->ident &= ~Char_label; dup->l = NULL;};
2737: if(dup->ident&Char_ranparms && dup->rp!=NULL)
2738: dup->rp = dup_ranparms(cp->rp);
2739: else {dup->ident &= ~Char_ranparms; dup->rp = NULL;};
2740: return(dup);
2741: }
2742:
2743: /* return a pointer to a distinct and duplicate copy of *cp and those of
2744: its lists as specified by etc. (Does not conform to practice for dup_word_etc.)
2745: */
2746: Char *dup_char_etc(cp,etc)
2747: Char *cp;
2748: Ident etc;
2749: { Char *dup;
2750: dup = dup_char(cp);
2751: if(dup->bmny>0&&etc&IsBlob) dup->fi = dup_blobl_etc(cp->fi,etc);
2752: else {dup->bmny=0; dup->fi=NULL;};
2753: if(dup->il.mny>0&&etc&IsInterp) dup->il = *dup_interpl_etc(&(cp->il),etc);
2754: else dup->il = empty_Interpl;
2755: /**
2756: if(dup->sfv!=NULL>0&&etc&IsSfeats) dup->sfv = dup_sfeats(cp->sfv);
2757: else dup->sfv = NULL;
2758: if(dup->sh.mny>0&&etc&IsShapes) dup->sh = *dup_shapes(&cp->sh);
2759: else dup->sh = empty_Shapes;
2760: **/
2761: #if CPU!=CRAY
2762: if(dup->bfsp!=NULL>0&&etc&IsBfeats) dup->bfsp = dup_bfeats(cp->bfsp);
2763: else
2764: #endif
2765: dup->bfsp = NULL;
2766: return(dup);
2767: }
2768:
2769: /* Return a pointer to a local static duplicate of non-empty *csp.
2770: Its cpa array is new, created out of malloc space.
2771: If etc&IsChar, all its Characters are also duplicated,
2772: else the contents of cpa point to the old unduplicated Chars.
2773: */
2774: Chars *dup_chars_etc(csp,etc)
2775: Chars *csp;
2776: Ident etc; /* parts to duplicate */
2777: { static Chars dup;
2778: register Char **cpp,**dpp;
2779: if((dup.mny=csp->mny)<=0) dup = empty_Chars;
2780: else { if((dup.cpa=(Char **)malloc((dup.mny+1)*sizeof(Char *)))==NULL)
2781: abort("can't dup cs.cpa");
2782: for(cpp=csp->cpa,dpp=dup.cpa; (*cpp)!=NULL; cpp++,dpp++) {
2783: if(etc&IsChar) *dpp = dup_char_etc(*cpp,etc);
2784: else *dpp = *cpp;
2785: };
2786: *dpp = NULL;
2787: };
2788: return(&dup);
2789: }
2790:
2791: err_chars(p)
2792: Chars *p;
2793: { register Char **cpp;
2794: fprintf(stderr,"Chars %d: ",p->mny);
2795: if(p->mny>0) for(cpp=p->cpa; (*cpp)!=NULL; cpp++)
2796: fprintf(stderr,"%X ",*cpp);
2797: fprintf(stderr,"\n");
2798: }
2799:
2800: /* Make a Char out of a single Blob. Return a freshly-allocated Char
2801: that owns the given Blob as is (not duplicated, copied or freed).
2802: The Blob's next pointer is set to NULL. */
2803: Char *char_of_blob(b)
2804: Blob *b;
2805: { Char *c;
2806: c=alloc_char();
2807: c->bx = b->bx;
2808: c->area = b->area;
2809: c->per = b->per;
2810: c->bmny = 1;
2811: c->fi = b;
2812: b->n = NULL;
2813: return(c);
2814: }
2815:
2816: Interp *alloc_interp()
2817: { Interp *new;
2818: if((new=(Interp *)malloc(sizeof(Interp)))==NULL)
2819: abort("alloc_interp: can't malloc");
2820: alloc_census(Interp,1);
2821: *new = empty_Interp;
2822: return(new);
2823: }
2824:
2825: Interp *dup_interp(ip)
2826: Interp *ip;
2827: { Interp *dup;
2828: if((dup=(Interp *)malloc(sizeof(Interp)))==NULL)
2829: abort("dup_interp: can't malloc");
2830: alloc_census(Interp,1);
2831: *dup = *ip;
2832: return(dup);
2833: }
2834:
2835: /* Print the interpl */
2836: fwra_interpl(fp,ilp)
2837: FILE *fp;
2838: Interpl *ilp;
2839: { register Interp *cp;
2840: fprintf(fp,"Interpl[%d] ",ilp->mny);
2841: for(cp=ilp->fi; cp!=NULL; cp=cp->n) {
2842: fprintf(fp," %s --",interp_toa(cp));
2843: };
2844: fprintf(fp,"\n");
2845: }
2846:
2847: /* Print the interpl very briefly */
2848: fwra_interpl_brief(fp,ilp)
2849: FILE *fp;
2850: Interpl *ilp;
2851: { register Interp *ip;
2852: for(ip=ilp->fi; ip!=NULL; ip=ip->n) {
2853: fprintf(fp,"%s %s ",ip->ci.c,merit_toa(ip->m));
2854: };
2855: fprintf(fp,"\n");
2856: }
2857:
2858: err_interpl(ilp)
2859: Interpl *ilp;
2860: { fwra_interpl(stderr,ilp);
2861: }
2862:
2863: /* return the address of a local static copy of the given Interpl,
2864: for which each Interp is a duplicate of those in the given list */
2865: Interpl *dup_interpl_etc(ilp,etc)
2866: Interpl *ilp;
2867: Ident etc;
2868: { static Interpl lis;
2869: register Interp *cp,*pp,*dp;
2870: lis = *ilp;
2871: if(ilp->fi==NULL) return(NULL);
2872: for(pp=NULL,cp=ilp->fi; cp!=NULL; pp=dp,cp=cp->n) {
2873: dp=dup_interp(cp);
2874: if(pp==NULL) lis.fi = dp;
2875: else pp->n = dp;
2876: };
2877: pp->n=NULL;
2878: return(&lis);
2879: }
2880:
2881: /* Return a pointer to a local static duplicate of *isp.
2882: Its pa array is new, created out of malloc space.
2883: If etc&IsInterp, all its Interps are also duplicated,
2884: else the contents of pa point to the old unduplicated Interps.
2885: */
2886: Interps *dup_interps_etc(isp,etc)
2887: Interps *isp;
2888: Ident etc; /* parts to duplicate */
2889: { static Interps dup;
2890: register Interp **ipp,**dpp;
2891: dup = *isp;
2892: if(dup.mny<=0) dup = empty_Interps;
2893: else { if((dup.pa=(Interp **)malloc((dup.mny+1)*sizeof(Interp *)))==NULL)
2894: abort("can't dup (Interp *)is.pa[%d]",(dup.mny+1));
2895: for(ipp=isp->pa,dpp=dup.pa; *ipp!=NULL; ipp++,dpp++) {
2896: if(etc&IsInterp) *dpp = dup_interp(*ipp);
2897: else *dpp = *ipp;
2898: };
2899: *dpp = NULL;
2900: };
2901: return(&dup);
2902: }
2903:
2904: free_interps_etc(isp,etc)
2905: Interps *isp;
2906: Ident etc; /* parts to free */
2907: { register Interp **ipp,**dpp;
2908: if(etc&IsInterp) {
2909: /* free contents */
2910: for(ipp=isp->pa; *ipp!=NULL; ipp++) free_interp(*ipp);
2911: };
2912: if(isp->pa!=NULL) { free(isp->pa); isp->pa = NULL; };
2913: isp->mny = 0;
2914: }
2915:
2916: /* remove a char from a chars set */
2917: remove_char(cp,csp)
2918: Char *cp;
2919: Chars *csp;
2920: { register Char *rp,**rpp,**npp;
2921: if(csp->mny==0) err("remove_char: can't - Chars empty");
2922: else { for(rp= *(rpp=csp->cpa); rp!=NULL; rp= *(++rpp)) if(rp==cp) break;
2923: if(rp==NULL) err("remove_char: can't - not found");
2924: else { /* move later entries up */
2925: npp=rpp+1;
2926: do *(rpp++)= *(npp++); while ((*rpp)!=NULL);
2927: if((--(csp->mny))==0) {free(csp->cpa); csp->cpa=NULL;};
2928: /* don't bother to realloc downwards */
2929: };
2930: };
2931: }
2932:
2933: /* Append a char to the end of a chars set.
2934: Do NOT attempt to maintain Chars in order sorted ascending on Char.bx.a.x.
2935: Return appended Char *. */
2936: Char *append_char(cp,csp)
2937: Char *cp;
2938: Chars *csp;
2939: { register Char *rp,**rpp,**npp;
2940: if(csp->mny==0) {
2941: if((csp->cpa=(Char **)malloc(2*sizeof(Char *)))==NULL)
2942: abort("append_char: can't malloc csp->cpa[%d]",2);
2943: }
2944: else { if((csp->cpa=(Char **)realloc(
2945: csp->cpa,
2946: (csp->mny+2)*sizeof(Char *))
2947: )==NULL)
2948: abort("append_char: can't realloc csp->cpa[%d]",
2949: (csp->mny+2));
2950: };
2951: csp->cpa[csp->mny] = cp;
2952: csp->cpa[++csp->mny] = NULL;
2953: return(cp);
2954: }
2955:
2956: /* Insert a Char into a Chars set. Chars is assumed to be sorted ascending
2957: on on Char.bx.a.x, and this order is maintained.
2958: Return inserted Char * */
2959: Char *insert_char(cp,csp)
2960: Char *cp;
2961: Chars *csp;
2962: { register Char **cpp,*ncp,*pcp;
2963: if(csp->mny==0) {
2964: if((csp->cpa=(Char **)malloc(2*sizeof(Char *)))==NULL)
2965: abort("insert_char: can't malloc csp->cpa[%d]",2);
2966: csp->cpa[csp->mny] = cp;
2967: }
2968: else { if((cpp=csp->cpa=(Char **)realloc(
2969: csp->cpa,
2970: (csp->mny+2)*sizeof(Char *))
2971: )==NULL)
2972: abort("insert_char: can't realloc csp->cpa[%d]",csp->mny+2);
2973: while(((*cpp)!=NULL)&&(*cpp)->bx.a.x<cp->bx.a.x) cpp++;
2974: /* **cpp is now 1st entry >= *cp in sorted order */
2975: pcp=cp;
2976: do { ncp= *cpp;
2977: *(cpp++)=pcp;
2978: pcp=ncp;
2979: }
2980: while(pcp!=NULL);
2981: };
2982: csp->cpa[++csp->mny] = NULL;
2983: return(cp);
2984: }
2985:
2986: /* Append the contents of a "source" chars set to a "destination" chars set.
2987: Merely copy (Char *) pointers: don't duplicate Chars.
2988: Do NOT attempt to maintain Chars in order sorted ascending on Char.bx.a.x.
2989: Return destination (Chars *). */
2990: Chars *append_chars(s,d)
2991: Chars *s; /* source */
2992: Chars *d; /* destination */
2993: { register Char *rp,**rpp,**npp;
2994: if(s->mny==0) return(d);
2995: if(d->mny==0) {
2996: if((d->cpa=(Char **)malloc((s->mny+1)*sizeof(Char *)))==NULL)
2997: abort("append_chars: can't malloc d->cpa[%d]",2);
2998: }
2999: else { if((d->cpa=(Char **)realloc(
3000: d->cpa,
3001: (d->mny+s->mny+1)*sizeof(Char *))
3002: )==NULL)
3003: abort("append_chars: can't realloc d->cpa[%d]",
3004: (d->mny+s->mny+1));
3005: };
3006: memcpy(d->cpa+d->mny,s->cpa,(s->mny+1)*sizeof(Char *));
3007: d->mny += s->mny;
3008: return(d);
3009: }
3010:
3011: /* Insert a Char into the Chars owned by a given Word,
3012: maintaining order in set, and updating the Word's bx */
3013: Char *insert_char_word(cp,wp)
3014: Char *cp;
3015: Word *wp;
3016: { merge_bbx(&(cp->bx),&(wp->bx));
3017: return(insert_char(cp,&(wp->cs)));
3018: }
3019:
3020: free_char_etc(p,etc)
3021: Char *p; /* !=NULL */
3022: Ident etc;
3023: { if(etc&IsBlob) free_blobl_etc(&(p->bmny),&(p->fi),etc);
3024: if(etc&IsInterp) free_interpl(&(p->il));
3025: if(etc&IsSfeats && p->sfv!=NULL) { free(p->sfv); p->sfv=NULL; };
3026: if(etc&IsShapes) free_shapes(&(p->sh));
3027: #if CPU!=CRAY
3028: if(etc&IsBfeats && p->bfsp!=NULL) { free_bfeats(p->bfsp); p->bfsp=NULL; };
3029: #endif
3030: if(etc&IsChar) {
3031: if(p->ident&Char_label && p->l!=NULL) {
3032: free(p->l); p->l=NULL;
3033: p->ident &= ~Char_label;
3034: };
3035: if(p->ident&Char_ranparms && p->rp!=NULL) {
3036: free_ranparms(p->rp); p->rp=NULL;
3037: p->ident &= ~Char_ranparms;
3038: };
3039: free(p);
3040: free_census(Char,1);
3041: };
3042: }
3043:
3044: /* Unconditionally free the malloc-space array of pointers, and empty the set.
3045: Don't free the records that it owned.
3046: */
3047: free_chars(csp)
3048: Chars *csp;
3049: { if(csp->cpa!=NULL) { free(csp->cpa); csp->cpa = NULL; }
3050: csp->mny = 0;
3051: }
3052:
3053: free_chars_etc(csp,etc)
3054: Chars *csp;
3055: Ident etc;
3056: { register Char *cp,**cpp;
3057: if(csp->mny>0&&(etc&IsChar))
3058: for(cp= *(cpp=csp->cpa); cp!=NULL; cp= *(++cpp))
3059: free_char_etc(cp,etc);
3060: free_chars(csp);
3061: }
3062:
3063: /** Blob handling:
3064: alloc_blob_pool(sz,debug) - create pool of free blob records
3065: free_blob_pool() - free the pool
3066: Blob *alloc_blob() - allocate a new blob (in pool)
3067: free_blob(bp) - free a specified blob
3068: free_blob_runs(bp) - free a blob & the runs in its blob set
3069: free_blobl_etc(int *,Blob **,etc) - free blobs etc in char's blob list
3070: out_blob(bp) - print (ascii) to stdout
3071: fwrb_blob(fp,bp) - write binary Blob (only) to fp
3072: fwrb_blob_etc(fp,bp,etc) - write binary Blob & specified parts to fp
3073: frdb_blob_etc(fp,bp,etc) - read binary Blob & parts in specified form
3074: frdb_runfs(fp,bp,max) - read *bp's (binary) RunF's from fp
3075: err_blob(s,bp) - print (ascii) to stderr
3076: err_blob_runs(s,bp) - print Blob & its Runs (ascii) to stderr
3077: err_blob_runfs(s,bp) - print Blob & its RunFs (ascii) to stderr
3078: err_blob_briefly(s,bp) - print (ascii) to stderr
3079: err_blobf(s,bp) - print file-format blob (ascii) to stderr
3080: err_blob_stats() - report blob statistics
3081: blob_small(bp) - test whether its runs' data can be compressed to chars
3082: BUGS
3083: most fread/fwrite/fseek should be read/write/lseek, for speed
3084: -- but how to choose?
3085: **/
3086:
3087: /* make (empty) pool of `size' Blobs (return F if can't allocate) */
3088: boolean alloc_blob_pool(size,dbg)
3089: int size;
3090: boolean dbg;
3091: { register Blob *cbp, *cbq, *pbp;
3092: blob_max=size;
3093: if((blob_pool=(Blob *)malloc(blob_max*sizeof(Blob)))==NULL) return(F);
3094: blob_debug = dbg;
3095: pbp= &blob_fr;
3096: /* link up all blobs into free list using only first-ptrs */
3097: for(cbq=(cbp=blob_pool)+blob_max; cbp<cbq; cbp++) {
3098: pbp->n = cbp;
3099: pbp = cbp;
3100: };
3101: pbp->n = NULL; /* marks end of free list */
3102: blob_fr_mny = blob_max; blob_hi=0; blob_chopped = 0;
3103: hi_blob_no = 0;
3104: return(T);
3105: }
3106:
3107: free_blob_pool()
3108: { free(blob_pool);
3109: }
3110:
3111: Blob *alloc_blob()
3112: { Blob *p;
3113: if((p=(Blob *)malloc(sizeof(Blob)))==NULL)
3114: abort("alloc_blob: can't");
3115: alloc_census(Blob,1);
3116: *p = empty_Blob;
3117: return(p);
3118: }
3119:
3120: /* Unconditionally free this Blob record. */
3121: free_blob(bp)
3122: Blob *bp;
3123: { free(bp);
3124: free_census(Blob,1);
3125: }
3126:
3127: /* Allocate new Blob record and assign to it the next blob no */
3128: Blob *alloc_pool_blob()
3129: { register Blob *bp;
3130: if((bp = blob_fr.n)==NULL) {
3131: err("too many alloc_blob() calls - aborting:");
3132: #ifdef STATS
3133: err_blob_stats();
3134: #endif
3135: exit(1);
3136: };
3137: blob_fr.n = bp->n;
3138: #ifdef STATS
3139: blob_fr_mny--;
3140: if(blob_hi<(blob_max-blob_fr_mny)) blob_hi = blob_max-blob_fr_mny;
3141: #endif
3142: bp->no = hi_blob_no++;
3143: return(bp);
3144: }
3145:
3146: free_pool_blob(bp)
3147: Blob *bp;
3148: {
3149: if(blob_debug&&bp==NULL) abort("free_pool_blob: can't free a NULL Blob");
3150: #ifdef STATS
3151: blob_fr_mny++;
3152: if(blob_debug&&(blob_fr_mny>blob_max)) {
3153: err("free_pool_blob: too many free_blob() calls - aborting:");
3154: #ifdef STATS
3155: err_blob_stats();
3156: #endif
3157: exit(1);
3158: };
3159: #endif
3160: bp->n = blob_fr.n;
3161: blob_fr.n = bp;
3162: }
3163:
3164: /* free the runs belonging to this blob */
3165: free_runs(bp)
3166: Blob *bp;
3167: { register Run *crp,*nrp;
3168: if(bp->ident&Runs_ff) {
3169: if(bp->r.ff!=NULL) free(bp->r.ff);
3170: bp->r.ff=NULL;
3171: }
3172: else if(bp->ident&Runs_f) {
3173: for(crp=bp->r.f; crp!=NULL; crp=nrp) {
3174: nrp=crp->n;
3175: free_run(crp);
3176: };
3177: }
3178: else if(bp->ident&Runs_seek) /* none to free */ ;
3179: }
3180:
3181: /* free blob *bp and those parts (runs) specified */
3182: free_blob_etc(bp,etc)
3183: Blob *bp;
3184: Ident etc;
3185: { if(etc&IsRun) free_runs(bp);
3186: if(etc&IsBlob) free_blob(bp);
3187: }
3188:
3189: /* return a pointer to a distinct and duplicate copy of *bp;
3190: it is created out of malloc space */
3191: Blob *dup_blob(bp)
3192: Blob *bp;
3193: { Blob *dup;
3194: if((dup=(Blob *)malloc(sizeof(Blob)))==NULL)
3195: abort("dup_blob: can't malloc");
3196: alloc_census(Blob,1);
3197: *dup = *bp;
3198: return(dup);
3199: }
3200:
3201: /* return a pointer to a distinct and duplicate copy of *bp and what it owns,
3202: as described by etc; created out of malloc space */
3203: Blob *dup_blob_etc(bp,etc)
3204: Blob *bp;
3205: Ident etc;
3206: { Blob *dup;
3207: dup = dup_blob(bp);
3208: if(bp->runs>0) {
3209: if(bp->ident&Runs_ff) {
3210: int ri;
3211: RunF *rp,*drp;
3212: if((dup->r.ff=
3213: (RunF *)malloc(bp->runs*sizeof(RunF)))==NULL)
3214: abort("dup_blob_etc: can't malloc RunF[%d]",
3215: bp->runs);
3216: for(ri=0,rp=bp->r.ff,drp=dup->r.ff; ri<bp->runs; ri++)
3217: *(drp++) = *(rp++);
3218: }
3219: else abort("dup_blob_etc: only Runs_ff implemented");
3220: };
3221: return(dup);
3222: }
3223:
3224: /* Return a pointer to a local static duplicate of non-empty *bsp.
3225: Its bpa array is created newly out of malloc space.
3226: If etc&IsBlob, all its Blobs are also fresh duplicates,
3227: else the contents of bpa point to the old unduplicated Blobs.
3228: */
3229: Blobs *dup_blobs_etc(bsp,etc)
3230: Blobs *bsp;
3231: Ident etc; /* parts to duplicate */
3232: { static Blobs dup;
3233: register Blob **bpp,**dpp;
3234: if((dup.mny = bsp->mny)<=0) dup = empty_Blobs;
3235: else { if((dup.bpa=(Blob **)malloc((dup.mny+1)*sizeof(Blob *)))==NULL)
3236: abort("dup_blobs_etc: can't malloc bs.bpa[%d]",dup.mny+1);
3237: for(bpp=bsp->bpa,dpp=dup.bpa; *bpp!=NULL; bpp++,dpp++) {
3238: if(etc&IsBlob) *dpp = dup_blob_etc(*bpp,etc);
3239: else *dpp = *bpp;
3240: };
3241: *dpp = NULL;
3242: };
3243: return(&dup);
3244: }
3245:
3246: /* Split the given Blobs into two, *b0 & *b1, according to the value 0 or !0
3247: respectively returned by the function s(b,a) applied to each Blob *b and
3248: blind argument *a.
3249: s() will be evaluated exactly once for each Blob, and the Blob's will be
3250: assigned in the order found in the original Blobs. Only pointers to Blob's
3251: are created; the Blob's themselves are not duplicated. The original Blobs
3252: record is unchanged.
3253: */
3254: split_blobs(b,s,a,b0,b1)
3255: Blobs *b;
3256: int (*s)();
3257: VOID *a; /* passed transparently to s() */
3258: Blobs *b0,*b1;
3259: { char *sel,*sp;
3260: register Blob *bp,**bpp;
3261: Blob **b0pp;
3262: Blob **b1pp;
3263: *b0 = *b1 = empty_Blobs;
3264: if(b->mny<=0) return;
3265: if((sel=(char *)malloc(b->mny))==NULL)
3266: abort("split_blobs: can't malloc sel[%d]",b->mny);
3267: for(bp= *(bpp=b->bpa),sp=sel; bp!=NULL; bp= *(++bpp),sp++)
3268: if(*sp = s(bp,a)) b1->mny++; else b0->mny++;
3269: if(b0->mny>0)
3270: if((b0->bpa=(Blob **)malloc((b0->mny+1)*sizeof(Blob *)))==NULL)
3271: abort("split_blobs: can't malloc b0->bpa[%d]",b0->mny+1);
3272: if(b1->mny>0)
3273: if((b1->bpa=(Blob **)malloc((b1->mny+1)*sizeof(Blob *)))==NULL)
3274: abort("split_blobs: can't malloc b1->bpa[%d]",b1->mny+1);
3275: b0pp=b0->bpa;
3276: b1pp=b1->bpa;
3277: for(bp= *(bpp=b->bpa),sp=sel; bp!=NULL; bp= *(++bpp),sp++)
3278: if(*sp) *(b1pp++)=bp; else *(b0pp++)=bp;
3279: if(b0->mny>0) *b0pp=NULL;
3280: if(b1->mny>0) *b1pp=NULL;
3281: free(sel);
3282: }
3283:
3284: /* Return the address of the first in a list of Blobs, duplicated from
3285: the given list. */
3286: Blob *dup_blobl_etc(bp,etc)
3287: Blob *bp;
3288: Ident etc;
3289: { Blob *fi,*cp,*pp,*dp;
3290: if(bp==NULL) return(NULL);
3291: for(pp=NULL,cp=bp; cp!=NULL; pp=dp,cp=cp->n) {
3292: dp=dup_blob_etc(cp,etc);
3293: if(pp==NULL) fi = dp;
3294: else pp->n = dp;
3295: };
3296: pp->n=NULL;
3297: return(fi);
3298: }
3299:
3300: /* Prepend this blob to the given Char's bloblist; update Char's bx, area, & per.
3301: Inverse of `remove_blobl()'. */
3302: Blob *insert_blobl(bp,cp)
3303: Blob *bp;
3304: Char *cp;
3305: { register Blob *pbp,*nbp;
3306: if(cp->bmny>0) bp->n = cp->fi;
3307: else bp->n = NULL;
3308: cp->fi = bp;
3309: cp->bmny++;
3310: merge_bbx(&(bp->bx),&(cp->bx));
3311: cp->area += bp->area;
3312: cp->per += bp->per;
3313: return(bp);
3314: }
3315:
3316: /* Remove this blob from a char's bloblist; update Char's bx, area, per.
3317: Inverse of `insert_blobl()'. */
3318: remove_blobl(bp,cp)
3319: Blob *bp;
3320: Char *cp;
3321: { Blob *rp,*pp;
3322: Bbx bx; /* Char's new Bbx */
3323: if(cp->bmny==1) { /* frequent case */
3324: cp->fi=NULL; cp->bmny=0;
3325: }
3326: else if(cp->bmny>1){
3327: bx=empty_Bbx;
3328: pp=NULL;
3329: for(rp=cp->fi; rp!=NULL; pp=rp,rp=rp->n) {
3330: if(rp==bp) break;
3331: else { if(bx.a.x > rp->bx.a.x) bx.a.x = rp->bx.a.x;
3332: if(bx.a.y > rp->bx.a.y) bx.a.y = rp->bx.a.y;
3333: if(bx.b.x < rp->bx.b.x) bx.b.x = rp->bx.b.x;
3334: if(bx.b.y < rp->bx.b.y) bx.b.y = rp->bx.b.y;
3335: };
3336: };
3337: if(rp!=NULL) { /* remove from list */
3338: if(pp==NULL) cp->fi=bp->n;
3339: else pp->n=bp->n;
3340: cp->bmny--;
3341: for(rp=bp->n; rp!=NULL; rp=rp->n) {
3342: if(bx.a.x > rp->bx.a.x) bx.a.x = rp->bx.a.x;
3343: if(bx.a.y > rp->bx.a.y) bx.a.y = rp->bx.a.y;
3344: if(bx.b.x < rp->bx.b.x) bx.b.x = rp->bx.b.x;
3345: if(bx.b.y < rp->bx.b.y) bx.b.y = rp->bx.b.y;
3346: };
3347: cp->bx = bx;
3348: }
3349: else err("remove_blobl: can't - not found");
3350: }
3351: else err("remove_blobl: can't - Blobl empty");
3352: cp->area -= bp->area;
3353: cp->per -= bp->per;
3354: }
3355:
3356: /* prepend this blob to the given Blob list */
3357: Blob *prepend_blobl(bp,blp)
3358: Blob *bp;
3359: Blobl *blp;
3360: { register Blob *pbp,*nbp;
3361: if(blp->mny>0) bp->n = blp->fi;
3362: else { bp->n = NULL;
3363: blp->la = bp;
3364: };
3365: blp->fi = bp;
3366: blp->mny++;
3367: return(bp);
3368: }
3369:
3370: /* append this blob to the given Blob list */
3371: Blob *append_blobl(bp,blp)
3372: Blob *bp;
3373: Blobl *blp;
3374: { register Blob *pbp,*nbp;
3375: if(blp->mny==0) blp->fi = bp;
3376: else blp->la->n = bp;
3377: blp->la = bp;
3378: bp->n = NULL;
3379: blp->mny++;
3380: return(bp);
3381: }
3382:
3383: /* remove a blob from a blobs set */
3384: remove_blob(bp,bsp)
3385: Blob *bp;
3386: Blobs *bsp;
3387: { register Blob *rp,**rpp,**npp;
3388: if(bsp->mny==0) err("remove_blob: can't - Blobs empty");
3389: else { for(rp= *(rpp=bsp->bpa); rp!=NULL; rp= *(++rpp)) if(rp==bp) break;
3390: if(rp==NULL) err("remove_blob: can't - not found");
3391: else { /* move later entries up */
3392: npp=rpp+1;
3393: do *(rpp++)= *(npp++); while ((*rpp)!=NULL);
3394: if((--(bsp->mny))==0) {free(bsp->bpa); bsp->bpa=NULL;};
3395: /* don't bother to realloc downwards */
3396: };
3397: };
3398: }
3399:
3400: /* Append a blob to the end of a blobs set.
3401: Return appended Blob *. */
3402: Blob *append_blob(p,sp)
3403: Blob *p;
3404: Blobs *sp;
3405: { register Blob *rp,**rpp,**npp;
3406: if(sp->mny==0) {
3407: if((sp->bpa=(Blob **)malloc(2*sizeof(Blob *)))==NULL)
3408: abort("append_blob: can't malloc sp->bpa[2]");
3409: }
3410: else { if((sp->bpa=(Blob **)realloc(
3411: sp->bpa,
3412: (sp->mny+2)*sizeof(Blob *))
3413: )==NULL)
3414: abort("append_blob: can't realloc sp->bpa[%d]",sp->mny+2);
3415: };
3416: sp->bpa[sp->mny] = p;
3417: sp->bpa[++sp->mny] = NULL;
3418: return(p);
3419: }
3420:
3421: /* Append Blobs *p1 to Blobs *p2. On return, *p1 is unchanged, *p2 is in general
3422: longer, and all the Blob's owned by *p1 are now also owned by *p2. */
3423: append_blobs_blobs(p1,p2)
3424: Blobs *p1,*p2;
3425: { int mny;
3426: register Blob **pp1,**pp2;
3427: if(p1->mny==0) return;
3428: if(p2->mny==0) { *p2 = *dup_blobs_etc(p1,IsNONE); return; };
3429: mny = p2->mny + p1->mny;
3430: if((p2->bpa=(Blob **)realloc(p2->bpa,(mny+1)*sizeof(Blob *)))==NULL)
3431: abort("append_blobs_blobs: can't realloc p2->bpa[%d]",mny+1);
3432: pp1=p1->bpa; pp2=p2->bpa+p2->mny; while(*pp1!=NULL) *(pp2++) = *(pp1++);
3433: *pp2 = NULL;
3434: p2->mny = mny;
3435: }
3436:
3437: free_blobl_etc(mnyp,fip,etc)
3438: int *mnyp;
3439: Blob **fip;
3440: Ident etc;
3441: { register Blob *bp,*nbp;
3442: if(*mnyp>0) {
3443: for(bp= *fip; bp != NULL; bp=nbp)
3444: { nbp=bp->n; free_blob_etc(bp,etc); };
3445: };
3446: *mnyp=0;
3447: *fip=NULL;
3448: }
3449:
3450: /* Unconditionally free the malloc-space array of pointers, and empty the set.
3451: Don't free the records that it owned.
3452: */
3453: free_blobs(bsp)
3454: Blobs *bsp;
3455: { if(bsp->bpa!=NULL) { free(bsp->bpa); bsp->bpa=NULL; };
3456: bsp->mny = 0;
3457: }
3458:
3459: free_blobs_etc(bsp,etc)
3460: Blobs *bsp;
3461: Ident etc;
3462: { register Blob *bp, **bpp;
3463: if(bsp->mny>0&&(etc&IsBlob)) for(bp= *(bpp=bsp->bpa); bp!=NULL; bp= *(++bpp))
3464: free_blob_etc(bp,etc);
3465: free_blobs(bsp);
3466: }
3467:
3468: Blobs *blobl_to_blobs(blp)
3469: Blobl *blp;
3470: { static Blobs bs;
3471: register Blob *bp,**bpp;
3472: bs = empty_Blobs;
3473: bs.mny = blp->mny;
3474: if(bs.mny>0) {
3475: if((bs.bpa=(Blob **)malloc((bs.mny+1)*sizeof(Blob *)))==NULL)
3476: abort("blobl_to_blobs: can't malloc Blobs.bpa[%d]",bs.mny+1);
3477: for(bp=blp->fi,bpp=bs.bpa; bp!=NULL; bp=bp->n,bpp++)
3478: *bpp = bp;
3479: *bpp = NULL;
3480: };
3481: return(&bs);
3482: }
3483:
3484: int bp_tod(bp)
3485: Blob *bp;
3486: { if(bp==NULL) return(-2);
3487: else return(bp-blob_pool);
3488: }
3489:
3490: /* test whether for this Blob, each runs's data fields could all be compressed
3491: from a short to a char */
3492: boolean blob_small(bp)
3493: Blob *bp;
3494: { if(bp->runs>255) return(F);
3495: if(bbx_wid(&bp->bx)>255) return(F);
3496: if(bbx_hgt(&bp->bx)>255) return(F);
3497: return(T);
3498: }
3499:
3500: char *blob_toa(bp)
3501: Blob *bp;
3502: { char s1[80];
3503: static char s[80];
3504: Scoor hgt,wid;
3505: if(bp==NULL) strcpy(s,"NULL");
3506: else { hgt = bp->bx.b.y - bp->bx.a.y + 1;
3507: wid = bp->bx.b.x - bp->bx.a.x + 1;
3508: sprintf(s1,"%s bx%s w%d,h%d ar%d pe%d r.",
3509: ident_toa(bp->ident),
3510: bbx_toa(&(bp->bx)),
3511: wid,
3512: hgt,
3513: bp->area,
3514: bp->per
3515: );
3516: if(bp->ident&Runs_f) strcat(s1,"f");
3517: else if(bp->ident&Runs_ff) strcat(s1,"ff");
3518: else if(bp->ident&Runs_seek) strcat(s1,"sk");
3519: else if(bp->ident&Runs_g4) strcat(s1,"g");
3520: else strcat(s1,"?");
3521: sprintf(s,"%s%d",s1,bp->runs);
3522: };
3523: return(s);
3524: }
3525:
3526: /* compute the centroid of the Blob, w.r.t bx.a */
3527: Pp *blob_centroid(bp)
3528: Blob *bp;
3529: { static Pp c;
3530: RunF *rfp;
3531: int ri,area;
3532: c.x = c.y = 0.0;
3533: if(bp->ident&Runs_ff) {
3534: for(ri=0, rfp=bp->r.ff; ri<bp->runs; ri++, rfp++) {
3535: c.x += (area=(rfp->xe-rfp->xs+1)) * (rfp->xe+rfp->xs);
3536: c.y += area * rfp->y;
3537: };
3538: c.x /= 2.0*bp->area;
3539: c.y /= bp->area;
3540: }
3541: else abort("blob_centroid: only Runs_ff supported");
3542: return(&c);
3543: }
3544:
3545: /* write (printably) to stdout */
3546: out_blob(bp)
3547: Blob *bp;
3548: { Run *crp;
3549: static char pad[] = " ";
3550: short y;
3551: if(bp==NULL) fprintf(stderr,"Bb NULL.\n");
3552: else fprintf(stdout,"%s\n",blob_toa(bp));
3553: fprintf(stdout,"%sy%d:",pad,bp->bx.a.y);
3554: for(crp=bp->r.f,y=crp->y; crp!=NULL; crp=crp->n) {
3555: if(crp->y!=y) {
3556: fprintf(stdout,"\n%sy%d:",pad,crp->y);
3557: y=crp->y;
3558: };
3559: fprintf(stdout," [%d,%d]",crp->xs,crp->xe);
3560: };
3561: fprintf(stdout,"\n");
3562: }
3563:
3564: #if FWRI
3565: /* Write blob record (only) to FILE *f.
3566: Check whether Blob is ``small'' and label *p accordingly. */
3567: fwrb_blob(f,p)
3568: FILE *f;
3569: Blob *p;
3570: {
3571: #if dbg_fwrb
3572: if((!(p->ident&IsBlob))||(p->ident&(IsALL&(~IsBlob))))
3573: err("fwrb_blob: %s",blob_toa(p));
3574: #endif
3575: if(blob_small(p)) p->ident |= Blob_small; else p->ident &= ~Blob_small;
3576: fwri_Ident(f,p->ident);
3577: /* fwri_Seq(f,p->no); */
3578: fwri_Bbx(f,&(p->bx));
3579: fwri_uint4(f,p->area);
3580: fwri_uint4(f,p->per);
3581: /* don't write .n */
3582: fwri_Merit(f,p->m);
3583: fwri_uint3(f,p->runs);
3584: fwri_uint2(f,((p->bdsp==NULL)? 0: p->bdsp->mny));
3585: #if dbg_fwrb_toa
3586: err("fwrb_blob: %s",blob_toa(p));
3587: #endif
3588: }
3589: #else
3590: /* Write blob record (only) to FILE *fp.
3591: Check whether Blob is ``small'' and label *bp accordingly. */
3592: fwrb_blob(fp,bp)
3593: FILE *fp;
3594: Blob *bp;
3595: { BlobF bf;
3596: #if dbg_fwrb
3597: if((!(bp->ident&IsBlob))||(bp->ident&(IsALL&(~IsBlob))))
3598: err("fwrb_blob: %s",blob_toa(bp));
3599: #endif
3600: memset(&bf,'\0',sizeof(bf));
3601: if(blob_small(bp)) bp->ident |= Blob_small;
3602: else bp->ident &= ~Blob_small;
3603: bf.ident = bp->ident;
3604: bf.bx=bp->bx;
3605: bf.area=bp->area;
3606: bf.per=bp->per;
3607: bf.runs=bp->runs;
3608: if(bp->bdsp==NULL) bf.bdys=0;
3609: else bf.bdys=bp->bdsp->mny;
3610: if(blob_debug) err_blobf("",&bf);
3611: if(fwrite(&bf,sizeof(BlobF),1,fp)!=1)
3612: abort("fwrb_blob: can't fwrite");
3613: #if dbg_fwrb_toa
3614: err("fwrb_blob: %s",blob_toa(bp));
3615: #endif
3616: }
3617: #endif
3618:
3619: /* Write detailed description of Runs to stderr. */
3620: Blob *err_runs(name,bp)
3621: char *name;
3622: Blob *bp;
3623: { Run *rp;
3624: RunF *rfp,*rfe;
3625: int ri;
3626: if(bp->ident&Runs_f) {
3627: fprintf(stderr,"%s Runs_f[%d] in %s:\n",
3628: name,bp->runs,bbx_toa(&bp->bx));
3629: for(rp=bp->r.f,ri=0; rp!=NULL; rp=rp->n,ri++) {
3630: fprintf(stderr," %2d: %d[%d,%d]\n",
3631: ri,rp->y,rp->xs,rp->xe);
3632: };
3633: }
3634: else if(bp->ident&Runs_ff) {
3635: fprintf(stderr,"%s Runs_ff[%d] in %s: ",
3636: name,bp->runs,bbx_toa(&(bp->bx)));
3637: for(rfe=(rfp=bp->r.ff)+bp->runs,ri=0; rfp<rfe; rfp++,ri++) {
3638: fprintf(stderr," %d:%d[%d,%d]",
3639: ri,rfp->y,rfp->xs,rfp->xe);
3640: };
3641: fprintf(stderr,"\n");
3642: }
3643: else if(bp->ident&Runs_seek) {
3644: goto unsupported;
3645: }
3646: else { goto unsupported;
3647: };
3648: return;
3649: unsupported:
3650: abort("err_runs: %s unsupported",ident_toa(bp->ident));
3651: }
3652:
3653: /* Convert the type of Runs in *bp to the type specified by id.
3654: Supported: only bp->ident&Runs_f to id&Runs_ff.
3655: Return pointer to local static duplicate of *bp.
3656: */
3657: Blob *runs_to_runs(bp,id)
3658: Blob *bp;
3659: Ident id;
3660: { static Blob b;
3661: register Run *rp;
3662: RunF *rfp;
3663:
3664: b = *bp;
3665: if(bp->ident&Runs_f) {
3666: if(id&Runs_ff) {
3667: b.ident &= ~(Runs_f|Blob_small);
3668: b.ident |= Runs_ff;
3669: if(blob_small(bp)) b.ident |= Blob_small;
3670: if((b.r.ff=(RunF *)malloc(b.runs*sizeof(RunF)))==NULL)
3671: abort("runs_to_runs: can't malloc Blob.r.ff[%d]",
3672: b.runs); for(rp=bp->r.f,rfp=b.r.ff; rp!=NULL; rp=rp->n,rfp++) {
3673: /* y, xs, xe will be relative to Blob.bx.a */
3674: rfp->y = rp->y - bp->bx.a.y;
3675: rfp->xs = rp->xs - bp->bx.a.x;
3676: rfp->xe = rp->xe - bp->bx.a.x;
3677: /* above,below connecting indices are relative to
3678: the sequence no. of this run (ac>0 & bc>0) */
3679: if((rfp->ad = rp->ad)!=0)
3680: rfp->ac = rp->u.no - rp->ac->u.no;
3681: else rfp->ac = 0;
3682: if((rfp->bd = rp->bd)!=0)
3683: rfp->bc = rp->bc->u.no - rp->u.no;
3684: else rfp->bc = 0;
3685: if(0) err_runf(" ",rfp);
3686: };
3687: }
3688: else { goto unsupported;
3689: };
3690: }
3691: else if(bp->ident&Runs_ff) {
3692: if(bp->ident&Blob_small) {
3693: goto unsupported;
3694: }
3695: else { goto unsupported;
3696: };
3697: }
3698: else if(bp->ident&Runs_seek) {
3699: goto unsupported;
3700: }
3701: else { goto unsupported;
3702: };
3703: return(&b);
3704:
3705: unsupported:
3706: abort("runs_to_runs: %s --> %s unsupported",
3707: ident_toa(bp->ident),ident_toa(id));
3708: }
3709:
3710: #if CPU!=CRAY
3711: /* Write these RunFs to FILE *fp in CCITT Group 4 format.
3712: BUG: uses bitio to one end of a pipe, just to store the entire
3713: byte-stream so it can be counted; then, it is copied to *fp.
3714: This fails on large bitmaps since the space available for pipe
3715: buffering is limited by system constraints and can run out at any
3716: time (symptom: the user process hangs in I state). Also, since
3717: it relies so heavily on streams, it may not prove to be very portable.
3718: Should be rewritten with an expandable byte-buffer of some kind,
3719: which requires that the `putting' function in bitio be user-selectable.
3720: */
3721: fwrb_runfs_g4(fp,bxp,runs,ff)
3722: FILE *fp;
3723: Bbx *bxp;
3724: int runs;
3725: RunF *ff;
3726: #define dbg_fwrb_runfs_g4_detail F
3727: { RLE_Line l0,l1;
3728: RLE_Line *cl,*pl,*swap; /* current/prior/swap line */
3729: int wid,hgt; /* width,height of rectangular box of pixels */
3730: BITFILE *bf;
3731: int iri;
3732: RunF *irp;
3733: RLE_Run *crp;
3734: static int pipe_fd[2] = {-1,-1};
3735: static FILE *pipe_fp[2] = {NULL,NULL};
3736: unsigned long bytes,bi;
3737: int och;
3738: /* buffer g4 code in a pipe in order to count it */
3739: if(pipe_fd[0]==-1) {
3740: pipe(pipe_fd);
3741: if((pipe_fp[0] = fdopen(pipe_fd[0],"r"))==NULL)
3742: abort("fwrb_runfs_g4: can't open pipe \"r\", fd=%d",
3743: pipe_fd[0]);
3744: if((pipe_fp[1] = fdopen(pipe_fd[1],"w"))==NULL)
3745: abort("fwrb_runfs_g4: can't open pipe \"w\", fd=%d",
3746: pipe_fd[1]);
3747: /* leave this pipe open for the duration of the process */
3748: };
3749: /* treat pipe_fp[1] as a sequence of bits */
3750: if((bf=bopen(pipe_fp[1],"w"))==NULL)
3751: abort("fwrb_runfs_g4: can't open bitfile");
3752: wid = bbx_wid(bxp); hgt=bbx_hgt(bxp);
3753: BOF_to_g4(bf);
3754: cl= &l0; pl= &l1; cl->len = pl->len = wid; cl->y=0; pl->runs=0;
3755: iri=0; irp=ff;
3756: do { /* build current RLE_Line */
3757: crp=cl->r;
3758: while(iri<runs&&irp->y==cl->y) {
3759: crp->xs=irp->xs;
3760: crp->xe=irp->xe;
3761: if(dbg_fwrb_runfs_g4_detail)
3762: err("i%d: y%d x[%d,%d]",
3763: iri,cl->y,crp->xs,crp->xe);
3764: iri++; irp++; crp++;
3765: };
3766: cl->runs = crp-cl->r;
3767: /* write current RLE_line to file */
3768: rlel_to_g4(pl,cl,wid,bf);
3769: /* save current line as prior */
3770: swap=pl; pl=cl; cl=swap; cl->runs=0; cl->y=pl->y+1;
3771: }
3772: while(cl->y<hgt);
3773: /** By policy, don't append EOFB (i.e. omit EOF_to_g4(bf)) **/
3774: bytes = bclose(bf);
3775: if(dbg_fwrb_runs) err("fwrb_runfs_g4: %d bytes",bytes);
3776: #if FWRI
3777: fwri_uint4(fp,bytes);
3778: #else
3779: fwrite(&bytes,sizeof(bytes),1,fp);
3780: #endif
3781: /* copy contents in pipe to fp */
3782: fflush(pipe_fp[1]);
3783: for(bi=0;bi<bytes;bi++) {
3784: putc(och=getc(pipe_fp[0]),fp);
3785: #if dbg_fwrb_runs
3786: fprintf(stderr,"%02x",(unsigned char)och);
3787: #endif
3788: };
3789: if(dbg_fwrb_runs) fprintf(stderr,"\n");
3790: }
3791: #else
3792: fwrb_runfs_g4(fp,bxp,runs,ff)
3793: FILE *fp;
3794: Bbx *bxp;
3795: int runs;
3796: RunF *ff;
3797: { abort("fwrb_runfs_g4: unimplemented on Cray");
3798: }
3799: #endif
3800:
3801: #if CPU != CRAY
3802: /* Read a connected group of Runs in CCITT Group 4 format, into an array of RunFs.
3803: Return: 1 if normal & successful, 0 if EOF, and -1 if error.
3804: */
3805: int frdb_g4_runfs(fp,bxp,runs,ff)
3806: FILE *fp;
3807: Bbx *bxp; /* their bounding box, shrink-wrapped to fit exactly */
3808: int runs; /* expect exactly this number of runs */
3809: RunF *ff; /* space for `runs' RunFs */
3810: #define dbg_frdb_g4_runfs_detail F
3811: { RLE_Line *cl; /* current line */
3812: int wid,hgt; /* width,height of rectangular box of pixels */
3813: int y; /* height of current line */
3814: boolean bof;
3815: BITFILE *bf;
3816: static DST_table *tbl = NULL;
3817: int iri;
3818: RLE_Run *irp;
3819: int ori;
3820: RunF *orp;
3821: unsigned long bytes,g4_bytes;
3822: #if FRDI
3823: bytes=frdi_uint4(fp);
3824: #else
3825: fread(&bytes,sizeof(bytes),1,fp);
3826: #endif
3827: if(dbg_frdb_runs) err("frdb_g4_runfs: %d bytes",bytes);
3828: /* read FILE *fp as a sequence of bits */
3829: if((bf=bopen(fp,"r"))==NULL)
3830: abort("frdb_g4_runfs: can't open bitfile");
3831: if(tbl==NULL) {
3832: tbl=ccitt_table();
3833: if(dbg_frdb_g4_runfs_detail) ccitt_err_tbl(tbl);
3834: };
3835: wid=bbx_wid(bxp); hgt=bbx_hgt(bxp);
3836: y=0; bof=T; ori=0; orp=ff;
3837: while((y<hgt)&&(cl=g4_to_rlel(tbl,bf,bof,wid))!=NULL) {
3838: /* copy runs to RunF ff[] */
3839: for(iri=0,irp=cl->r; iri<cl->runs; iri++,irp++) {
3840: if(dbg_frdb_g4_runfs_detail)
3841: err("o%d i%d: y%d x[%d,%d]",
3842: ori,iri,y,irp->xs,irp->xe);
3843: if(ori<runs) {
3844: orp->y = y; orp->xs = irp->xs; orp->xe = irp->xe;
3845: orp++;
3846: }
3847: else err("frdb_g4_runfs: too many runs: ori%d >= runs%d",
3848: ori,runs);
3849: ori++;
3850: };
3851: y++; bof=F;
3852: };
3853: if(cl==NULL) {
3854: err("frdb_g4_runfs: unexpected EOF");
3855: return(0);
3856: };
3857: /* recover connectivity among runs, on the assumption that they
3858: are still in increasing lexicographic order on (y,xs) */
3859: fix_lag(orp-ff,(char *)ff,Runs_ff);
3860: if(ori!=runs) {
3861: err("frdb_g4_runfs: expected %d runs, but read %d",runs,ori);
3862: return(-1);
3863: };
3864: if((g4_bytes=bclose(bf))!=bytes) {
3865: err("frdb_g4_runfs: expected %d bytes, but read %d",
3866: bytes,g4_bytes);
3867: return(-1);
3868: };
3869: if(ferror(fp)) return(-errno); else return(1);
3870: }
3871: #else
3872: int frdb_g4_runfs(fp,bxp,runs,ff)
3873: FILE *fp;
3874: Bbx *bxp; /* exact bounding box, shrink-wrapped to fit */
3875: int runs; /* expect exactly this number of runs */
3876: RunF *ff; /* space for `runs' RunFs */
3877: { abort("frdb_g4_runfs: unimplemented on Cray");
3878: }
3879: #endif
3880:
3881: /* Write blob, etc to FILE *fp in binary format.
3882: If !(etc&IsBlob), then do nothing.
3883: else write Blob record and:
3884: If etc&IsRun, then also try to write Runs:
3885: If Blob.runs==0, write no runs.
3886: else
3887: if etc&Runs_g4, write in CCITT G4 format
3888: compact but needs large streams; may not port well;
3889: else write in Runs_ff format
3890: if blob is small enough, use compressed RunFS form on output.
3891:
3892: */
3893: fwrb_blob_etc(fp,bp,etc)
3894: FILE *fp;
3895: Blob *bp;
3896: Ident etc;
3897: { Ident sv_ident;
3898: int sv_runs;
3899: Run *rp;
3900: RunF rf;
3901: register RunF *rfp, *rfq;
3902: RunFS *rsp;
3903: #if FWRI
3904: RunFS rfs;
3905: #else
3906: static RunFS rfsa[256];
3907: #endif
3908: int ri;
3909: if(!(etc&IsBlob)) return;
3910:
3911: sv_ident = bp->ident;
3912: sv_runs = bp->runs;
3913: if(etc&IsRun) {
3914: /* decide which Runs_* bits should be set on output */
3915: bp->ident &= ~(Runs_f|Runs_ff|Runs_seek|Runs_g4);
3916: if(etc&Runs_g4) {
3917: bp->ident |= Runs_g4;
3918: }
3919: else { /* assume Runs_ff is wanted */
3920: bp->ident |= Runs_ff;
3921: };
3922: }
3923: else { bp->ident &= ~(IsRun|Runs_f|Runs_ff|Runs_seek|Runs_g4);
3924: bp->runs = 0;
3925: };
3926: fwrb_blob(fp,bp);
3927: bp->ident = sv_ident;
3928: bp->runs = sv_runs;
3929:
3930: if(bp->runs==0) return;
3931:
3932: if(etc&Runs_g4) {
3933: /* write CCITT Group 4 encoding for Runs */
3934: if(bp->ident&Runs_ff) {
3935: fwrb_runfs_g4(fp,&(bp->bx),bp->runs,bp->r.ff);
3936: }
3937: else abort("fwrb_blob_etc: etc&Runs_g4 but !(id&Runs_ff)");
3938: }
3939: else { /* Assume Runs_ff format is desired */
3940: if(bp->ident&Runs_f) {
3941: rp=bp->r.f;
3942: if(bp->ident&Blob_small) { /* use compressed Run records */
3943: if(blob_debug) err("small");
3944: /* can use small local static array */
3945: #if FWRI
3946: rsp= &rfs;
3947: #else
3948: rsp=rfsa;
3949: #endif
3950: while(rp!=NULL) {
3951: /* y, xs, xe will be relative to Blob.bx.a */
3952: rsp->y = rp->y - bp->bx.a.y;
3953: rsp->xs = rp->xs - bp->bx.a.x;
3954: rsp->xe = rp->xe - bp->bx.a.x;
3955: /* above,below connecting run indices are relative to
3956: the sequence no. of this run (ac>0 & bc>0) */
3957: if((rsp->ad = rp->ad)!=0)
3958: rsp->ac = rp->u.no - rp->ac->u.no;
3959: else rsp->ac = 0;
3960: if((rsp->bd = rp->bd)!=0)
3961: rsp->bc = rp->bc->u.no - rp->u.no;
3962: else rsp->bc = 0;
3963: if(blob_debug) err_runfs(" ",rsp);
3964: rp=rp->n;
3965: #if FWRI
3966: fwri_RunFS(fp,rsp);
3967: #else
3968: rsp++;
3969: #endif
3970: };
3971: #if !FWRI
3972: if(fwrite(rfsa,sizeof(RunFS),bp->runs,fp)!=bp->runs)
3973: abort("fwrb_blob_etc: can't fwrite RunFS[%d]",bp->runs);
3974: if(dbg_fwrb_runs)
3975: err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunFS));
3976: #endif
3977: }
3978: else { if(blob_debug) err("large");
3979: while(rp!=NULL) {
3980: /* y, xs, xe will be relative to Blob.bx.a */
3981: rf.y = rp->y - bp->bx.a.y;
3982: rf.xs = rp->xs - bp->bx.a.x;
3983: rf.xe = rp->xe - bp->bx.a.x;
3984: /* above,below connecting run indices are relative to
3985: the sequence no. of this run (ac>0 & bc>0) */
3986: if((rf.ad = rp->ad)!=0)
3987: rf.ac = rp->u.no - rp->ac->u.no;
3988: else rf.ac = 0;
3989: if((rf.bd = rp->bd)!=0)
3990: rf.bc = rp->bc->u.no - rp->u.no;
3991: else rf.bc = 0;
3992: if(blob_debug) err_runf(" ",&rf);
3993:
3994: /* since there may be many, won't use a local array */
3995: #if FWRI
3996: fwri_RunF(fp,&rf);
3997: #else
3998: if(fwrite(&rf,sizeof(RunF),1,fp)!=1)
3999: abort("fwrb_blob_etc: can't fwrite RunF");
4000: #endif
4001: rp=rp->n;
4002: };
4003: if(dbg_fwrb_runs)
4004: err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunF));
4005: };
4006: }
4007: else if(bp->ident&Runs_ff) {
4008: if(bp->ident&Blob_small) { /* use compressed Run records */
4009: if(blob_debug) err("small");
4010: /* can use small local static array */
4011: #if FWRI
4012: rsp= &rfs;
4013: #else
4014: rsp=rfsa;
4015: #endif
4016: for(rfp=bp->r.ff,ri=0; ri<bp->runs; rfp++,ri++) {
4017: rsp->y = rfp->y;
4018: rsp->xs = rfp->xs;
4019: rsp->xe = rfp->xe;
4020: rsp->ad = rfp->ad;
4021: rsp->bd = rfp->bd;
4022: rsp->ac = rfp->ac;
4023: rsp->bc = rfp->bc;
4024: #if FWRI
4025: fwri_RunFS(fp,rsp);
4026: #else
4027: rsp++;
4028: #endif
4029: };
4030: #if !FWRI
4031: if(fwrite(rfsa,sizeof(RunFS),bp->runs,fp)!=bp->runs)
4032: abort("fwrb_blob_etc: can't fwrite RunFS[%d]",bp->runs);
4033: if(dbg_fwrb_runs)
4034: err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunFS));
4035: #endif
4036: }
4037: else { if(blob_debug) err("large");
4038: #if FWRI
4039: for(rfq=(rfp=bp->r.ff)+bp->runs; rfp<rfq; rfp++) {
4040: fwri_RunF(fp,rfp);
4041: };
4042:
4043: #else
4044: if(fwrite(bp->r.ff,sizeof(RunF),bp->runs,fp)!=bp->runs)
4045: abort("fwrb_blob_etc: can't fwrite RunF[%d]",bp->runs);
4046: if(dbg_fwrb_runs)
4047: err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunF));
4048: #endif
4049: };
4050: };
4051: };
4052: }
4053:
4054: /* Read a given Blob's RunF's (binary) from FILE *fp; return F on EOF.
4055: If bp->runs<=max, read the RunF's into bp->r.ff, and set Runs_ff bit.
4056: otherwise ignore them all and set bp->r.ff==NULL. */
4057: int frdb_runfs(fp,bp,max)
4058: FILE *fp;
4059: Blob *bp; /* *bp's fields already set up */
4060: int max; /* maximum no. RunF records expected */
4061: { register RunFS *rsp,*rsq;
4062: static RunFS rfsa[256];
4063: register RunF *rfp,*rfq;
4064: if(bp->r.ff!=NULL && bp->runs <= max) {
4065: bp->ident |= Runs_ff; bp->ident &= ~(Runs_f|Runs_seek);
4066: if(bp->ident&Blob_small) {
4067: if(blob_debug) err("small");
4068: #if FRDI
4069: for(rsq=(rsp=rfsa)+bp->runs; rsp<rsq; rsp++) {
4070: frdi_RunFS(fp,rsp);
4071: };
4072: #else
4073: if(fread(rfsa,sizeof(RunFS),bp->runs,fp) < bp->runs)
4074: return(0);
4075: #endif
4076: /* copy compressed RunFS's into RunF's */
4077: for(rsq=(rsp=rfsa)+bp->runs,rfp=bp->r.ff;
4078: rsp<rsq;
4079: rsp++,rfp++) {
4080: /* beware sign extension from unsigned chars */
4081: if(blob_debug) err_runfs(" ",rsp);
4082: rfp->y = 0377&rsp->y;
4083: rfp->xs = 0377&rsp->xs;
4084: rfp->xe = 0377&rsp->xe;
4085: rfp->ad = 0377&rsp->ad;
4086: rfp->bd = 0377&rsp->bd;
4087: rfp->ac = 0377&rsp->ac;
4088: rfp->bc = 0377&rsp->bc;
4089: };
4090: }
4091: else { if(blob_debug) err("large");
4092: #if FRDI
4093: for(rfq=(rfp=bp->r.ff)+bp->runs; rfp<rfq; rfp++)
4094: frdi_RunF(fp,rfp);
4095: #else
4096: if(fread(bp->r.ff,sizeof(RunF),bp->runs,fp) != bp->runs)
4097: return(F);
4098: #endif
4099: };
4100: }
4101: else { bp->ident &= ~(Runs_ff|Runs_f);
4102: bp->ident |= Runs_seek;
4103: bp->r.seek=ftell(fp);
4104: /* skip past excessive no. of runs */
4105: /** What if FRDI?? **/
4106: if(bp->ident&Blob_small)
4107: fseek(fp,(long)((bp->runs)*sizeof(RunFS)),1);
4108: else
4109: fseek(fp,(long)((bp->runs)*sizeof(RunF)),1);
4110: };
4111: if(ferror(fp)) return(-errno); else return(1);
4112: }
4113:
4114: #if FRDI
4115: /* read a Blob record (only) into *p */
4116: int frdb_blob(f,p)
4117: FILE *f;
4118: Blob *p;
4119: { int bdy_mny;
4120: *p = empty_Blob;
4121: if(feof(f))
4122: return(0);
4123: p->ident=frdi_Ident(f);
4124: /* p->no=frdi_Seq(f); */
4125: frdi_Bbx(f,&(p->bx));
4126: p->area=frdi_uint4(f);
4127: p->per=frdi_uint4(f);
4128: /* don't read .n */
4129: p->m=frdi_Merit(f);
4130: p->runs=frdi_uint3(f);
4131: if((bdy_mny=frdi_uint2(f))>0) {
4132: p->bdsp = alloc_bdys();
4133: p->bdsp->mny = bdy_mny;
4134: };
4135: #if dbg_frdb
4136: if((!(p->ident&IsBlob))||(p->ident&(IsALL&(~IsBlob))))
4137: err("frdb_blob: %s",blob_toa(p));
4138: #endif
4139: #if dbg_frdb_toa
4140: err("frdb_blob: %s",blob_toa(p));
4141: #endif
4142: if(ferror(f))
4143: return(-errno);
4144: else return(1);
4145: }
4146: #else
4147: /* read a Blob record (only) into *bp; return F if EOF */
4148: int frdb_blob(fp,bp)
4149: FILE *fp;
4150: Blob *bp;
4151: { BlobF bf;
4152: if(fread(&bf,sizeof(BlobF),1,fp)!=1) return(0);
4153: if(blob_debug) err_blobf("bf",&bf);
4154: bp->ident=bf.ident;
4155: bp->no = 0;
4156: bp->bx=bf.bx;
4157: bp->area=bf.area;
4158: /*bp->per=bf.per;*/
4159: bp->runs=bf.runs;
4160: /*bp->bdys=bf.bdys;*/
4161: bp->n = NULL;
4162: bp->r.f = NULL;
4163: bp->bdsp = NULL;
4164: #if dbg_frdb
4165: if((!(bp->ident&IsBlob))||(bp->ident&(IsALL&(~IsBlob))))
4166: err("frdb_blob: %s",blob_toa(bp));
4167: #endif
4168: #if dbg_frdb_toa
4169: err("frdb_blob: %s",blob_toa(bp));
4170: #endif
4171: if(ferror(fp)) return(-errno); else return(1);
4172: }
4173: #endif
4174:
4175: err_blob(s,bp)
4176: char *s;
4177: Blob *bp;
4178: { fprintf(stderr,"%s ",s);
4179: if(bp==NULL) fprintf(stderr,"Blob NULL.\n");
4180: else fprintf(stderr,
4181: "Blob %d: x[%d,%d],y[%d,%d] ar%d ft%s r(#%d f%d)\n",
4182: bp->no,bp->bx.a.x,bp->bx.b.x,bp->bx.a.y,bp->bx.b.y,
4183: bp->area,ident_toa(bp->ident),bp->runs,rp_tod(bp->r.f));
4184: }
4185:
4186: err_blob_runs(s,bp)
4187: char *s;
4188: Blob *bp;
4189: { Run *crp;
4190: char cs[20];
4191: fprintf(stderr,"%s ",s);
4192: err_blob(s,bp);
4193: if(bp!=NULL&&bp->runs>0&&bp->r.f!=NULL) {
4194: sprintf(cs,"%*s",strlen(s)+2," ");
4195: for(crp=bp->r.f; crp!=NULL; crp=crp->n) err_run(cs,crp);
4196: };
4197: }
4198:
4199: err_blob_runfs(s,bp)
4200: char *s;
4201: Blob *bp;
4202: { RunF *crp;
4203: int ri;
4204: char cs[20];
4205: fprintf(stderr,"%s ",s);
4206: err_blob_briefly("",bp);
4207: if(bp!=NULL&&bp->runs>0&&bp->r.ff!=NULL) {
4208: sprintf(cs,"%*s",strlen(s)+2," ");
4209: for(crp=bp->r.ff,ri=0; ri<bp->runs; crp++,ri++) err_runf(cs,crp);
4210: };
4211: }
4212:
4213: err_blobf(s,bp)
4214: char *s;
4215: BlobF *bp;
4216: { Run *crp;
4217: char cs[20];
4218: fprintf(stderr,"%s ",s);
4219: if(bp==NULL) fprintf(stderr,"BlobF NULL.\n");
4220: else fprintf(stderr,
4221: "BlobF: x[%d,%d],y[%d,%d] ar%d ft%s #r%d\n",
4222: bp->bx.a.x,bp->bx.b.x,bp->bx.a.y,bp->bx.b.y,
4223: bp->area,ident_toa(bp->ident),bp->runs);
4224: }
4225:
4226: err_blob_briefly(s,bp)
4227: char s[];
4228: Blob *bp;
4229: { Run *crp;
4230: if(bp==NULL) err("%s Blob NULL.",s);
4231: else { fprintf(stderr,
4232: "%s Blob #%d: bx(%d,%d),(%d,%d) ar%d f%s runs%d ",
4233: s,
4234: bp->no,
4235: bp->bx.a.x,bp->bx.a.y,bp->bx.b.x,bp->bx.b.y,
4236: bp->area,
4237: ident_toa(bp->ident),
4238: bp->runs);
4239: fprintf(stderr,"\n");
4240: };
4241: }
4242:
4243: err_blob_stats()
4244: { err("Blob stats: %d now, %d total, %d hi-water\n",
4245: blob_max-blob_fr_mny,hi_blob_no+1,blob_hi);
4246: }
4247:
4248: /* write blob list starting at fi */
4249: fwrb_blobl_etc(fp,mny,fi,etc)
4250: FILE *fp;
4251: int mny;
4252: Blob *fi;
4253: Ident etc;
4254: { int bi;
4255: Blob *bp;
4256: if(mny>0) for(bi=0,bp=fi; bi<mny; bi++,bp=bp->n) {
4257: if(bp!=NULL) fwrb_blob_etc(fp,bp,etc);
4258: else { err("fwrb_blobl_etc: bmny==%d but %dth (Blob *) is NULL",
4259: mny,bi);
4260: break;
4261: };
4262: };
4263: }
4264:
4265: fwrb_blobs_etc(fp,bs,etc)
4266: FILE *fp;
4267: Blobs bs;
4268: Ident etc;
4269: { register Blob *bp,**bpp;
4270: if(bs.mny==0) return;
4271: for(bp= *(bpp=bs.bpa); bp!=NULL; bp= *(++bpp))
4272: fwrb_blob_etc(fp,bp,etc);
4273: }
4274:
4275: /* read a set of blobs, and their parts */
4276: frdb_blobs_etc(fp,bsp,etc)
4277: FILE *fp;
4278: Blobs *bsp;
4279: Ident etc; /* read only the parts indicated */
4280: { int bi;
4281: register Blob *bp,**bpp;
4282: if(bsp->mny<=0) {
4283: *bsp = empty_Blobs;
4284: return(1);
4285: };
4286:
4287: if((bpp=bsp->bpa=(Blob **)malloc((bsp->mny+1)*sizeof(Blob *)))==NULL)
4288: abort("frdb_blobs_etc: can't alloc Blobs.bpa[%d]",bsp->mny+1);
4289: for(bi=0; bi<bsp->mny; bi++) {
4290: *(bpp++) = bp = alloc_blob();
4291: if(!frdb_blob_etc(fp,bp,etc))
4292: abort("frdb_blobs_etc: unexpected EOF");
4293: };
4294: *bpp = NULL;
4295: if(ferror(fp)) return(-errno); else return(1);
4296: }
4297:
4298: /* Read a blob record into *bp, and then read its parts as specified by etc.
4299: If there aren't any runs, return normally.
4300: If etc&IsRun is false, then set Runs_seek and proceed as described below.
4301: If etc&Runs_ff, then the contents of r.ff is examined:
4302: if NULL, then space is allocated here for `runs' RunF's;
4303: if non-NULL, then on the assumption that it points to space for
4304: at least `runs' many, they are read into it.
4305: If etc&Runs_seek, then the ftell value is placed in r.seek,
4306: and the runs are simply skipped over.
4307: The Runs_f (list) option is unimplemented.
4308: The Blob is marked with the appropriate Runs_X bit.
4309: Return: 1 if normal & successful, 0 if EOF, and -1 if error.
4310: */
4311: int frdb_blob_etc(fp,bp,etc)
4312: FILE *fp;
4313: Blob *bp;
4314: Ident etc;
4315: { int stat;
4316: if((stat=frdb_blob(fp,bp))!=1)
4317: return(stat);
4318: if(bp->runs<=0) {
4319: bp->runs = 0;
4320: bp->r.ff = NULL;
4321: bp->ident &= ~(Runs_f|Runs_seek|Runs_g4);
4322: bp->ident |= Runs_ff;
4323: return(1);
4324: };
4325:
4326: if(!(etc&IsRun)) {
4327: etc |= IsRun|Runs_seek;
4328: etc &= ~(Runs_f|Runs_ff|Runs_g4);
4329: };
4330: if (!(etc&(Runs_f|Runs_ff|Runs_g4|Runs_seek)) || etc&Runs_ff) {
4331: /* Want to deliver Runs in Runf ff[] format */
4332: if(bp->r.ff==NULL) {
4333: if( (bp->r.ff=
4334: (RunF *)malloc(bp->runs*sizeof(RunF)))==NULL)
4335: abort("frdb_blob_etc: can't alloc r.ff[%d]",bp->runs);
4336: };
4337: if(bp->ident&Runs_g4) {
4338: /* Runs are in CCITT Group 4 format */
4339: stat=frdb_g4_runfs(fp,&(bp->bx),bp->runs,bp->r.ff);
4340: }
4341: else { /* Runs are in RunF or RunFS format */
4342: stat=frdb_runfs(fp,bp,bp->runs);
4343: };
4344: bp->ident |= Runs_ff; bp->ident &= ~(Runs_f|Runs_seek|Runs_g4);
4345: return(stat);
4346: }
4347: else if(etc&Runs_seek) {
4348: bp->ident |= Runs_seek; bp->ident &= ~(Runs_ff|Runs_f);
4349: bp->r.seek=ftell(fp); /* save seek addr */
4350: /* skip past runs */
4351: if(bp->ident&Blob_small)
4352: fseek(fp,(long)((bp->runs)*sizeof(RunFS)),1);
4353: else fseek(fp,(long)((bp->runs)*sizeof(RunF)),1);
4354: }
4355: else /* (etc&Runs_f) || (etc&Runs_g4) */ {
4356: abort("frdb_blob_etc: Runs_f & Runs_g4 etc option unimplemented");
4357: };
4358: if(ferror(fp)) return(-errno); else return(1);
4359: }
4360:
4361: /* read a number of blobs, and their parts, into linked-list (mny, *fi);
4362: return T iff not EOF */
4363: boolean frdb_blobl_etc(fp,bmny,fip,etc)
4364: FILE *fp;
4365: int bmny;
4366: Blob **fip;
4367: Ident etc;
4368: { int bi;
4369: register Blob *bp,**bpp;
4370: RunF *rp;
4371: int stat;
4372: if(bmny<=0) return(1);
4373: bi=0; bpp=fip;
4374: do { bp=alloc_blob();
4375: if((stat=frdb_blob_etc(fp,bp,etc))!=1) return(stat);
4376: *bpp=bp; bpp= &(bp->n);
4377: }
4378: while((++bi)<bmny);
4379: *bpp=NULL;
4380: if(ferror(fp)) return(-errno); else return(1);
4381: }
4382:
4383: char *interp_toa(ip)
4384: Interp *ip;
4385: { static char s[80];
4386: char ms[3],shs[3],szs[3],hts[3],prs[3];
4387: strcpy(ms,merit_toa(ip->m));
4388: strcpy(shs,merit_toa(ip->mshap));
4389: strcpy(szs,merit_toa(ip->msize));
4390: strcpy(hts,merit_toa(ip->mbhgt));
4391: strcpy(prs,merit_toa(ip->p));
4392: sprintf(s,"%s %s sz%s ba%d m%s (sh%s sz%s ht%s) p%s",
4393: ident_toa(ip->ident),
4394: #if CPU!=CRAY
4395: classid_toa(&(ip->ci)),
4396: #else
4397: ip->ci.c,
4398: #endif
4399: pts_toa(ip->size),
4400: ip->basl,
4401: ms,shs,szs,hts,prs);
4402: return(s);
4403: }
4404:
4405: frdb_interpl_etc(fp,ilp,etc)
4406: FILE *fp;
4407: Interpl *ilp;
4408: Ident etc;
4409: { int ii,stat;
4410: Interp *ip,*pp;
4411: if(ilp->mny<=0) {
4412: *ilp = empty_Interpl;
4413: return(1);
4414: };
4415:
4416: for(ii=0; ii<ilp->mny; ii++) {
4417: ip=alloc_interp();
4418: if(ii==0) ilp->fi = ip;
4419: else pp->n = ip;
4420: if((stat=frdb_interp(fp,ip))!=1) return(stat);
4421: pp=ip;
4422: };
4423: ip->n = NULL;
4424: if(ferror(fp)) return(-errno); else return(1);
4425: }
4426:
4427: #if FRDI
4428: int frdb_interp(f,p)
4429: FILE *f;
4430: Interp *p;
4431: { int stat;
4432: *p = empty_Interp;
4433: if(feof(f))
4434: return(0);
4435: p->ident=frdi_Ident(f);
4436: frdi_ClassId(f,&(p->ci));
4437: p->mshap=frdi_Merit(f);
4438: p->size=frdi_Pts(f);
4439: p->msize=frdi_Merit(f);
4440: p->basl=frdi_Scoor(f);
4441: p->mbhgt=frdi_Merit(f);
4442: p->m=frdi_Merit(f);
4443: p->p=frdi_Prob(f);
4444: #if dbg_frdb
4445: if((!(p->ident&IsInterp))||(p->ident&(IsALL&(~IsInterp))))
4446: err("frdb_interp: %s",interp_toa(p));
4447: #endif
4448: if(ferror(f)) return(-errno); else return(1);
4449: }
4450: #else
4451: int frdb_interp(fp,ip)
4452: FILE *fp;
4453: Interp *ip;
4454: { InterpF inf;
4455: int stat;
4456: if((stat=fread(&inf,sizeof(InterpF),1,fp))!=1) {
4457: err("can't fread InterpF, status %d",stat);
4458: return(stat);
4459: };
4460: *ip = empty_Interp;
4461: ip->ident = inf.ident;
4462: ip->ci = inf.ci;
4463: ip->clp = NULL;
4464: ip->clsp = NULL;
4465: ip->mshap = inf.mshap;
4466: ip->size = inf.size;
4467: ip->msize = inf.msize;
4468: ip->basl = inf.basl;
4469: ip->mbhgt = inf.mbhgt;
4470: ip->m = inf.m;
4471: #if dbg_frdb
4472: if((!(ip->ident&IsInterp))||(ip->ident&(IsALL&(~IsInterp))))
4473: err("frdb_interp: %s",interp_toa(ip));
4474: #endif
4475: if(ferror(fp)) return(-errno); else return(1);
4476: }
4477: #endif
4478:
4479: free_interpl(ilp)
4480: Interpl *ilp;
4481: { int ii;
4482: Interp *ip,*np;
4483: if(ilp->mny>0) {
4484: for(ip=ilp->fi; ip!=NULL; ip=np) { np=ip->n; free_interp(ip); }
4485: ilp->mny=0;
4486: };
4487: ilp->fi=NULL;
4488: };
4489:
4490: fwrb_interpl_etc(fp,is,etc)
4491: FILE *fp;
4492: Interpl is;
4493: Ident etc;
4494: { Interp *ip;
4495: int ii;
4496: if(is.mny>0) for(ii=0,ip=is.fi; ii<is.mny; ii++,ip=ip->n)
4497: fwrb_interp_etc(fp,ip,etc);
4498: }
4499:
4500: /* remove this Interp from the Interp-list */
4501: remove_interpl(ip,ilp)
4502: Interp *ip;
4503: Interpl *ilp;
4504: { Interp *rp,*pp;
4505: if(ilp->mny==1) { /* frequent case */
4506: ilp->fi=NULL; ilp->mny=0;
4507: }
4508: else if(ilp->mny>1){
4509: pp=NULL;
4510: for(rp=ilp->fi; rp!=ip&&rp!=NULL; pp=rp,rp=rp->n) ;
4511: if(rp!=NULL) { /* remove from list */
4512: if(pp==NULL) ilp->fi=ip->n;
4513: else pp->n=ip->n;
4514: ilp->mny--;
4515: }
4516: else err("remove_interpl: can't - not found");
4517: }
4518: else err("remove_interpl: can't - Interpl empty");
4519: }
4520:
4521: /* prepend this Interp to the Interp-list */
4522: prepend_interpl(ip,ilp)
4523: Interp *ip;
4524: Interpl *ilp;
4525: { Interp *rp,*pp;
4526: ip->n = ilp->fi;
4527: ilp->fi = ip;
4528: ilp->mny++;
4529: }
4530:
4531: fwrb_interp_etc(fp,ip,etc)
4532: FILE *fp;
4533: Interp *ip;
4534: Ident etc;
4535: { fwrb_interp(fp,ip);
4536: }
4537:
4538: #if FWRI
4539: fwrb_interp(f,p)
4540: FILE *f;
4541: Interp *p;
4542: { InterpF inf;
4543: int stat;
4544: #if dbg_fwrb
4545: if((!(p->ident&IsInterp))||(p->ident&(IsALL&(~IsInterp))))
4546: err("fwrb_interp: %s",interp_toa(p));
4547: #endif
4548: fwri_Ident(f,p->ident);
4549: fwri_ClassId(f,&(p->ci));
4550: fwri_Merit(f,p->mshap);
4551: fwri_Pts(f,p->size);
4552: fwri_Merit(f,p->msize);
4553: fwri_Scoor(f,p->basl);
4554: fwri_Merit(f,p->mbhgt);
4555: fwri_Merit(f,p->m);
4556: fwri_Prob(f,p->p);
4557: #if dbg_fwrb_toa
4558: err("fwrb_interp: %s",interp_toa(p));
4559: #endif
4560: }
4561: #else
4562: fwrb_interp(fp,ip)
4563: FILE *fp;
4564: Interp *ip;
4565: { InterpF inf;
4566: int stat;
4567: #if dbg_fwrb
4568: if((!(ip->ident&IsInterp))||(ip->ident&(IsALL&(~IsInterp))))
4569: err("fwrb_interp: %s",interp_toa(ip));
4570: #endif
4571: memset(&inf,'\0',sizeof(inf));
4572: inf.ident = ip->ident;
4573: inf.ci = ip->ci;
4574: inf.mshap = ip->mshap;
4575: inf.size = ip->size;
4576: inf.msize = ip->msize;
4577: inf.basl = ip->basl;
4578: inf.mbhgt = ip->mbhgt;
4579: inf.m = ip->m;
4580: if((stat=fwrite(&inf,sizeof(InterpF),1,fp))!=1)
4581: abort("fwrb_interp: can't fwrite, status %d",stat);
4582: #if dbg_fwrb_toa
4583: err("fwrb_interp: %s",interp_toa(ip));
4584: #endif
4585: }
4586: #endif
4587:
4588: /** Run handling:
4589: alloc_run_pool -create pool of free run records
4590: free_run_pool - free entire pool
4591: alloc_run - allocate a new run from pool
4592: free_run - free a specified run (into pool)
4593: err_run - print Run (ascii) to stderr
4594: err_runb - print Run (ascii) to stderr (after added to blob set)
4595: err_runf - print RunF (ascii) to stderr (after added to blob set)
4596: err_runfs - print RunFS (ascii) to stderr (after added to blob set)
4597: err_run_stats - report statistics to stderr
4598: **/
4599:
4600: /* RunPool functions: variable-size pool, speed-optimized alloc/free */
4601:
4602: /* Initialize pool of Runs with increment `incr' (return F if can't allocate) */
4603: boolean alloc_run_pool(incr,dbg)
4604: int incr;
4605: boolean dbg; /* trace actions on Runs */
4606: { register Run *crp, *prp;
4607: register int i;
4608: _RunPool.incr = incr;
4609: _RunPool.pools = 1;
4610: if((_RunPool.pool=(Run **)malloc(_RunPool.pools*sizeof(Run *)))==NULL)
4611: return(F);
4612: if((_RunPool.pool[_RunPool.pools-1] =
4613: (Run *)malloc(_RunPool.incr*sizeof(Run)))==NULL) {
4614: free(_RunPool.pool);
4615: return(F);
4616: };
4617: _RunPool.next = 0;
4618: _RunPool.free = NULL;
4619: #if STATS
4620: _RunPool.total = 0;
4621: #endif
4622: _RunPool.dbg = dbg;
4623: if(_RunPool.dbg) err("alloc_run_pool: incr%d",_RunPool.incr);
4624: return(T);
4625: }
4626:
4627: free_run_pool()
4628: { register int i;
4629: for(i=0; i<_RunPool.pools; i++) free(_RunPool.pool[i]);
4630: free(_RunPool.pool);
4631: }
4632:
4633: /* The ``hard'' case of allocating runs from RunPool: can't be inline */
4634: Run *hard_alloc_run()
4635: { _RunPool.pools++;
4636: if((_RunPool.pool=
4637: (Run **)realloc(_RunPool.pool,_RunPool.pools*sizeof(Run *)))==NULL)
4638: abort("alloc_Run: can't realloc");
4639: if((_RunPool.cur=_RunPool.pool[_RunPool.pools-1] =
4640: (Run *)malloc(_RunPool.incr*sizeof(Run)))==NULL)
4641: abort("alloc_Run: can't malloc");
4642: _RunPool.next=1;
4643: *(_RunPool.cur) = empty_Run;
4644: return(_RunPool.cur);
4645: }
4646:
4647: int rp_tod(rp)
4648: Run *rp;
4649: { return((int)rp);
4650: }
4651:
4652: char *runf_toa(rp)
4653: RunF *rp;
4654: { static char s[80];
4655: char s1[80];
4656: strcpy(s,"RunF ");
4657: if(rp==NULL) strcat(s,"NULL");
4658: else { sprintf(s1,
4659: "y%d,x[%d,%d] lag(ad%d,bd%d ac%d,bc%d)",
4660: rp->y,rp->xs,rp->xe,
4661: rp->ad,rp->bd, rp->ac,rp->bc );
4662: strcat(s,s1);
4663: };
4664: return(s);
4665: }
4666:
4667: char *runfs_toa(rp)
4668: RunFS *rp;
4669: { static char s[80];
4670: char s1[80];
4671: strcpy(s,"RunFS ");
4672: if(rp==NULL) strcat(s,"NULL");
4673: else { sprintf(s1,
4674: "y%d,x[%d,%d] lag(ad%d,bd%d ac%d,bc%d)",
4675: rp->y,rp->xs,rp->xe,
4676: rp->ad,rp->bd, rp->ac,rp->bc );
4677: strcat(s,s1);
4678: };
4679: return(s);
4680: }
4681:
4682: err_run(s,rp)
4683: char *s;
4684: Run *rp;
4685: { fprintf(stderr,"%s ",s);
4686: if(rp==NULL) fprintf(stderr,"Run NULL.\n");
4687: else fprintf(stderr,
4688: "Run %d: y%d,x[%d,%d] l(n%d) t(o%x ad%d,bd%d ac%d,bc%d)\n",
4689: rp_tod(rp), rp->y,rp->xs,rp->xe,
4690: rp_tod(rp->n),
4691: #if CPU!=CRAY
4692: (int)rp->u.o,
4693: #else
4694: 0,
4695: #endif
4696: rp->ad,rp->bd,
4697: rp_tod(rp->ac),
4698: rp_tod(rp->bc) );
4699: }
4700:
4701: /* print Run after it has been added to Blob set */
4702: err_runb(s,rp)
4703: char *s;
4704: Run *rp;
4705: { fprintf(stderr,"%s ",s);
4706: if(rp==NULL) fprintf(stderr,"Run NULL.\n");
4707: else fprintf(stderr,
4708: "Run %d: y%d,x[%d,%d] l(n%d) t(no%d ad%d,bd%d ac%d,bc%d)\n",
4709: rp_tod(rp), rp->y,rp->xs,rp->xe,
4710: rp_tod(rp->n),
4711: rp->u.no, rp->ad,rp->bd, rp_tod(rp->ac),rp_tod(rp->bc) );
4712: }
4713:
4714: err_runf(s,rp)
4715: char *s;
4716: RunF *rp;
4717: { fprintf(stderr,"%s ",s);
4718: if(rp==NULL) fprintf(stderr,"RunF NULL.\n");
4719: else fprintf(stderr,
4720: "RunF: y%d,x[%d,%d] t(ad%d,bd%d ac%d,bc%d)\n",
4721: rp->y,rp->xs,rp->xe,
4722: rp->ad,rp->bd, rp->ac,rp->bc );
4723: }
4724:
4725: err_runfs(s,rp)
4726: char *s;
4727: RunFS *rp;
4728: { RunF rf;
4729: rf.y = 0377&rp->y;
4730: rf.xs = 0377&rp->xs;
4731: rf.xe = 0377&rp->xe;
4732: rf.ad = 0377&rp->ad;
4733: rf.bd = 0377&rp->bd;
4734: rf.ac = 0377&rp->ac;
4735: rf.bc = 0377&rp->bc;
4736: err_runf(s,&rf);
4737: }
4738:
4739: int runs_of_blob(p,ra,max)
4740: Blob *p;
4741: RLE_Yrun *ra;
4742: int max;
4743: { int runs,ri;
4744: RunF *rfp;
4745: runs = p->runs;
4746: if(runs>max) {
4747: err("runs_of_blob: max exceeded - skip this blob");
4748: runs = 0;
4749: }
4750: else if(runs>0) {
4751: if(p->ident&Runs_ff) {
4752: for(ri=0,rfp=p->r.ff; ri<runs; ri++,rfp++) {
4753: ra->y = p->bx.a.y + rfp->y;
4754: ra->xs = p->bx.a.x + rfp->xs;
4755: ra->xe = p->bx.a.x + rfp->xe;
4756: ra++;
4757: };
4758: }
4759: else { err("runs_of_blob: handle only Runs_ff - skip this blob");
4760: runs = 0;
4761: };
4762: };
4763: return(runs);
4764: }
4765:
4766: int no_runs_of_blobl(p)
4767: Blobl *p;
4768: { int runs;
4769: Blob *pp;
4770: runs = 0;
4771: if(p->mny>0) for(pp=p->fi; pp!=NULL; pp=pp->n) runs += pp->runs;
4772: return(runs);
4773: }
4774:
4775: int runs_of_blobl(p,ra,max)
4776: Blobl *p;
4777: RLE_Yrun *ra;
4778: int max;
4779: { int runs;
4780: Blob *pp;
4781: runs = 0;
4782: if(p->mny>0) for(pp=p->fi; pp!=NULL; pp=pp->n)
4783: runs += runs_of_blob(pp,ra+runs,max-runs);
4784: return(runs);
4785: }
4786:
4787: int no_runs_of_char(p)
4788: Char *p;
4789: { int runs;
4790: Blobl bl;
4791: runs = 0;
4792: bl.mny = p->bmny; bl.fi = p->fi;
4793: runs += no_runs_of_blobl(&bl);
4794: return(runs);
4795: }
4796:
4797: int runs_of_char(p,ra,max)
4798: Char *p;
4799: RLE_Yrun *ra;
4800: int max;
4801: { int runs;
4802: Blobl bl;
4803: runs = 0;
4804: bl.mny = p->bmny; bl.fi = p->fi;
4805: runs += runs_of_blobl(&bl,ra,max);
4806: return(runs);
4807: }
4808:
4809: /* ascending lexicographic order on y,xs */
4810: int rn_asc(r1,r2)
4811: RLE_Yrun *r1,*r2;
4812: { if(r1->y < r2->y) return(-1);
4813: else if(r1->y==r2->y) {
4814: if(r1->xs < r2->xs) return(-1);
4815: else if (r1->xs == r2->xs) return(0);
4816: else return(1);
4817: }
4818: else return(1);
4819: }
4820:
4821: RLE_Lines *rlines_of_char(chp)
4822: Char *chp;
4823: { static RLE_Lines rls;
4824: int no_runs,cy,ri;
4825: RLE_Run *lr;
4826: RLE_Yrun *ra,*cr;
4827: RLE_Line *cl;
4828: /* count runs */
4829: no_runs = no_runs_of_char(chp);
4830: /* allocate runs array */
4831: if((ra=(RLE_Yrun *)malloc(no_runs*sizeof(RLE_Yrun)))==NULL)
4832: abort("rlines_of_char: can't malloc ra[%d]",no_runs);
4833: runs_of_char(chp,ra,no_runs);
4834: /* sort runs ascending on (y,xs) */
4835: qsort(ra,no_runs,sizeof(RLE_Yrun),rn_asc);
4836: /* count RLE_lines.mny */
4837: rls.mny = 0; cy=Scoor_MIN;
4838: for(ri=0,cr=ra; ri<no_runs; ri++,cr++)
4839: if(cr->y!=cy) {
4840: rls.mny++;
4841: cy = cr->y;
4842: };
4843: /* allocate RLE_lines */
4844: if((rls.rla=(RLE_Line *)malloc(rls.mny*sizeof(RLE_Line)))==NULL)
4845: abort("rlines_of_page: can't malloc rls.rla[%d]",rls.mny);
4846: /* fill in RLE_lines */
4847: cy=Scoor_MIN; cl=rls.rla-1;
4848: for(ri=0,cr=ra; ri<no_runs; ri++,cr++) {
4849: if(cr->y!=cy) {
4850: cl++;
4851: cl->y = cy = cr->y;
4852: cl->runs = 0;
4853: lr = cl->r;
4854: };
4855: lr->xs = cr->xs; lr->xe = cr->xe; lr++; cl->runs++;
4856: };
4857: free(ra);
4858: return(&rls);
4859: }
4860:
4861: int asc_merit(m1,m2)
4862: Merit *m1,*m2;
4863: { if(*m1 < *m2) return(-1);
4864: else if(*m1 > *m2) return(1);
4865: else return(0);
4866: }
4867:
4868: /* Word merit is computed as a function of the merit of its Chars.
4869: No Chars forces merit to 0.0.
4870: The result is dominated by the weakest merit in the Word, slightly
4871: improved by the others. */
4872: Merit wordmerit(w)
4873: Word *w;
4874: { register Char *cp,**cpp;
4875: static int m_alloc = 0;
4876: static Merit *ma; /* ma[m_alloc] */
4877: int mi;
4878: Merit m;
4879: double wgt,sumwgt;
4880:
4881: if(w->cs.mny<=0) return(0.0);
4882: if(w->cs.mny>m_alloc) {
4883: if(m_alloc==0) {
4884: m_alloc=w->cs.mny;
4885: if((ma=(Merit *)malloc(m_alloc*sizeof(Merit)))==NULL)
4886: abort("wordmerit: can't malloc ma[%d]",m_alloc);
4887: }
4888: else { m_alloc=w->cs.mny;
4889: if((ma=(Merit *)realloc(ma,m_alloc*sizeof(Merit)))==NULL)
4890: abort("wordmerit: can't realloc ma[%d]",m_alloc);
4891: };
4892: };
4893: for(cp= *(cpp=w->cs.cpa),mi=0; cp!=NULL; cp= *(++cpp),mi++) {
4894: if(cp->area==0 || cp->il.mny==0) ma[mi]=0.0;
4895: else ma[mi] = cp->il.fi->m;
4896: };
4897: qsort(ma,w->cs.mny,sizeof(Merit),asc_merit);
4898: #define DOM (5.0)
4899: /* The worst merit is DOM times more significant than second worst, which
4900: is DOM times more significant than the third worst, and so on.
4901: */
4902: m=ma[0]; sumwgt=wgt=1.0;
4903: for(mi=1; mi<w->cs.mny; mi++) {
4904: m += ma[mi]*(wgt /= DOM); sumwgt += wgt;
4905: };
4906: m /= sumwgt;
4907: return(m);
4908: }
4909:
4910: WordSet *alloc_wordset(top,cut,cap)
4911: double top; /* initial maximum merit (is never reduced) */
4912: double cut; /* cut ratio: don't keep merit < cut*top */
4913: int cap; /* capacity: maximum no. at a time (0 ==> no limit) */
4914: { WordSet *res;
4915: if((res=(WordSet *)malloc(sizeof(WordSet)))==NULL)
4916: abort("alloc_wordset: can't");
4917: *res = empty_WordSet;
4918: res->top = top;
4919: res->cut = cut;
4920: if((res->cap = cap)==0) res->cap=INT_MAX;
4921: return(res);
4922: }
4923:
4924: int free_wordset_etc(s,etc)
4925: WordSet *s;
4926: Ident etc;
4927: { int high;
4928: free_words_etc(&(s->ws),etc);
4929: high = s->high;
4930: free(s);
4931: return(high);
4932: }
4933:
4934: /* Find the maximum-merit word in the set; among ties, pick the first seen. */
4935: Word *find_max_wordset(s)
4936: WordSet *s;
4937: { register Word *max,**wpp;
4938: max=NULL;
4939: if(s->ws.mny>0) for(wpp=s->ws.wpa; *wpp!=NULL; wpp++) {
4940: if(max==NULL || max->m < (*wpp)->m) max=(*wpp);
4941: };
4942: return(max);
4943: }
4944:
4945: /* Find the maximum-merit word in the set; among ties, pick the last seen. */
4946: Word *find_min_wordset(s)
4947: WordSet *s;
4948: { register Word *min,**wpp;
4949: min=NULL;
4950: if(s->ws.mny>0) for(wpp=s->ws.wpa; *wpp!=NULL; wpp++) {
4951: if(min==NULL || min->m >= (*wpp)->m) min=(*wpp);
4952: };
4953: return(min);
4954: }
4955:
4956: /* Insert a Word (without duplicating it).
4957: Update top, min, max, & high.
4958: If the new word's merit is equal to the current maximum, it does not become
4959: become the new maximum.
4960: If the new word's merit is equal to the current minimum, it becomes
4961: the new minimum.
4962: */
4963: put_wordset(w,s)
4964: Word *w; /* must have w->m set up */
4965: WordSet *s;
4966: { insert_word(w,&(s->ws));
4967: if(max_wordset(s)==NULL || max_wordset(s)->m < w->m) {
4968: max_wordset(s) = w;
4969: if(s->top < max_wordmerit(s)) s->top = max_wordmerit(s);
4970: };
4971: if(min_wordset(s)==NULL || min_wordset(s)->m >= w->m)
4972: min_wordset(s) = w;
4973: if(s->high < s->ws.mny) s->high = s->ws.mny;
4974: }
4975:
4976: /* Remove a Word (without freeing it). Maintain min/max, but don't prune items.
4977: Also, don't lower top or high. */
4978: Word *get_wordset(w,s)
4979: Word *w;
4980: WordSet *s;
4981: { if(w==NULL || s->ws.mny==0) return(NULL);
4982: remove_word(w,&s->ws);
4983: if(s->ws.mny==0) {
4984: max_wordset(s) = NULL;
4985: min_wordset(s) = NULL;
4986: }
4987: else { if(w==max_wordset(s)) max_wordset(s) = find_max_wordset(s);
4988: if(w==min_wordset(s)) min_wordset(s) = find_min_wordset(s);
4989: };
4990: return(w);
4991: }
4992:
4993: /* Remove a Word (without freeing it). Maintain min/max. Don't lower top. */
4994: Word *remove_wordset(w,s,n)
4995: Word *w;
4996: WordSet *s;
4997: char *n;
4998: { register Word *gw;
4999: #if dbg_ws
5000: if(w!=NULL) err("remove_wordset: %X %s",w,word_toa(w));
5001: else err("remove_wordset: NULL");
5002: #endif
5003: gw=get_wordset(w,s);
5004: #if dbg_ws
5005: err_wordset(s,n);
5006: #endif
5007: return(gw);
5008: }
5009:
5010: /* Check whether a given Word is identical to any already in a given set.
5011: Word *w must have its hash key set up. */
5012: boolean member_wordset(w,s)
5013: Word *w;
5014: WordSet *s;
5015: { register Word **ww;
5016: if(s->ws.mny>0) {
5017: for(ww=s->ws.wpa; (*ww)!=NULL; ww++) {
5018: if(w->hash==(*ww)->hash && eq_word(w,(*ww)))
5019: return(T);
5020: };
5021: };
5022: return(F);
5023: }
5024:
5025: /* Insert a Word into a set, maintaining uniqueness, a ``range'' property, and
5026: a maximum capacity.
5027: Uniqueness is maintained by refusing to insert words that are identical
5028: (eq_word()) to a word already in the set (or in set `u').
5029: The range property is that every word in the set must have merit no less
5030: than `s->cut' times the lifetime maximum for the set `s->top'.
5031: Maximum capacity is maintained as follows: if insertion would mean more
5032: members than `cap', then either (a) the insertion is refused (if its
5033: merit is less than the current `min', or (b) the current `min' is deleted
5034: (and silently freed in its entirety), and the insertion occurs.
5035: The inserted Word is not duplicated. If, as a result of an insertion,
5036: some of its words no longer satisfy the range property, they are silently
5037: removed (and freed in their entirety).
5038: Return T iff the Word is actually inserted.
5039: */
5040: boolean insert_wordset(w,s,n,u)
5041: Word *w;
5042: WordSet *s;
5043: char *n; /* name of set `s' */
5044: WordSet *u; /* if !=NULL, also check uniqueness here */
5045: { Word *fr;
5046: #if dbg_ws
5047: err("insert_wordset: %X %s",w,word_toa(w));
5048: #endif
5049: if((w->m = wordmerit(w)) >= (s->cut * s->top)) {
5050: w->hash = hash_word(w);
5051: if(member_wordset(w,s) || (u!=NULL&&member_wordset(w,u)))
5052: /* don't insert */
5053: return(F);
5054: if(s->ws.mny==s->cap) /* at capacity */ {
5055: if(w->m <= min_wordmerit(s)) /* too poor */ return(F);
5056: else { fr = remove_wordset(min_wordset(s),s);
5057: free_word_etc(fr,IsALL);
5058: };
5059: };
5060: put_wordset( w, s );
5061: if(max_wordset(s)==w) /* this has become the new maximum */ {
5062: while(min_wordmerit(s) < (s->cut * s->top)) {
5063: fr = remove_wordset(min_wordset(s),s);
5064: free_word_etc(fr,IsALL);
5065: };
5066: };
5067: #if dbg_ws
5068: err_wordset(s,n);
5069: #endif
5070: return(T);
5071: }
5072: else {
5073: #if dbg_ws
5074: err_wordset(s,n);
5075: #endif
5076: return(F);
5077: };
5078: }
5079:
5080: err_wordset(s,n)
5081: WordSet *s;
5082: char *n; /* name of set */
5083: { char m1[10],m2[10];
5084: register Word *wp,**wpp;
5085: fprintf( stderr,"WordSet %s: t%g c%g [%s/%X,%s/%X] m%d h%d: ",
5086: n,
5087: s->top,s->cut,
5088: strcpy(m1,merit_toa(max_wordmerit(s))),max_wordset(s),
5089: strcpy(m2,merit_toa(min_wordmerit(s))),min_wordset(s),
5090: s->ws.mny,s->high );
5091: if(s->ws.mny>0) for(wp= *(wpp=s->ws.wpa); wp!=NULL; wp= *(++wpp))
5092: fprintf(stderr,"%X/%s/%d ",wp,merit_toa(wp->m),wp->cs.mny);
5093: fprintf(stderr,"\n");
5094: }
5095:
5096: translate_txtln(lp,off)
5097: Txtln *lp;
5098: Sp off;
5099: { lp->bx = *translate_bbx(&lp->bx,off);
5100: lp->basl += off.y;
5101: translate_chars(lp->cs,off);
5102: }
5103:
5104: translate_chars(csp,off)
5105: Chars *csp;
5106: Sp off;
5107: { register Char *cp,**cpp;
5108: for(cp= *(cpp=csp->cpa); cp!=NULL; cp= *(++cpp))
5109: translate_char(cp,off);
5110: }
5111:
5112: translate_char(cp,off)
5113: Char *cp;
5114: Sp off;
5115: { cp->bx = *translate_bbx(&cp->bx,off);
5116: translate_blobl(cp,off);
5117: }
5118:
5119: translate_blobs(b,off)
5120: Blobs *b;
5121: Sp off;
5122: { register Blob *bp,**bpp;
5123: if(b->mny>0) for ( bp= *(bpp=b->bpa); bp!=NULL; bp= *(++bpp) )
5124: translate_blob(bp,off);
5125: }
5126:
5127: translate_blobl(cp,off)
5128: Char *cp;
5129: Sp off;
5130: { int bi;
5131: register Blob *bp;
5132: for(bi=0,bp=cp->fi; bi<cp->bmny&&bp!=NULL; bi++,bp=bp->n)
5133: translate_blob(bp,off);
5134: }
5135:
5136: translate_blob(bp,off)
5137: Blob *bp;
5138: Sp off;
5139: { bp->bx = *translate_bbx(&bp->bx,off);
5140: }
5141:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.