Annotation of parser3/src/lib/cord/cordxtra.c, revision 1.16

1.2       paf         1: /*
                      2:  * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
                      3:  *
                      4:  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
                      5:  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
                      6:  *
                      7:  * Permission is hereby granted to use or copy this program
                      8:  * for any purpose,  provided the above notices are retained on all copies.
                      9:  * Permission to modify the code and to distribute modified code is granted,
                     10:  * provided the above notices are retained, and a notice that the code was
                     11:  * modified is included with the above copyright notice.
                     12:  *
                     13:  * Author: Hans-J. Boehm (boehm@parc.xerox.com)
                     14:  */
                     15: /*
                     16:  * These are functions on cords that do not need to understand their
                     17:  * implementation.  They serve also serve as example client code for
                     18:  * cord_basics.
                     19:  */
                     20: /* Boehm, December 8, 1995 1:53 pm PST */
1.16    ! moko       21: 
1.7       paf        22: #include "pa_config_includes.h"
1.16    ! moko       23: #include "cord.h"
        !            24: #include "ec.h"
1.9       misha      25: 
1.2       paf        26: # define I_HIDE_POINTERS       /* So we get access to allocation lock. */
                     27:                                /* We use this for lazy file reading,   */
                     28:                                /* so that we remain independent        */
                     29:                                /* of the threads primitives.           */
                     30: # include "gc.h"
                     31: 
                     32: /* For now we assume that pointer reads and writes are atomic,         */
                     33: /* i.e. another thread always sees the state before or after   */
                     34: /* a write.  This might be false on a Motorola M68K with       */
                     35: /* pointers that are not 32-bit aligned.  But there probably   */
                     36: /* aren't too many threads packages running on those.          */
                     37: # define ATOMIC_WRITE(x,y) (x) = (y)
                     38: # define ATOMIC_READ(x) (*(x))
                     39: 
                     40: /* The standard says these are in stdio.h, but they aren't always: */
                     41: # ifndef SEEK_SET
                     42: #   define SEEK_SET 0
                     43: # endif
                     44: # ifndef SEEK_END
                     45: #   define SEEK_END 2
                     46: # endif
                     47: 
                     48: # define BUFSZ 2048    /* Size of stack allocated buffers when         */
                     49:                        /* we want large buffers.                       */
                     50: 
                     51: typedef void (* oom_fn)(void);
                     52: 
                     53: # define OUT_OF_MEMORY {  if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
                     54:                          ABORT("Out of memory\n"); }
                     55: # define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
                     56: 
                     57: CORD CORD_cat_char(CORD x, char c)
                     58: {
                     59:     register char * string;
                     60:     
                     61:     if (c == '\0') return(CORD_cat(x, CORD_nul(1)));
                     62:     string = GC_MALLOC_ATOMIC(2);
                     63:     if (string == 0) OUT_OF_MEMORY;
                     64:     string[0] = c;
                     65:     string[1] = '\0';
                     66:     return(CORD_cat_char_star(x, string, 1));
                     67: }
                     68: 
                     69: CORD CORD_catn(int nargs, ...)
                     70: {
                     71:     register CORD result = CORD_EMPTY;
                     72:     va_list args;
                     73:     register int i;
                     74: 
                     75:     va_start(args, nargs);
                     76:     for (i = 0; i < nargs; i++) {
                     77:         register CORD next = va_arg(args, CORD);
                     78:         result = CORD_cat(result, next);
                     79:     }
                     80:     va_end(args);
                     81:     return(result);
                     82: }
                     83: 
                     84: typedef struct {
                     85:        size_t len;
                     86:        size_t count;
                     87:        char * buf;
                     88: } CORD_fill_data;
                     89: 
                     90: int CORD_fill_proc(char c, void * client_data)
                     91: {
                     92:     register CORD_fill_data * d = (CORD_fill_data *)client_data;
                     93:     register size_t count = d -> count;
                     94:     
                     95:     (d -> buf)[count] = c;
                     96:     d -> count = ++count;
                     97:     if (count >= d -> len) {
                     98:        return(1);
                     99:     } else {
                    100:        return(0);
                    101:     }
                    102: }
                    103: 
                    104: int CORD_batched_fill_proc(const char*  s, void * client_data)
                    105: {
                    106:     register CORD_fill_data * d = (CORD_fill_data *)client_data;
                    107:     register size_t count = d -> count;
                    108:     register size_t max = d -> len;
                    109:     register char * buf = d -> buf;
                    110:     register const char*  t = s;
                    111:     
                    112:     while((buf[count] = *t++) != '\0') {
                    113:         count++;
                    114:         if (count >= max) {
                    115:             d -> count = count;
                    116:             return(1);
                    117:         }
                    118:     }
                    119:     d -> count = count;
                    120:     return(0);
                    121: }
                    122: 
                    123: /* Fill buf with len characters starting at i.                         */
                    124: /* Assumes len characters are available.                               */ 
                    125: void CORD_fill_buf(CORD x, size_t i, size_t len, char * buf)
                    126: {
                    127:     CORD_fill_data fd;
                    128:     
                    129:     fd.len = len;
                    130:     fd.buf = buf;
                    131:     fd.count = 0;
                    132:     (void)CORD_iter5(x, i, CORD_fill_proc, CORD_batched_fill_proc, &fd);
                    133: }
                    134: 
                    135: int CORD_cmp(CORD x, CORD y)
                    136: {
                    137:     CORD_pos xpos;
                    138:     CORD_pos ypos;
                    139:     register size_t avail, yavail;
                    140:     
                    141:     if (y == CORD_EMPTY) return(x != CORD_EMPTY);
                    142:     if (x == CORD_EMPTY) return(-1);
1.15      misha     143:        if (x == y) return (0);
1.2       paf       144:     if (CORD_IS_STRING(y) && CORD_IS_STRING(x)) return(strcmp(x,y));
                    145:     CORD_set_pos(xpos, x, 0);
                    146:     CORD_set_pos(ypos, y, 0);
                    147:     for(;;) {
                    148:         if (!CORD_pos_valid(xpos)) {
                    149:             if (CORD_pos_valid(ypos)) {
                    150:                return(-1);
                    151:             } else {
                    152:                 return(0);
                    153:             }
                    154:         }
                    155:         if (!CORD_pos_valid(ypos)) {
                    156:             return(1);
                    157:         }
                    158:         if ((avail = CORD_pos_chars_left(xpos)) <= 0
                    159:             || (yavail = CORD_pos_chars_left(ypos)) <= 0) {
                    160:             register char xcurrent = CORD_pos_fetch(xpos);
                    161:             register char ycurrent = CORD_pos_fetch(ypos);
                    162:             if (xcurrent != ycurrent) return(xcurrent - ycurrent);
                    163:             CORD_next(xpos);
                    164:             CORD_next(ypos);
                    165:         } else {
                    166:             /* process as many characters as we can    */
                    167:             register int result;
                    168:             
                    169:             if (avail > yavail) avail = yavail;
                    170:             result = strncmp(CORD_pos_cur_char_addr(xpos),
                    171:                             CORD_pos_cur_char_addr(ypos), avail);
                    172:             if (result != 0) return(result);
                    173:             CORD_pos_advance(xpos, avail);
                    174:             CORD_pos_advance(ypos, avail);
                    175:         }
                    176:     }
                    177: }
                    178: 
                    179: int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
                    180: {
                    181:     CORD_pos xpos;
                    182:     CORD_pos ypos;
                    183:     register size_t count;
                    184:     register long avail, yavail;
                    185:     
                    186:     CORD_set_pos(xpos, x, x_start);
                    187:     CORD_set_pos(ypos, y, y_start);
                    188:     for(count = 0; count < len;) {
                    189:         if (!CORD_pos_valid(xpos)) {
                    190:             if (CORD_pos_valid(ypos)) {
                    191:                return(-1);
                    192:             } else {
                    193:                 return(0);
                    194:             }
                    195:         }
                    196:         if (!CORD_pos_valid(ypos)) {
                    197:             return(1);
                    198:         }
                    199:         if ((avail = CORD_pos_chars_left(xpos)) <= 0
                    200:             || (yavail = CORD_pos_chars_left(ypos)) <= 0) {
                    201:             register char xcurrent = CORD_pos_fetch(xpos);
                    202:             register char ycurrent = CORD_pos_fetch(ypos);
                    203:             if (xcurrent != ycurrent) return(xcurrent - ycurrent);
                    204:             CORD_next(xpos);
                    205:             CORD_next(ypos);
                    206:             count++;
                    207:         } else {
                    208:             /* process as many characters as we can    */
                    209:             register int result;
                    210:             
                    211:             if (avail > yavail) avail = yavail;
                    212:             count += avail;
                    213:             if (count > len) avail -= (count - len);
                    214:             result = strncmp(CORD_pos_cur_char_addr(xpos),
                    215:                             CORD_pos_cur_char_addr(ypos), (size_t)avail);
                    216:             if (result != 0) return(result);
                    217:             CORD_pos_advance(xpos, (size_t)avail);
                    218:             CORD_pos_advance(ypos, (size_t)avail);
                    219:         }
                    220:     }
                    221:     return(0);
                    222: }
                    223: 
