|
|
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.