comparison anagram/agcore/textfile.cpp @ 0:13d2b8934445

Import AnaGram (near-)release tree into Mercurial.
author David A. Holland
date Sat, 22 Dec 2007 17:52:45 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:13d2b8934445
1 /*
2 * AnaGram, A System for Syntax Directed Programming
3 * Copyright 1993-2002 Parsifal Software. All Rights Reserved.
4 * See the file COPYING for license and usage terms.
5 *
6 * textfile.cpp
7 */
8
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <errno.h>
13
14 #include "port.h"
15
16 #include "agstack.h"
17 #include "config.h"
18 #include "file.h"
19 #include "minmax.h"
20 //#include "stacks.h"
21 #include "textfile.h"
22
23 //#define INCLUDE_LOGGING
24 #include "log.h"
25
26
27 #define BUF_SIZE 0x4000000
28
29 text_file::text_file(const text_file &t)
30 : name(t.name), text(t.text), lx(t.lx), width(t.width)
31 , stringLength(t.stringLength)
32 , truncated(0)
33 , readFlags(t.readFlags)
34 {
35 LOGSECTION("text_file::text_file");
36 LOGV(name) LCV(width);
37 LOGV((int) text.pointer());
38 }
39
40 text_file &text_file::operator =(const text_file &t) {
41 name = t.name; /* name of file */
42 text = t.text; /* body of file */
43 lx = t.lx; /* array of line indices */
44 width = t.width; /* length of longest line? */
45 truncated = t.truncated;
46 stringLength = t.stringLength;
47 readFlags = t.readFlags;
48 return *this;
49 }
50
51
52 text_file::text_file(const char *n)
53 : name(n), text(), lx(), width(0), stringLength(0)
54 , truncated(0)
55 , readFlags(O_TEXT|O_RDONLY)
56 {
57 LOGSECTION("text_file::text_file");
58 LOGV(name);
59 LOGV((int) text.pointer());
60 read_file(readFlags);
61 }
62
63 text_file::text_file(const AgString n)
64 : name(n), text(), lx(), width(0), stringLength(0)
65 , truncated(0)
66 , readFlags(O_TEXT|O_RDONLY)
67 {
68 LOGSECTION("text_file::text_file");
69 LOGV(name.pointer());
70 LOGV((int) text.pointer());
71 LOGV((int) readFlags);
72 read_file(readFlags);
73 }
74
75 text_file::text_file(const char *n, int flags)
76 : name(n), text(), lx(), width(0), stringLength(0)
77 , truncated(0)
78 , readFlags(flags)
79 {
80 LOGSECTION("text_file::text_file");
81 LOGV(name);
82 LOGV((int) text.pointer());
83 read_file(flags);
84 }
85
86 text_file::text_file(const AgString n, int flags)
87 : name(n), text(), lx(), width(0), stringLength(0)
88 , truncated(0)
89 , readFlags(flags)
90 {
91 LOGSECTION("text_file::text_file");
92 LOGV(name.pointer());
93 LOGV((int) text.pointer());
94 LOGV((int) flags);
95 read_file(flags);
96 }
97
98 void text_file::find_lines(void) {
99 char *p, *b, *bl, *q;
100 int w, wmax;
101 LOGSECTION("text_file::find_lines");
102 AgStack<int> lineStack;
103
104 wmax = w = 0;
105 p = b = text.pointer();
106 LOGV(p);
107 if (p != NULL) {
108 do {
109 p = strchr(bl = p,'\n');
110 lineStack.push((int)(bl-b));
111 if (p != NULL) {
112 *p = 0;
113 }
114 else {
115 q = strchr(bl, 0);
116 if (q == bl) {
117 break;
118 }
119 }
120 q = bl;
121 w = 0;
122 LOGV(lineStack.size()) LCV(bl);
123 while (*q) {
124 w += (*q++ == '\t') ? tab_spacing - w%tab_spacing : 1;
125 }
126 if (w > wmax) {
127 wmax = w;
128 }
129 if (p == NULL) {
130 break;
131 }
132 *p++ = '\n';
133 } while(*p);
134 }
135
136 LOGS("Line scan complete");
137 LOGV((int) &lineStack[0]) LCV((int) &lineStack[lineStack.size() - 1]);
138
139 lx = AgArray<int>(lineStack);
140 LOGS("Line array completed");
141
142 width = wmax;
143 }
144
145 void text_file::read_file() {
146 read_file(readFlags);
147 }
148
149 void text_file::read_file(int flags) {
150 int fh;
151 long n;
152
153 LOGSECTION("text_file::read_file");
154 LOGV(name);
155 LOGV(flags);
156 fh = open_shared_any(name.pointer(),flags);
157 LOGV(fh);
158 if (fh < 0) {
159 LOGV(errno);
160 LOGV(strerror(errno));
161 return;
162 }
163 LOGV(name);
164 char *buf, *bufptr;
165 long length;
166 long buffer_length;
167 struct stat statbuf;
168
169 fstat(fh, &statbuf);
170 //file_time_stamp = statbuf.st_atime;
171 length = statbuf.st_size;
172 stringLength = 0;
173 LOGV(length);
174 buffer_length = min((long)(length+1), (long)(MAX_BYTES - 1 - sizeof(short)));
175 LOGV((int) text.pointer());
176 text = AgString(buffer_length);
177 LOGV((int) text.pointer());
178 buf = bufptr = text.pointer();
179 LOGV((int) text.pointer());
180 n = 0;
181 while (1) {
182 unsigned k;
183 unsigned read_request = (unsigned) min(buffer_length, (long) BUF_SIZE);
184 LOGV(read_request);
185 if ((long)read_request > length) {
186 read_request = (unsigned) length;
187 }
188 length -= read_request;
189 LOGV(read_request) LCV(length);
190 k = read(fh, bufptr, read_request);
191 bufptr[k] = 0;
192 LOGV(k) LCV(stringLength);
193 // XXX howabout checking for -1 before dereferencing with it?
194 if (k == 0 || k == (unsigned) -1) {
195 break;
196 }
197 stringLength += k;
198 LOGV(k) LCV(stringLength);
199 bufptr += k;
200 LOGV((int) (bufptr- 10)) LCV(bufptr - 10);
201 buffer_length -= k;
202 n += k;
203 }
204 truncated = length != 0;
205 LOGV(stringLength) LCV(n) LCV(length);
206 LOGV(buf[n-5]) LCV(buf[n-4]) LCV(buf[n-3]) LCV(buf[n-2]) LCV(buf[n-1]);
207 buf[(unsigned)n] = 0;
208 close(fh);
209 find_lines();
210 LOGV(lx.size()) LCV((int) lx.pointer());
211 //printf("text_file::read_file\n");
212 }
213
214 int text_file::findNext(cint &loc, AgString s) {
215 LOGSECTION("text_file::findNext");
216 LOGV(name);
217 LOGV(loc) LCV(s);
218 searchProcess.setKey(s);
219 assert((unsigned) loc.y < lx.size());
220 unsigned start = lx[loc.y] + loc.x;
221 LOGV(lx[loc.y]) LCV(start) LCV(stringLength);
222 assert(start <= stringLength);
223 if (start == stringLength) {
224 return 0;
225 }
226 char *initial = text.pointer() + start + 1;
227 char *ptr = searchProcess.scanForward(initial, stringLength - start);
228 if (ptr == 0) {
229 return 0;
230 }
231 unsigned index = ptr - text.pointer();
232 while ((unsigned) loc.y < lx.size() && (unsigned) lx[loc.y] < index) {
233 loc.y++;
234 }
235 if ((unsigned) loc.y >= lx.size() || (unsigned) lx[loc.y] > index) {
236 loc.y--;
237 }
238 loc.x = index - lx[loc.y];
239 return 1;
240 }
241
242 int text_file::findPrev(cint &loc, AgString s) {
243 LOGSECTION("text_file::findPrev");
244 LOGV(loc) LCV(s);
245 searchProcess.setKey(s);
246 assert((unsigned) loc.y < lx.size());
247 unsigned length = lx[loc.y] + loc.x - 1;
248 LOGV(length);
249 char *ptr = searchProcess.scanReverse(text.pointer(), length);
250 if (ptr == 0) {
251 return 0;
252 }
253 unsigned index = ptr - text.pointer();
254 while (loc.y && (unsigned) lx[loc.y] > index) {
255 loc.y--;
256 }
257 loc.x = index - lx[loc.y];
258 LOGV(loc) LCV(index);
259 return 1;
260 }