1.13      misha     224: char * CORD_to_char_star(CORD x, size_t len)
1.2       paf       225: {
1.13      misha     226:        char * result;
                    227:     if(0 == len) len = CORD_len(x);
                    228:     result = GC_MALLOC_ATOMIC(len + 1);
1.2       paf       229:     
                    230:     if (result == 0) OUT_OF_MEMORY;
                    231:     CORD_fill_buf(x, 0, len, result);
                    232:     result[len] = '\0';
                    233:     return(result);
                    234: }
                    235: 
                    236: CORD CORD_from_char_star(const char* s)
                    237: {
                    238:     char * result;
                    239:     size_t len = strlen(s);
                    240: 
                    241:     if (0 == len) return(CORD_EMPTY);
                    242:     result = GC_MALLOC_ATOMIC(len + 1);
                    243:     if (result == 0) OUT_OF_MEMORY;
                    244:     memcpy(result, s, len+1);
                    245:     return(result);
                    246: }
                    247: 
1.13      misha     248: const char*  CORD_to_const_char_star(CORD x, size_t len)
1.2       paf       249: {
                    250:     if (x == 0) return("");
                    251:     if (CORD_IS_STRING(x)) return((const char* )x);
1.13      misha     252:     return(CORD_to_char_star(x, len));
1.2       paf       253: }
                    254: 
                    255: char CORD_fetch(CORD x, size_t i)
                    256: {
                    257:     CORD_pos xpos;
                    258:     
                    259:     CORD_set_pos(xpos, x, i);
                    260:     if (!CORD_pos_valid(xpos)) ABORT("bad index?");
                    261:     return(CORD_pos_fetch(xpos));
                    262: }
                    263: 
                    264: 
                    265: int CORD_put_proc(char c, void * client_data)
                    266: {
                    267:     register FILE * f = (FILE *)client_data;
                    268:     
                    269:     return(putc(c, f) == EOF);
                    270: }
                    271: 
                    272: int CORD_batched_put_proc(const char*  s, void * client_data)
                    273: {
                    274:     register FILE * f = (FILE *)client_data;
                    275:     
                    276:     return(fputs(s, f) == EOF);
                    277: }
                    278:     
                    279: 
                    280: int CORD_put(CORD x, FILE * f)
                    281: {
                    282:     if (CORD_iter5(x, 0, CORD_put_proc, CORD_batched_put_proc, f)) {
                    283:         return(EOF);
                    284:     } else {
                    285:        return(1);
                    286:     }
                    287: }
                    288: 
                    289: typedef struct {
                    290:     size_t pos;                /* Current position in the cord */
                    291:     char target;       /* Character we're looking for  */
                    292: } chr_data;
                    293: 
                    294: int CORD_chr_proc(char c, void * client_data)
                    295: {
                    296:     register chr_data * d = (chr_data *)client_data;
                    297:     
                    298:     if (c == d -> target) return(1);
                    299:     (d -> pos) ++;
                    300:     return(0);
                    301: }
