root/libutil/linetable.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. linetable_open
  2. linetable_read
  3. linetable_put
  4. linetable_get
  5. linetable_close
  6. linetable_print

/*
 * Copyright (c) 2002, 2004 Tama Communications Corporation
 *
 * This file is part of GNU GLOBAL.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef STDC_HEADERS
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#include <sys/stat.h>

#include "die.h"
#include "linetable.h"
#include "varray.h"
#include "strbuf.h"

/* File buffer */
#define EXPAND 1024
static STRBUF *ib;
static char *filebuf;
static int filesize;

/* File pointer */
static char *curp;
static char *endp;

/* Offset table */
static VARRAY *vb;

static void linetable_put(int, int);
/*
 * linetable_open: load whole of file into memory.
 *
 *      i)      path    path
 *      r)              0: normal
 *                      -1: cannot open file.
 */
int
linetable_open(const char *path)
{
        FILE *ip;
        struct stat sb;
        int lineno, offset;

        if (stat(path, &sb) < 0)
                return -1;
        ib = strbuf_open(sb.st_size);
        vb = varray_open(sizeof(int), EXPAND);
        if ((ip = fopen(path, "r")) == NULL)
                return -1;
        lineno = 1;
        offset = 0;
        for (offset = 0;
                (strbuf_fgets(ib, ip, STRBUF_APPEND), offset != strbuf_getlen(ib));
                offset = strbuf_getlen(ib))
        {
                linetable_put(offset, lineno++);
        }
        fclose(ip);
        curp = filebuf = strbuf_value(ib);
        filesize = offset;
        endp = filebuf + filesize;
        /* strbuf_close(ib); */

        return 0;
}
/*
 * linetable_read: read(2) compatible routine for linetable.
 *
 *      io)     buf     read buffer
 *      i)      size    buffer size
 *      r)              ==-1: end of file
 *                      !=-1: number of bytes actually read
 */
int
linetable_read(char *buf, int size)
{
        int leaved = endp - curp;

        if (leaved <= 0)
                return -1;      /* EOF */
        if (size > leaved)
                size = leaved;
        memcpy(buf, curp, size);
        curp += size;

        return size;
}
/*
 * linetable_put: put a line into table.
 *
 *      i)      offset  offset of the line
 *      i)      lineno  line number of the line (>= 1)
 */
void
linetable_put(int offset, int lineno)
{
        int *entry;

        if (lineno <= 0)
                die("linetable_put: line number must >= 1 (lineno = %d)", lineno);
        entry = varray_assign(vb, lineno - 1, 1);
        *entry = offset;
}
/*
 * linetable_get: get a line from table.
 *
 *      i)      lineno  line number of the line (>= 1)
 *      o)      offset  offset of the line
 *                      if offset == NULL, nothing returned.
 *      r)              line pointer
 */
char *
linetable_get(int lineno, int *offset)
{
        int addr;

        if (lineno <= 0)
                die("linetable_get: line number must >= 1 (lineno = %d)", lineno);
        addr = *((int *)varray_assign(vb, lineno - 1, 0));
        if (offset)
                *offset = addr;
        return filebuf + addr;
}
/*
 * linetable_close: close line table.
 */
void
linetable_close(void)
{
        varray_close(vb);
        strbuf_close(ib);
}
/*
 * linetable_print: print a line.
 *
 *      i)      op      output file pointer
 *      i)      lineno  line number (>= 1)
 */
void
linetable_print(FILE *op, int lineno)
{
        const char *s, *p;

        if (lineno <= 0)
                die("linetable_print: line number must >= 1 (lineno = %d)", lineno);
        s = linetable_get(lineno, NULL);
        if (vb->length == lineno) {
                /*
                 * The last line may not include newline.
                 */
                fwrite(s, 1, endp - s, op);
                if (endp[-1] != '\n')
                        fputc('\n', op);
        } else {
                p = linetable_get(lineno + 1, NULL);
                fwrite(s, 1, p - s, op);
        }
}

/* [<][>][^][v][top][bottom][index][help] */