戻る 目次へ
§5.1.21 vfile.cc
戻る 目次へ

  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: 




Copyright 2004 Tradcrafts. ALL RIGHTS RESERVED.