1.4       paf       302:           
1.2       paf       303: int CORD_rchr_proc(char c, void * client_data)
                    304: {
                    305:     register chr_data * d = (chr_data *)client_data;
                    306:     
                    307:     if (c == d -> target) return(1);
                    308:     (d -> pos) --;
                    309:     return(0);
                    310: }
                    311: 
                    312: int CORD_batched_chr_proc(const char* s, void * client_data)
                    313: {
                    314:     register chr_data * d = (chr_data *)client_data;
                    315:     register char * occ = strchr(s, d -> target);
                    316:     
                    317:     if (occ == 0) {
                    318:        d -> pos += strlen(s);
                    319:        return(0);
                    320:     } else {
                    321:        d -> pos += occ - s;
                    322:        return(1);
                    323:     }
                    324: }
                    325: 
                    326: size_t CORD_chr(CORD x, size_t i, int c)
                    327: {
                    328:     chr_data d;
                    329:     
                    330:     d.pos = i;
                    331:     d.target = c;
                    332:     if (CORD_iter5(x, i, CORD_chr_proc, CORD_batched_chr_proc, &d)) {
                    333:         return(d.pos);
                    334:     } else {
                    335:        return(CORD_NOT_FOUND);
                    336:     }
                    337: }
                    338: 
                    339: size_t CORD_rchr(CORD x, size_t i, int c)
                    340: {
                    341:     chr_data d;
                    342:     
                    343:     d.pos = i;
                    344:     d.target = c;
                    345:     if (CORD_riter4(x, i, CORD_rchr_proc, &d)) {
                    346:         return(d.pos);
                    347:     } else {
                    348:        return(CORD_NOT_FOUND);
                    349:     }
                    350: }
                    351: 
                    352: /* Find the first occurrence of s in x at position start or later.     */
                    353: /* This uses an asymptotically poor algorithm, which should typically  */
                    354: /* perform acceptably.  We compare the first few characters directly,  */
                    355: /* and call CORD_ncmp whenever there is a partial match.               */
                    356: /* This has the advantage that we allocate very little, or not at all. */
                    357: /* It's very fast if there are few close misses.                       */
