1: /******************************************************************************
2: ezht - Copyright (C) 2004 Tradcrafts
3: This file is part of the ezht.
4:
5: ezht is free software; you can redistribute it and/or modify
6: it under the terms of the GNU General Public License as published by the
7: Free Software Foundation; either version 2 of the License, or (at your
8: option) any later version.
9:
10: ezht is distributed in the hope that it will be useful, but
11: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13: more details.
14:
15: You should have received a copy of the GNU General Public License along with
16: this program; see the file COPYING. If not, write to the Free Software
17: Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18: ******************************************************************************/
19:
20: #include "vfile.h"
21: #include "error.h"
22:
23: #include <stdio.h>
24: #include <stdarg.h>
25: #include <errno.h>
26: #include <deque>
27:
28: VFile::VFile(const char *_fnam)
29: {
30: is_clone = false;
31: datas = new std::list<std::string>;
32: cur = datas->end();
33: fname = _fnam;
34: }
35:
36: VFile::VFile(const VFile &src)
37: {
38: is_clone = true;
39: datas = src.datas;
40: cur = src.cur;
41: fname = src.fname;
42: }
43:
44: VFile::~VFile()
45: {
46: if( ! is_clone )
47: delete datas;
48: }
49:
50: void VFile::reset_filename(const char *new_fname)
51: {
52: fname = new_fname;
53: }
54:
55: VFile* VFile::clone()
56: {
57: return
58: new VFile(*this);
59: }
60:
61: const char* VFile::get_filename()
62: {
63: return fname.c_str();
64: }
65:
66: void VFile::chomp()
67: {
68:
69: if( cur == datas->begin() )
70: return;
71:
72: std::list<std::string>::iterator p = cur;
73:
74: do{
75: p--;
76: std::string &s = *p;
77: if( s[0] == '\t' ){
78: if( s[s.length()-1] == '\n' ){
79: char *tmp = new char[s.length()];
80: memcpy(tmp,s.c_str(),s.length()-1);
81: tmp[s.length()-1] = '\0';
82: if( s.length() >= 2 && tmp[s.length()-2]=='\r' ){
83: // DOS,Winの\r\n形式の改行の場合
84: // \rも取り除かねばならない (UNIX環境からの場合)
85: tmp[s.length()-2] = '\0';
86: }
87: s = tmp;
88: delete tmp;
89: }
90: break;
91: }
92: }while( p != datas->begin() );
93:
94: }
95:
96: void VFile::puts(const char *s)
97: {
98: char *buf = new char[strlen(s)+2];
99: const char *p = s;
100:
101: while(1){
102: while( *p && *p != '\n' ){
103: p++;
104: }
105:
106: buf[0] = '\t';
107:
108: if( *p == '\0' ){
109: // 空行は無視
110: if( strlen(s) > 0 ){
111: strcpy(buf+1,s);
112: datas->insert(cur,buf);
113: }
114: break;
115: }
116:
117: // *p == '\n'
118:
119: int len = p - s + 1;
120: // 空行は無視
121: if( len > 0 && 0!=strcmp(s,"\n") && 0!=strcmp(s,"\r\n") ){
122: memcpy(buf+1,s,len);
123: buf[len+1] = '\0';
124: datas->insert(cur, buf);
125: }
126: s = p = p+1;
127:
128: }
129:
130: delete buf;
131: }
132:
133: void VFile::printf(const char *fmt, ...)
134: {
135: static char buf[8192];
136: va_list args;
137: va_start(args,fmt);
138: vsprintf(buf,fmt,args);
139: va_end(args);
140:
141: VFile::puts(buf);
142: }
143:
144: void VFile::add_index(const char *index_name)
145: {
146: datas->insert(cur,index_name);
147: datas->insert(cur,""); // これは必要
148: }
149:
150: bool VFile::seek(const std::string &index_name)
151: {
152: std::list<std::string>::iterator p;
153: for(p=datas->begin(); p!=datas->end(); p++)
154: if( *p == index_name ){
155: p++;
156: cur = p;
157: return true; // FOUND
158: }
159:
160: return false; // NOT FOUND
161: }
162:
163: static int compare(std::list<std::string> *datas,std::string fname)
164: {
165: FILE *rd = fopen(fname.c_str(),"r");
166: if( ! rd )
167: return 1; // ファイルが存在しないので当然異なる
168:
169: std::deque<char> body;
170: int c;
171: while( EOF != (c=fgetc(rd)) )
172: body.push_back((char)c);
173: fclose(rd);
174:
175:
176: std::deque<char>::iterator itr = body.begin();
177: std::list<std::string>::iterator p;
178: for(p=datas->begin(); p!=datas->end(); p++){
179: std::string &str = *p;
180: if( str[0] == '\t' ){
181: const char *s = str.c_str()+1;
182: while( *s ){
183: if( itr == body.end() ||
184: *s++ != *itr++ ){
185: return 1; // 異なる
186: }
187: }
188: }
189: }
190:
191: return 0; //一致した
192: }
193:
194: void VFile::flush()
195: {
196: if( 0==compare(datas,fname) ){
197: fprintf(stderr,"[skipped] ");
198: return;
199: }
200:
201: FILE *fh = fopen(fname.c_str(),"w");
202: if( ! fh ){
203: error("can't create file `%s': %s",fname.c_str(), strerror(errno));
204: return;
205: }
206:
207: std::list<std::string>::iterator p;
208: for(p=datas->begin(); p!=datas->end(); p++){
209: std::string &str = *p;
210: if( str[0] == '\t' ){
211: if( EOF == fputs(str.c_str()+1,fh) ){
212: fclose(fh);
213: error("error occurred while writing in `%s': %s",fname.c_str(), strerror(errno));
214: return;
215: }
216: }
217: }
218:
219: fclose(fh);
220:
221: fprintf(stderr,"[wrote] ");
222: }
223:
224: static void _put_body(const char *s,FILE *fh)
225: {
226: fputc('-',fh);
227: while( *s && *s!='\n' )
228: fputc(*s++,fh);
229:
230: if( *s=='\n' ){
231: fputc('\n',fh);
232: if( *(s+1)=='\0' )
233: return;
234: }
235:
236: if( *s == '\0' )
237: fputc('\n',fh);
238: else
239: _put_body(s+1,fh);
240: }
241:
242:
243: void VFile::flush2(FILE *out)
244: {
245: fprintf(out,"+%s\n",fname.c_str());
246:
247: std::list<std::string>::iterator p;
248: for(p=datas->begin(); p!=datas->end(); p++){
249: std::string &str = *p;
250: if( str[0] == '\t' ){
251: _put_body(str.c_str()+1,out);
252: }
253: }
254: }
255:
256: void VFile::rewind()
257: {
258: cur = datas->begin();
259: }
260:
261: void VFile::each( bool (*callback)(VFile*,const char*,std::string&,std::string*) )
262: {
263: while( cur != datas->end() ){
264: std::string &line = *cur;
265: if( line[0] == '\t' ){
266: std::string modified_line;
267: if( (*callback)(this,line.c_str()+1,modified_line,&line) ){
268: line = '\t' + modified_line;
269: }
270: }
271: cur++;
272: }
273:
274: }
275:
276: /////
277:
278: static std::list<VFile*> vf_list;
279:
280: VFile* vf_open(const char *fname)
281: {
282: VFile *vf = new VFile(fname);
283: vf_list.push_back(vf);
284: return vf;
285: }
286:
287: VFile* vf_search(const char *fname)
288: {
289: std::list<VFile*>::iterator p;
290: for(p=vf_list.begin(); p!=vf_list.end(); p++)
291: if( 0 == strcmp(fname,(*p)->get_filename()) )
292: return *p; // FOUND
293:
294: return NULL; // NOT FOUND
295: }
296:
297:
298: void vf_flushall()
299: {
300: fprintf(stderr,"generating... "); fflush(stderr);
301:
302: std::list<VFile*>::iterator p;
303: for(p=vf_list.begin(); p!=vf_list.end(); p++){
304: fprintf(stderr,"%s",(*p)->get_filename()); fflush(stderr);
305: (*p)->flush();
306: }
307:
308: fprintf(stderr,"\ndone.\n");
309: }
310:
311: void vf_flushall_to(FILE *out)
312: {
313: std::list<VFile*>::iterator p;
314: for(p=vf_list.begin(); p!=vf_list.end(); p++)
315: (*p)->flush2(out);
316: }
317:
318: ///
319: void vf_each(bool (*callback)(VFile*,const char *,std::string &,std::string*))
320: {
321: std::list<VFile*>::iterator p;
322: for(p=vf_list.begin(); p!=vf_list.end(); p++){
323: (*p)->rewind();
324: (*p)->each(callback);
325: }
326: }
327:
328: