Reads good & works for me, ok nicm

On Wed, Jul 06, 2011 at 01:02:31PM -0400, Todd C. Miller wrote:
> Since cgetnext() iterates over the file it can just pass the entire
> record in to getent() so getent() doesn't need to re-parse the file
> again to find it.  This speeds up cap_mkdb when building termcap.db.
> 
> Other potential speedups include useing stdio in getent() and to
> using pfp instead of opening an fd each time.  I'll send those out
> once this goes in.
> 
>  - todd
> 
> Index: lib/libc/gen/getcap.c
> ===================================================================
> RCS file: /home/cvs/openbsd/src/lib/libc/gen/getcap.c,v
> retrieving revision 1.27
> diff -u -r1.27 getcap.c
> --- lib/libc/gen/getcap.c     15 May 2006 04:18:19 -0000      1.27
> +++ lib/libc/gen/getcap.c     6 Jul 2011 15:22:09 -0000
> @@ -657,123 +657,141 @@
>   * upon returning an entry with more remaining, and -1 if an error occurs.
>   */
>  int
> -cgetnext(char **bp, char **db_array)
> +cgetnext(char **cap, char **db_array)
>  {
>       size_t len;
> -     int status, done;
> -     char *line, *np, buf[BSIZE], nbuf[BSIZE];
> +     int serrno, status = -1;
> +     char nbuf[BSIZE];
> +     char *record = NULL, *r_end, *rp;
> +     char buf[BUFSIZ];
> +     char *b_end, *bp;
> +     int c;
>       u_int dummy;
>  
>       if (dbp == NULL)
>               dbp = db_array;
>  
> -     if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) {
> -             (void)cgetclose();
> -             return (-1);
> +     if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL)
> +             goto done;
> +
> +     /*
> +      * Check if we have an unused top record from cgetset().
> +      */
> +     if (toprec && !gottoprec) {
> +             gottoprec = 1;
> +             goto lookup;
>       }
> +
> +     /*
> +      * Allocate first chunk of memory.
> +      */
> +     if ((record = malloc(BFRAG)) == NULL)
> +             goto done;
> +     r_end = record + BFRAG;
> +
> +     /*
> +      * Find the next capability record
> +      */
> +     /*
> +      * Loop invariants:
> +      *      There is always room for one more character in record.
> +      *      R_end always points just past end of record.
> +      *      Rp always points just past last character in record.
> +      *      B_end always points just past last character in buf.
> +      *      Bp always points at next character in buf.
> +      */
> +     b_end = buf;
> +     bp = buf;
>       for (;;) {
> -             if (toprec && !gottoprec) {
> -                     gottoprec = 1;
> -                     line = toprec;
> -             } else {
> -                     line = fgetln(pfp, &len);
> -                     if (line == NULL) {
> -                             if (ferror(pfp)) {
> -                                     (void)cgetclose();
> -                                     return (-1);
> -                             } else {
> +             /*
> +              * Read in a line implementing (\, newline)
> +              * line continuation.
> +              */
> +             rp = record;
> +             for (;;) {
> +                     if (bp >= b_end) {
> +                             size_t n;
> +
> +                             n = fread(buf, 1, sizeof(buf), pfp);
> +                             if (n == 0) {
> +                                     if (ferror(pfp))
> +                                             goto done;
>                                       (void)fclose(pfp);
>                                       pfp = NULL;
>                                       if (*++dbp == NULL) {
> -                                             (void)cgetclose();
> -                                             return (0);
> +                                             status = 0;
> +                                             goto done;
>                                       } else if ((pfp =
>                                           fopen(*dbp, "r")) == NULL) {
> -                                             (void)cgetclose();
> -                                             return (-1);
> +                                             goto done;
>                                       } else
>                                               continue;
>                               }
> -                     } else
> -                             line[len - 1] = '\0';/* XXX - assumes newline */
> -                     if (len == 1) {
> -                             slash = 0;
> -                             continue;
> -                     }
> -                     if (isspace(*line) ||
> -                         *line == ':' || *line == '#' || slash) {
> -                             if (line[len - 2] == '\\')
> -                                     slash = 1;
> -                             else
> -                                     slash = 0;
> -                             continue;
> +                             b_end = buf + n;
> +                             bp = buf;
>                       }
> -                     if (line[len - 2] == '\\')
> -                             slash = 1;
> -                     else
> -                             slash = 0;
> -             }
> -
>  
> -             /*
> -              * Line points to a name line.
> -              */
> -             done = 0;
> -             np = nbuf;
> -             for (;;) {
> -                     len = strcspn(line, ":\\");
> -                     if (line[len] == ':') {
> -                             done = 1;
> -                             ++len;
> -                     }
> -                     /* copy substring */
> -                     if (len >= sizeof(nbuf) - (np - nbuf)) {
> -                             (void)cgetclose();
> -                             return (-1);
> +                     c = *bp++;
> +                     if (c == '\n') {
> +                             if (rp > record && *(rp-1) == '\\') {
> +                                     rp--;
> +                                     continue;
> +                             } else
> +                                     break;
>                       }
> -                     memcpy(np, line, len);
> -                     np += len;
> +                     *rp++ = c;
>  
> -                     if (done) {
> -                             *np = '\0';
> -                             break;
> -                     } else { /* name field extends beyond the line */
> -                             line = fgetln(pfp, &len);
> -                             if (line == NULL) {
> -                                     if (ferror(pfp)) {
> -                                             (void)cgetclose();
> -                                             return (-1);
> -                                     }
> -                                     /* Move on to next file. */
> -                                     (void)fclose(pfp);
> -                                     pfp = NULL;
> -                                     ++dbp;
> -                                     /* NUL terminate nbuf. */
> -                                     *np = '\0';
> -                                     break;
> -                             } else
> -                                     /* XXX - assumes newline */
> -                                     line[len - 1] = '\0';
> +                     /*
> +                      * Enforce loop invariant: if no room
> +                      * left in record buffer, try to get
> +                      * some more.
> +                      */
> +                     if (rp >= r_end) {
> +                             size_t newsize, pos;
> +                             char *nrecord;
> +
> +                             pos = rp - record;
> +                             newsize = r_end - record + BFRAG;
> +                             nrecord = realloc(record, newsize);
> +                             if (nrecord == NULL)
> +                                     goto done;
> +                             record = nrecord;
> +                             r_end = record + newsize;
> +                             rp = record + pos;
>                       }
>               }
> -             len = strcspn(nbuf, "|:");
> -             memcpy(buf, nbuf, len);
> -             buf[len] = '\0';
> +             /* loop invariant lets us do this */
> +             *rp++ = '\0';
> +
>               /*
> -              * XXX
> -              * Last argument of getent here should be nbuf if we want true
> -              * sequential access in the case of duplicates.
> -              * With NULL, getent will return the first entry found
> -              * rather than the duplicate entry record.  This is a
> -              * matter of semantics that should be resolved.
> +              * If not blank or comment, set toprec and topreclen so
> +              * getent() doesn't have to re-parse the file to find it.
>                */
> -             status = getent(bp, &dummy, db_array, -1, buf, 0, NULL);
> -             if (status == -2 || status == -3)
> -                     (void)cgetclose();
> -
> -             return (status + 1);
> +             if (*record != '\0' && *record != '#') {
> +                     /* Rewind to end of record */
> +                     fseeko(pfp, (off_t)(bp - b_end), SEEK_CUR);
> +                     toprec = record;
> +                     topreclen = rp - record;
> +                     gottoprec = 1;
> +                     break;
> +             }
>       }
> -     /* NOTREACHED */
> +lookup:
> +     /* extract name from record */
> +     len = strcspn(record, "|:");
> +     memcpy(nbuf, record, len);
> +     nbuf[len] = '\0';
> +
> +     /* return value of getent() is one less than cgetnext() */
> +     status = getent(cap, &dummy, db_array, -1, nbuf, 0, NULL) + 1;
> +done:
> +     serrno = errno;
> +     free(record);
> +     if (status <= 0)
> +             (void)cgetclose();
> +     errno = serrno;
> +
> +     return (status);
>  }
>  
>  /*

Reply via email to