1.13      misha     358: size_t CORD_str(CORD x, size_t start, CORD s, size_t xlen)
1.2       paf       359: {
                    360:     CORD_pos xpos;
                    361:     size_t slen;
                    362:     register size_t start_len;
                    363:     const char*  s_start;
                    364:     unsigned long s_buf = 0;   /* The first few characters of s        */
                    365:     unsigned long x_buf = 0;   /* Start of candidate substring.        */
                    366:                                /* Initialized only to make compilers   */
                    367:                                /* happy.                               */
                    368:     unsigned long mask = 0;
                    369:     register size_t i;
                    370:     register size_t match_pos;
                    371:     
                    372:     if (s == CORD_EMPTY) return(start);
                    373:     if (CORD_IS_STRING(s)) {
                    374:         s_start = s;
                    375:         slen = strlen(s);
                    376:     } else {
1.13      misha     377:         s_start = CORD_to_char_star(CORD_substr(s, 0, sizeof(unsigned long), 0), 0);
1.2       paf       378:         slen = CORD_len(s);
                    379:     }
                    380:     if (xlen < start || xlen - start < slen) return(CORD_NOT_FOUND);
                    381:     start_len = slen;
                    382:     if (start_len > sizeof(unsigned long)) start_len = sizeof(unsigned long);
                    383:     CORD_set_pos(xpos, x, start);
                    384:     for (i = 0; i < start_len; i++) {
                    385:         mask <<= 8;
                    386:         mask |= 0xff;
                    387:         s_buf <<= 8;
1.3       paf       388:         s_buf |= (unsigned char)s_start[i];
1.2       paf       389:         x_buf <<= 8;
1.5       paf       390:         x_buf |= (unsigned char)CORD_pos_fetch(xpos);
1.2       paf       391:         CORD_next(xpos);
                    392:     }
                    393:     for (match_pos = start; ; match_pos++) {
                    394:        if ((x_buf & mask) == s_buf) {
                    395:            if (slen == start_len ||
                    396:                CORD_ncmp(x, match_pos + start_len,
                    397:                          s, start_len, slen - start_len) == 0) {
                    398:                return(match_pos);
                    399:            }
                    400:        }
                    401:        if ( match_pos == xlen - slen ) {
                    402:            return(CORD_NOT_FOUND);
                    403:        }
                    404:        x_buf <<= 8;
1.5       paf       405:         x_buf |= (unsigned char)CORD_pos_fetch(xpos);
1.2       paf       406:         CORD_next(xpos);
                    407:     }
                    408: }
                    409: 
                    410: void CORD_ec_flush_buf(CORD_ec x)
                    411: {
                    412:     register size_t len = x[0].ec_bufptr - x[0].ec_buf;
                    413:     char * s;
                    414: 
                    415:     if (len == 0) return;
                    416:     s = GC_MALLOC_ATOMIC(len+1);
1.14      misha     417:     if (s == 0) OUT_OF_MEMORY;
1.2       paf       418:     memcpy(s, x[0].ec_buf, len);
                    419:     s[len] = '\0';
                    420:     x[0].ec_cord = CORD_cat_char_star(x[0].ec_cord, s, len);
                    421:     x[0].ec_bufptr = x[0].ec_buf;
                    422: }
                    423: 
                    424: void CORD_ec_append_cord(CORD_ec x, CORD s)
                    425: {
                    426:     CORD_ec_flush_buf(x);
                    427:     x[0].ec_cord = CORD_cat(x[0].ec_cord, s);
                    428: }
                    429: 
                    430: /*ARGSUSED*/
                    431: char CORD_nul_func(size_t i, void * client_data)
                    432: {
                    433:     return((char)(unsigned long)client_data);
1.4       paf       434: }
                    435: 
