1 /*
2 * Copyright (c) 2002, 2004 Tama Communications Corporation
3 *
4 * This file is part of GNU GLOBAL.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #ifdef STDC_HEADERS
24 #include <stdlib.h>
25 #endif
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #else
29 #include <strings.h>
30 #endif
31 #include <sys/stat.h>
32
33 #include "die.h"
34 #include "linetable.h"
35 #include "varray.h"
36 #include "strbuf.h"
37
38 /* File buffer */
39 #define EXPAND 1024
40 static STRBUF *ib;
41 static char *filebuf;
42 static int filesize;
43
44 /* File pointer */
45 static char *curp;
46 static char *endp;
47
48 /** Offset table */
49 static VARRAY *vb;
50
51 static void linetable_put(int, int);
52 /**
53 * linetable_open: load whole of file into memory.
54 *
55 * @param[in] path path
56 * @return 0: normal,
57 * -1: cannot open file.
58 */
59 int
linetable_open(const char * path)60 linetable_open(const char *path)
61 {
62 FILE *ip;
63 struct stat sb;
64 int lineno, offset;
65
66 if (stat(path, &sb) < 0)
67 return -1;
68 ib = strbuf_open(sb.st_size);
69 vb = varray_open(sizeof(int), EXPAND);
70 if ((ip = fopen(path, "r")) == NULL)
71 return -1;
72 lineno = 1;
73 offset = 0;
74 for (offset = 0;
75 (strbuf_fgets(ib, ip, STRBUF_APPEND), offset != strbuf_getlen(ib));
76 offset = strbuf_getlen(ib))
77 {
78 linetable_put(offset, lineno++);
79 }
80 fclose(ip);
81 curp = filebuf = strbuf_value(ib);
82 filesize = offset;
83 endp = filebuf + filesize;
84 /* strbuf_close(ib); */
85
86 return 0;
87 }
88 /**
89 * linetable_read: read(2) compatible routine for linetable.
90 *
91 * @param[in,out] buf read buffer
92 * @param[in] size buffer size
93 * @return ==-1: end of file,
94 * !=-1: number of bytes actually read
95 */
96 int
linetable_read(char * buf,int size)97 linetable_read(char *buf, int size)
98 {
99 int left = endp - curp;
100
101 if (left <= 0)
102 return -1; /* EOF */
103 if (size > left)
104 size = left;
105 memcpy(buf, curp, size);
106 curp += size;
107
108 return size;
109 }
110 /**
111 * linetable_put: put a line into table.
112 *
113 * @param[in] offset offset of the line
114 * @param[in] lineno line number of the line (>= 1)
115 */
116 void
linetable_put(int offset,int lineno)117 linetable_put(int offset, int lineno)
118 {
119 int *entry;
120
121 if (lineno <= 0)
122 die("linetable_put: line number must >= 1 (lineno = %d)", lineno);
123 entry = varray_assign(vb, lineno - 1, 1);
124 *entry = offset;
125 }
126 /**
127 * linetable_get: get a line from table.
128 *
129 * @param[in] lineno line number of the line (>= 1)
130 * @param[out] offset offset of the line,
131 * if offset == NULL, nothing returned.
132 * @return line pointer
133 */
134 char *
linetable_get(int lineno,int * offset)135 linetable_get(int lineno, int *offset)
136 {
137 int addr;
138
139 if (lineno <= 0)
140 die("linetable_get: line number must >= 1 (lineno = %d)", lineno);
141 addr = *((int *)varray_assign(vb, lineno - 1, 0));
142 if (offset)
143 *offset = addr;
144 return filebuf + addr;
145 }
146 /**
147 * linetable_close: close line table.
148 */
149 void
linetable_close(void)150 linetable_close(void)
151 {
152 varray_close(vb);
153 strbuf_close(ib);
154 }
155 /**
156 * linetable_print: print a line.
157 *
158 * @param[in] op output file pointer
159 * @param[in] lineno line number (>= 1)
160 */
161 void
linetable_print(FILE * op,int lineno)162 linetable_print(FILE *op, int lineno)
163 {
164 const char *s, *p;
165
166 if (lineno <= 0)
167 die("linetable_print: line number must >= 1 (lineno = %d)", lineno);
168 s = linetable_get(lineno, NULL);
169 if (vb->length == lineno) {
170 /*
171 * The last line may not include newline.
172 */
173 fwrite(s, 1, endp - s, op);
174 if (endp[-1] != '\n')
175 fputc('\n', op);
176 } else {
177 p = linetable_get(lineno + 1, NULL);
178 fwrite(s, 1, p - s, op);
179 }
180 }
181