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