1.9       misha     436: #ifdef CORD_CHARS_CACHE
1.11      misha     437: static char* cord_chars_cache[256][15]={0};
1.9       misha     438: #endif
                    439: 
1.2       paf       440: CORD CORD_chars(char c, size_t i)
                    441: {
1.8       misha     442:        if (i>0 && i<16 /* SHORT_LIMIT */) {
1.10      misha     443:                register char* result;
1.9       misha     444: #ifdef CORD_CHARS_CACHE
1.11      misha     445:                if(cord_chars_cache[(unsigned char)c][i])
                    446:                        return((CORD) cord_chars_cache[(unsigned char)c][i]);
1.9       misha     447: #endif
1.8       misha     448:                result=GC_MALLOC_ATOMIC(i+1);
                    449:                if(result==0) OUT_OF_MEMORY;
                    450:                memset(result, c, i);
                    451:                result[i] = '\0';
1.9       misha     452: #ifdef CORD_CHARS_CACHE
1.11      misha     453:                cord_chars_cache[(unsigned char)c][i]=result;
1.9       misha     454: #endif
1.8       misha     455:                return((CORD) result);
                    456:        } else {
                    457:                return(CORD_from_fn(CORD_nul_func, (void *)(unsigned long)c, i));
                    458:        }
1.2       paf       459: }
                    460: 
                    461: CORD CORD_from_file_eager(FILE * f)
                    462: {
                    463:     register int c;
                    464:     CORD_ec ecord;
                    465:     
                    466:     CORD_ec_init(ecord);
                    467:     for(;;) {
                    468:         c = getc(f);
                    469:         if (c == 0) {
                    470:           /* Append the right number of NULs   */
                    471:           /* Note that any string of NULs is rpresented in 4 words,    */
                    472:           /* independent of its length.                                        */
                    473:             register size_t count = 1;
                    474:             
                    475:             CORD_ec_flush_buf(ecord);
                    476:             while ((c = getc(f)) == 0) count++;
                    477:             ecord[0].ec_cord = CORD_cat(ecord[0].ec_cord, CORD_nul(count));
                    478:         }
                    479:         if (c == EOF) break;
                    480:         CORD_ec_append(ecord, c);
                    481:     }
                    482:     (void) fclose(f);
                    483:     return(CORD_balance(CORD_ec_to_cord(ecord)));
                    484: }
                    485: 
                    486: /* The state maintained for a lazily read file consists primarily      */
                    487: /* of a large direct-mapped cache of previously read values.           */
                    488: /* We could rely more on stdio buffering.  That would have 2           */
                    489: /* disadvantages:                                                      */
                    490: /*     1) Empirically, not all fseek implementations preserve the      */
                    491: /*        buffer whenever they could.                                  */
                    492: /*     2) It would fail if 2 different sections of a long cord         */
                    493: /*        were being read alternately.                                 */
                    494: /* We do use the stdio buffer for read ahead.                          */
                    495: /* To guarantee thread safety in the presence of atomic pointer                */
                    496: /* writes, cache lines are always replaced, and never modified in      */
                    497: /* place.                                                              */
                    498: 
                    499: # define LOG_CACHE_SZ 14
                    500: # define CACHE_SZ (1 << LOG_CACHE_SZ)
                    501: # define LOG_LINE_SZ 9
                    502: # define LINE_SZ (1 << LOG_LINE_SZ)
                    503: 
                    504: typedef struct {
                    505:     size_t tag;
                    506:     char data[LINE_SZ];
                    507:        /* data[i%LINE_SZ] = ith char in file if tag = i/LINE_SZ        */
                    508: } cache_line;
                    509: 
                    510: typedef struct {
                    511:     FILE * lf_file;
                    512:     size_t lf_current; /* Current file pointer value */
                    513:     cache_line * volatile lf_cache[CACHE_SZ/LINE_SZ];
                    514: } lf_state;
                    515: 
                    516: # define MOD_CACHE_SZ(n) ((n) & (CACHE_SZ - 1))
                    517: # define DIV_CACHE_SZ(n) ((n) >> LOG_CACHE_SZ)
                    518: # define MOD_LINE_SZ(n) ((n) & (LINE_SZ - 1))
                    519: # define DIV_LINE_SZ(n) ((n) >> LOG_LINE_SZ)
                    520: # define LINE_START(n) ((n) & ~(LINE_SZ - 1))
                    521: 
                    522: typedef struct {
                    523:     lf_state * state;
                    524:     size_t file_pos;   /* Position of needed character. */
                    525:     cache_line * new_cache;
                    526: } refill_data;
                    527: 
                    528: /* Executed with allocation lock. */
                    529: static char refill_cache(client_data)
                    530: refill_data * client_data;
                    531: {
                    532:     register lf_state * state = client_data -> state;
                    533:     register size_t file_pos = client_data -> file_pos;
                    534:     FILE *f = state -> lf_file;
                    535:     size_t line_start = LINE_START(file_pos);
                    536:     size_t line_no = DIV_LINE_SZ(MOD_CACHE_SZ(file_pos));
                    537:     cache_line * new_cache = client_data -> new_cache;
                    538:     
                    539:     if (line_start != state -> lf_current
                    540:         && fseek(f, line_start, SEEK_SET) != 0) {
                    541:            ABORT("fseek failed");
                    542:     }
                    543:     if (fread(new_cache -> data, sizeof(char), LINE_SZ, f)
                    544:        <= file_pos - line_start) {
                    545:        ABORT("fread failed");
                    546:     }
                    547:     new_cache -> tag = DIV_LINE_SZ(file_pos);
                    548:     /* Store barrier goes here. */
                    549:     ATOMIC_WRITE(state -> lf_cache[line_no], new_cache);
                    550:     state -> lf_current = line_start + LINE_SZ;
                    551:     return(new_cache->data[MOD_LINE_SZ(file_pos)]);
                    552: }
                    553: 
                    554: char CORD_lf_func(size_t i, void * client_data)
                    555: {
                    556:     register lf_state * state = (lf_state *)client_data;
                    557:     register cache_line * volatile * cl_addr =
                    558:                &(state -> lf_cache[DIV_LINE_SZ(MOD_CACHE_SZ(i))]);
                    559:     register cache_line * cl = (cache_line *)ATOMIC_READ(cl_addr);
                    560:     
                    561:     if (cl == 0 || cl -> tag != DIV_LINE_SZ(i)) {
                    562:        /* Cache miss */
                    563:        refill_data rd;
                    564:        
                    565:         rd.state = state;
                    566:         rd.file_pos =  i;
                    567:         rd.new_cache = GC_NEW_ATOMIC(cache_line);
                    568:         if (rd.new_cache == 0) OUT_OF_MEMORY;
                    569:         return((char)(GC_word)
                    570:                  GC_call_with_alloc_lock((GC_fn_type) refill_cache, &rd));
                    571:     }
                    572:     return(cl -> data[MOD_LINE_SZ(i)]);
                    573: }    
                    574: 
                    575: /*ARGSUSED*/
                    576: void CORD_lf_close_proc(void * obj, void * client_data)  
                    577: {
                    578:     if (fclose(((lf_state *)obj) -> lf_file) != 0) {
                    579:        ABORT("CORD_lf_close_proc: fclose failed");
                    580:     }
                    581: }                      
                    582: 
                    583: #ifndef PA_DEBUG_DISABLE_GC
                    584: CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
                    585: {
                    586:     register lf_state * state = GC_NEW(lf_state);
                    587:     register int i;
                    588:     
                    589:     if (state == 0) OUT_OF_MEMORY;
                    590:     if (len != 0) {
                    591:        /* Dummy read to force buffer allocation.       */
                    592:        /* This greatly increases the probability       */
                    593:        /* of avoiding deadlock if buffer allocation    */
                    594:        /* is redirected to GC_malloc and the           */
                    595:        /* world is multithreaded.                      */
                    596:        char buf[1];
                    597: 
                    598:        (void) fread(buf, 1, 1, f); 
                    599:        rewind(f);
                    600:     }
                    601:     state -> lf_file = f;
                    602:     for (i = 0; i < CACHE_SZ/LINE_SZ; i++) {
                    603:         state -> lf_cache[i] = 0;
                    604:     }
                    605:     state -> lf_current = 0;
                    606:     GC_REGISTER_FINALIZER(state, CORD_lf_close_proc, 0, 0, 0);
                    607:     return(CORD_from_fn(CORD_lf_func, state, len));
                    608: }
                    609: 
                    610: CORD CORD_from_file_lazy(FILE * f)
                    611: {
                    612:     register long len;
                    613:     
                    614:     if (fseek(f, 0l, SEEK_END) != 0) {
                    615:         ABORT("Bad fd argument - fseek failed");
                    616:     }
                    617:     if ((len = ftell(f)) < 0) {
                    618:         ABORT("Bad fd argument - ftell failed");
                    619:     }
                    620:     rewind(f);
                    621:     return(CORD_from_file_lazy_inner(f, (size_t)len));
                    622: }
                    623: 
                    624: # define LAZY_THRESHOLD (128*1024 + 1)
                    625: 
                    626: CORD CORD_from_file(FILE * f)
                    627: {
                    628:     register long len;
                    629:     
                    630:     if (fseek(f, 0l, SEEK_END) != 0) {
                    631:         ABORT("Bad fd argument - fseek failed");
                    632:     }
                    633:     if ((len = ftell(f)) < 0) {
                    634:         ABORT("Bad fd argument - ftell failed");
                    635:     }
                    636:     rewind(f);
                    637:     if (len < LAZY_THRESHOLD) {
                    638:         return(CORD_from_file_eager(f));
                    639:     } else {
                    640:         return(CORD_from_file_lazy_inner(f, (size_t)len));
                    641:     }
                    642: }
                    643: #endif

E-mail: