Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

textfile.cc

Go to the documentation of this file.
00001 /*
00002  *      HT Editor
00003  *      textfile.cc
00004  *
00005  *      Copyright (C) 1999-2002 Stefan Weyergraf (stefan@weyergraf.de)
00006  *
00007  *      This program is free software; you can redistribute it and/or modify
00008  *      it under the terms of the GNU General Public License version 2 as
00009  *      published by the Free Software Foundation.
00010  *
00011  *      This program is distributed in the hope that it will be useful,
00012  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *      GNU General Public License for more details.
00015  *
00016  *      You should have received a copy of the GNU General Public License
00017  *      along with this program; if not, write to the Free Software
00018  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  */
00020 
00021 #include <errno.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 
00025 #include "htdebug.h"
00026 #include "textfile.h"
00027 #include "tools.h"
00028 
00029 #define TEXTFILE_READSIZE                               256
00030 #define TEXTFILE_MAX_LINELEN                            512
00031 
00032 #define TEXTFILE_MAX_LINEENDLEN                 2
00033 
00034 //#define TEXTFILE_MAX_UPDATE_PARSE_STEPS               64
00035 
00036 /*
00037  *      CLASS ht_textfile
00038  */
00039 
00040 /*
00041  *      CLASS ht_layer_textfile
00042  */
00043  
00044 void ht_layer_textfile::init(ht_textfile *textfile, bool own_textfile)
00045 {
00046         ht_textfile::init(textfile, own_textfile);
00047 }
00048 
00049 bool ht_layer_textfile::convert_ofs2line(FILEOFS o, UINT *line, UINT *pofs)
00050 {
00051         return ((ht_textfile*)streamfile)->convert_ofs2line(o, line, pofs);
00052 }
00053 
00054 bool ht_layer_textfile::convert_line2ofs(UINT line, UINT pofs, FILEOFS *o)
00055 {
00056         return ((ht_textfile*)streamfile)->convert_line2ofs(line, pofs, o);
00057 }
00058 
00059 void ht_layer_textfile::delete_lines(UINT line, UINT count)
00060 {
00061         ((ht_textfile*)streamfile)->delete_lines(line, count);
00062 }
00063 
00064 void ht_layer_textfile::delete_chars(UINT line, UINT ofs, UINT count)
00065 {
00066         ((ht_textfile*)streamfile)->delete_chars(line, ofs, count);
00067 }
00068 
00069 bool ht_layer_textfile::get_char(UINT line, char *ch, UINT pos)
00070 {
00071         return ((ht_textfile*)streamfile)->get_char(line, ch, pos);
00072 }
00073 
00074 bool ht_layer_textfile::getline(UINT line, UINT pofs, void *buf, UINT buflen, UINT *retlen, lexer_state *state)
00075 {
00076         return ((ht_textfile*)streamfile)->getline(line, pofs, buf, buflen, retlen, state);
00077 }
00078 
00079 UINT ht_layer_textfile::getlinelength(UINT line)
00080 {
00081         return ((ht_textfile*)streamfile)->getlinelength(line);
00082 }
00083 
00084 void ht_layer_textfile::insert_lines(UINT before, UINT count, void **line_ends, int *line_end_lens)
00085 {
00086         ((ht_textfile*)streamfile)->insert_lines(before, count, line_ends, line_end_lens);
00087 }
00088 
00089 void ht_layer_textfile::insert_chars(UINT line, UINT ofs, void *chars, UINT len)
00090 {
00091         ((ht_textfile*)streamfile)->insert_chars(line, ofs, chars, len);
00092 }
00093 
00094 bool ht_layer_textfile::has_line(UINT line)
00095 {
00096         return ((ht_textfile*)streamfile)->has_line(line);
00097 }
00098 
00099 UINT ht_layer_textfile::linecount()
00100 {
00101         return ((ht_textfile*)streamfile)->linecount();
00102 }
00103 
00104 void ht_layer_textfile::set_layered_assume(ht_streamfile *s, bool changes_applied)
00105 {
00106 /*      ht_streamfile *q = streamfile->get_layered();
00107         if (q)*/ ((ht_textfile*)streamfile)->set_layered_assume(s, changes_applied);
00108 /*     else
00109                 streamfile = s;*/
00110 }
00111 
00112 void ht_layer_textfile::set_lexer(ht_syntax_lexer *lexer)
00113 {
00114         ((ht_textfile*)streamfile)->set_lexer(lexer);
00115 }
00116 
00117 /*
00118  *      CLASS ht_ltextfile_line
00119  */
00120 
00121 ht_ltextfile_line::~ht_ltextfile_line()
00122 {
00123         if (is_in_memory) free(in_memory.data);
00124 }
00125 
00126 /*
00127  *      CLASS ht_ltextfile
00128  */
00129  
00130 void    ht_ltextfile::init(ht_streamfile *streamfile, bool own_streamfile, ht_syntax_lexer *l)
00131 {
00132         ht_textfile::init(streamfile, own_streamfile);
00133         int e = get_error();
00134         if (get_error()) return;
00135         lexer = l;
00136         lines = new ht_clist();
00137         lines->init();
00138         orig_lines = new ht_clist();
00139         orig_lines->init();
00140         reread();
00141         first_parse_dirty_line = linecount();
00142         first_nofs_dirty_line = linecount();
00143         dirty = false;
00144         ofs = 0;
00145 }
00146 
00147 void ht_ltextfile::done()
00148 {
00149         lines->destroy();
00150         delete lines;
00151         orig_lines->destroy();
00152         delete orig_lines;
00153         ht_textfile::done();
00154 }
00155 
00156 void ht_ltextfile::cache_invd()
00157 {
00158         lines->empty();
00159         UINT c=orig_lines->count();
00160         for (UINT i=0; i<c; i++) {
00161                 ht_ltextfile_line *l = new ht_ltextfile_line();
00162                 *l = *((ht_ltextfile_line*)orig_lines->get(i));
00163                 lines->append(l);
00164         }
00165         dirty_parse(0);
00166 /*      reread();*/
00167         dirty = false;
00168 }
00169 
00170 void ht_ltextfile::cache_flush()
00171 {
00172 }
00173 
00174 bool ht_ltextfile::convert_line2ofs(UINT line, UINT pofs, FILEOFS *o)
00175 {
00176         ht_ltextfile_line *x;
00177         x=fetch_line_nofs_ok(line);
00178         if (x) {
00179                 UINT m=getlinelength_i(x);
00180                 if (pofs<m) {
00181                         *o=x->nofs+pofs;
00182                 } else {
00183                         *o=x->nofs+m;
00184                 }
00185                 return true;
00186         }
00187         return false;
00188 }
00189 
00190 bool ht_ltextfile::convert_ofs2line(FILEOFS o, UINT *line, UINT *pofs)
00191 {
00192         UINT l=0, r=linecount();
00193         if (!r) return 0; else r--;
00194         UINT m=0;
00195         ht_ltextfile_line *x, *y;
00196         while (l<=r) {
00197                 m=(l+r) / 2;
00198                 x=fetch_line_nofs_ok(m);
00199                 y=fetch_line_nofs_ok(m+1);
00200                 if ((x->nofs < o) && ((y && (y->nofs <= o)) || !y)) l=m+1; else
00201                 if (x->nofs > o) r=m-1; else break;
00202         }
00203         
00204 /* FIXME: debug */
00205         x=fetch_line_nofs_ok(m);
00206         if (x) assert(o>=x->nofs);
00207         x=fetch_line_nofs_ok(m+1);
00208         if (x) assert(o<x->nofs);
00209 
00210 
00211         x=fetch_line_nofs_ok(m);
00212         
00213         *line=m;
00214         *pofs=o - x->nofs;
00215         return true;
00216 }
00217 
00218 void    ht_ltextfile::copy_to(ht_stream *stream)
00219 {
00220 /*      UINT c=linecount();
00221         char buf[TEXTFILE_MAX_LINELEN+1];
00222         for (UINT i=0; i<c; i++) {
00223                 ht_ltextfile_line *e=fetch_line(i);
00224                 if (e) {
00225                         UINT s;
00226                         getline(i, 0, buf, TEXTFILE_MAX_LINELEN+1, &s, NULL);
00227                         stream->write(buf, s);
00228                         stream->write(e->lineend, e->lineendlen);
00229                 }
00230         }*/
00231 #define STREAM_COPYBUF_SIZE (64*1024)
00232         const UINT bufsize=STREAM_COPYBUF_SIZE;
00233         byte *buf=(byte*)malloc(bufsize);
00234         UINT r;
00235         do {
00236                 r=read(buf, bufsize);
00237                 stream->write(buf, r);
00238         } while (r);
00239         free(buf);
00240 }
00241 
00242 void ht_ltextfile::delete_chars(UINT line, UINT ofs, UINT count)
00243 {
00244         ht_ltextfile_line *e=fetch_line_into_memory(line);
00245         if (e) {
00246                 char *ostr=e->in_memory.data;
00247                 UINT olen=e->in_memory.len;
00248                 
00249                 if (ofs<olen) {
00250                         if (ofs+count>olen) count=olen-ofs;
00251                         char *nstr=(char*)malloc(olen-count);
00252                         memcpy(nstr, ostr, ofs);
00253                         memcpy(nstr+ofs, ostr+ofs+count, olen-ofs-count);
00254                         free(ostr);
00255                         e->in_memory.data=nstr;
00256                         e->in_memory.len=olen-count;
00257                         dirty_parse(line+1);
00258                         dirty_nofs(line+1);
00259                         dirty=true;
00260                 }
00261         }
00262 }
00263 
00264 void ht_ltextfile::delete_lines(UINT line, UINT count)
00265 {
00266         lines->del_multiple(line, count);
00267         dirty_parse(line);
00268         dirty_nofs(line);
00269         dirty=true;
00270 }
00271 
00272 void ht_ltextfile::dirty_parse(UINT line)
00273 {
00274         if (line<first_parse_dirty_line) first_parse_dirty_line=line;
00275 }
00276 
00277 void ht_ltextfile::dirty_nofs(UINT line)
00278 {
00279         if (line<first_nofs_dirty_line) first_nofs_dirty_line=line;
00280 }
00281 
00282 int     ht_ltextfile::extend(UINT newsize)
00283 {
00284         /* FIXME: nyi */
00285         return ENOSYS;
00286 }
00287 
00288 ht_ltextfile_line *ht_ltextfile::fetch_line(UINT line)
00289 {
00290         return (ht_ltextfile_line*)lines->get(line);
00291 }
00292 
00293 ht_ltextfile_line *ht_ltextfile::fetch_line_nofs_ok(UINT line)
00294 {
00295         if (is_dirty_nofs(line)) update_nofs(line);
00296         return fetch_line(line);
00297 }
00298                         
00299 UINT ht_ltextfile::find_linelen_forwd(byte *buf, UINT maxbuflen, FILEOFS ofs, int *le_len)
00300 {
00301         UINT readlen=(maxbuflen>TEXTFILE_READSIZE) ? TEXTFILE_READSIZE : maxbuflen;
00302         byte *bufp;
00303         UINT s;
00304         UINT len = 0;
00305         
00306         if (le_len) *le_len = 0;
00307         do {
00308                 streamfile->seek(ofs);
00309                 s = streamfile->read(buf, readlen);
00310                 int l;
00311                 bufp = match_lineend_forwd(buf, s, &l);
00312                 if (bufp) {
00313                         len += bufp-buf+l;
00314                         if (le_len) *le_len = l;
00315                         break;
00316                 }
00317                 if (s != readlen) {
00318                         len += s;
00319                         break;
00320                 }
00321                 /* make sure current and next read overlap
00322                    to guarantee proper lineend-matching */
00323                 if (s > (TEXTFILE_MAX_LINEENDLEN-1)) {
00324                         len += s-(TEXTFILE_MAX_LINEENDLEN-1);
00325                 }
00326                 ofs += s-(TEXTFILE_MAX_LINEENDLEN-1);
00327         } while (s == readlen);
00328         if (len > TEXTFILE_MAX_LINELEN) {
00329                 len = TEXTFILE_MAX_LINELEN;
00330                 if (le_len) *le_len = 0;
00331         }
00332         return len;
00333 }
00334 
00335 ht_ltextfile_line *ht_ltextfile::fetch_line_into_memory(UINT line)
00336 {
00337         ht_ltextfile_line *e=fetch_line(line);
00338         if (e) {
00339                 if (!e->is_in_memory) {
00340                         char *data=(char*)malloc(e->on_disk.len);
00341                         streamfile->seek(e->on_disk.ofs);
00342                         UINT x=streamfile->read(data, e->on_disk.len);
00343 
00344                         e->is_in_memory=true;
00345                         e->in_memory.data=data;
00346                         e->in_memory.len=x/*e->data.on_disk.len*/;
00347                 }
00348         }
00349         return e;
00350 }
00351 
00352 UINT    ht_ltextfile::get_size()
00353 {
00354         int line = linecount()-1;
00355         FILEOFS o = 0;
00356         convert_line2ofs(line, getlinelength(line), &o);
00357         return o;
00358 }
00359 
00360 bool ht_ltextfile::get_char(UINT line, char *ch, UINT pos)
00361 {
00362         ht_ltextfile_line *e=fetch_line(line);
00363         if (e) {
00364                 if (e->is_in_memory) {
00365                         if (pos<e->in_memory.len) {
00366                                 *ch=e->in_memory.data[pos];
00367                                 return true;
00368                         }
00369                 } else {
00370                         if (pos<e->on_disk.len) {
00371                                 streamfile->seek(e->on_disk.ofs);
00372                                 streamfile->read(ch, 1);
00373                                 return true;
00374                         }
00375                 }
00376         }
00377         return false;
00378 }
00379 
00380 
00381 bool ht_ltextfile::getline(UINT line, UINT pofs, void *buf, UINT buflen, UINT *retlen, lexer_state *state)
00382 {
00383 /* <debug> */
00384 /*      bool debug=false;
00385         if (line & 0x80000000) {
00386                 debug=true;
00387                 line&=0x7fffffff;
00388         }*/
00389 /* </debug> */
00390 
00391         ht_ltextfile_line *e=fetch_line(line);
00392 
00393         if (e) {
00394                 if (is_dirty_parse(line)) update_parse(line);
00395                 if (is_dirty_nofs(line)) update_nofs(line);
00396 
00397 /* <debug> */
00398 /*              if (debug) {
00399                         buf+=sprintf(buf, "%5d:", e->nofs);
00400                         maxbuflen-=9;
00401                 }*/
00402 
00403 /* </debug> */
00404 
00405                 UINT ret;
00406                 if (e->is_in_memory) {
00407                         UINT l=e->in_memory.len;
00408                         if (l>buflen-1) l=buflen-1;
00409                         if (pofs>l) l=0; else l-=pofs;
00410                         memmove(buf, e->in_memory.data+pofs, l);
00411                         ret=l;
00412                 } else {
00413                         UINT l=e->on_disk.len;
00414                         if (l>buflen-1) l=buflen-1;
00415                         if (pofs>l) l=0; else l-=pofs;
00416                         streamfile->seek(e->on_disk.ofs+pofs);
00417                         streamfile->read(buf, l);
00418                         ret=l;
00419                 }
00420                 if (state) *state=e->instate;
00421                 *retlen=ret;
00422                 return true;
00423         }
00424         return false;
00425 }
00426 
00427 UINT ht_ltextfile::getlinelength(UINT line)
00428 {
00429         ht_ltextfile_line *e=fetch_line(line);
00430         return getlinelength_i(e);
00431 }
00432 
00433 UINT ht_ltextfile::getlinelength_i(ht_ltextfile_line *e)
00434 {
00435         if (e) {
00436                 if (e->is_in_memory) {
00437                         return e->in_memory.len;
00438                 } else {
00439                         return e->on_disk.len;
00440                 }
00441         }
00442         return 0;
00443 }
00444 
00445 void ht_ltextfile::insert_lines(UINT before, UINT count, void **line_ends, int *line_end_lens)
00446 {
00447         ht_ltextfile_line *e = fetch_line(before);
00448         int instate = e->instate;
00449         while (count--) {
00450                 e = new ht_ltextfile_line();
00451                 e->is_in_memory = true;
00452                 e->instate = instate;
00453                 e->on_disk.ofs = 0xffffffff;
00454                 e->on_disk.len = 0;
00455                 e->in_memory.data = (char*)malloc(1);
00456                 e->in_memory.len = 0;
00457                 e->nofs = 0;
00458                 if (line_ends && line_end_lens) {
00459                         e->lineendlen = *line_end_lens++;
00460                         memmove(e->lineend, *line_ends++, e->lineendlen);
00461                 } else {
00462                         e->lineendlen = 1;
00463                         e->lineend[0] = '\n';
00464                 }
00465                 lines->insert_before(e, before);
00466         }
00467         dirty_parse(before);
00468         dirty_nofs(before);
00469         dirty = true;
00470 }
00471 
00472 void ht_ltextfile::insert_chars(UINT line, UINT ofs, void *chars, UINT len)
00473 {
00474         ht_ltextfile_line *e=fetch_line(line);
00475         if (e) {
00476                 UINT olen=e->is_in_memory ? e->in_memory.len : e->on_disk.len;
00477                 if (ofs<=olen) {
00478                         e=fetch_line_into_memory(line);
00479                         char *ostr=e->in_memory.data;
00480 
00481                         char *nstr;
00482                         UINT nlen=olen;
00483 
00484                         UINT clen=len;
00485 
00486                         if (ofs>nlen) nlen=ofs;
00487                         nlen+=clen;
00488                         nstr=(char*)malloc(nlen);
00489 
00490                         memcpy(nstr, ostr, ofs);
00491                         memcpy(nstr+ofs, chars, clen);
00492                         memcpy(nstr+ofs+clen, ostr+ofs, olen-ofs);
00493 
00494                         e->in_memory.data=nstr;
00495                         e->in_memory.len=nlen;
00496                         dirty_parse(line+1);
00497                         dirty_nofs(line+1);
00498                         dirty=true;
00499                         free(ostr);
00500                 }                       
00501         }
00502 }
00503 
00504 bool ht_ltextfile::has_line(UINT line)
00505 {
00506         return (fetch_line(line)!=NULL);
00507 }
00508 
00509 bool ht_ltextfile::is_dirty_nofs(UINT line)
00510 {
00511         return (line>=first_nofs_dirty_line);
00512 }
00513 
00514 bool ht_ltextfile::is_dirty_parse(UINT line)
00515 {
00516         return (line>=first_parse_dirty_line);
00517 }
00518 
00519 UINT ht_ltextfile::linecount()
00520 {
00521         return lines->count();
00522 }
00523 
00524 byte *ht_ltextfile::match_lineend_forwd(byte *buf, UINT buflen, int *le_len)
00525 {
00526         byte *result=NULL;
00527         
00528         byte *n=(byte*)memchr(buf, '\n', buflen);
00529         if (n) {
00530                 if ((n>buf) && (n[-1] == '\r')) {
00531                         *le_len=2;
00532                         result=n-1;
00533                 } else {
00534                         *le_len=1;
00535                         result=n;
00536                 }
00537         }
00538         return result;
00539 }
00540 
00541 lexer_state ht_ltextfile::next_instate(UINT line)
00542 {
00543         byte buf[TEXTFILE_MAX_LINELEN+1];
00544         lexer_state state = 0;
00545 
00546         UINT buflen;
00547         if (!getline(line, 0, buf, TEXTFILE_MAX_LINELEN, &buflen, &state)) return state;
00548         buf[buflen] = 0;
00549         
00550         if (lexer) {
00551                 text_pos p;
00552                 char *bufp = (char*)buf;
00553                 UINT toklen;
00554                 bool start_of_line = true;
00555                 p.line = line;
00556                 p.pofs = 0;
00557                 int bufplen = buflen;
00558                 int prev_bufplen = -1;
00559                 while ((lexer->gettoken(bufp, bufplen, p, start_of_line, &state, &toklen))) {
00560                         bufp += toklen;
00561                         p.pofs += toklen;
00562                         bufplen -= toklen;
00563                         start_of_line = false;
00564                         if (!bufplen && !prev_bufplen) break;
00565                         prev_bufplen = bufplen;
00566                 }
00567         }
00568         return state;
00569 }
00570 
00571 FILEOFS ht_ltextfile::next_nofs(ht_ltextfile_line *l)
00572 {
00573         if (l) {
00574                 if (l->is_in_memory) return l->nofs+l->in_memory.len+l->lineendlen; else
00575                         return l->nofs+l->on_disk.len+l->lineendlen;
00576         }
00577         return 0;
00578 }
00579 
00580 void    ht_ltextfile::pstat(pstat_t *s)
00581 {
00582         streamfile->pstat(s);
00583         s->size=get_size();
00584         s->size_high=0;
00585 }
00586 
00587 UINT    ht_ltextfile::read(void *buf, UINT size)
00588 {
00589         FILEOFS o=tell();
00590         UINT line;
00591         UINT pofs;
00592         UINT c=0;
00593         byte *b=(byte*)buf;
00594         
00595         if (convert_ofs2line(o, &line, &pofs)) while (size) {
00596                 ht_ltextfile_line *l=fetch_line(line);
00597                 if (!l)
00598                         break;
00599                 UINT q;
00600                 if (l->is_in_memory) {
00601                         q=l->in_memory.len;
00602                         UINT s=q;
00603                         if (s>pofs) {
00604                                 s-=pofs;
00605                                 s=MIN(size, s);
00606                                 memcpy(b+c, l->in_memory.data+pofs, s);
00607                                 size-=s;
00608                                 c+=s;
00609                                 pofs+=s;
00610                         }
00611                 } else {
00612                         q=l->on_disk.len;
00613                         UINT r;
00614                         UINT s=q;
00615                         if (s>pofs) {
00616                                 s-=pofs;
00617                                 s=MIN(size, s);
00618                                 streamfile->seek(l->on_disk.ofs+pofs);
00619                                 r=streamfile->read(b+c, s);
00620                                 if (r!=s) break;
00621                                 size-=s;
00622                                 c+=s;
00623                                 pofs+=s;
00624                         }
00625                 }
00626                 UINT s=l->lineendlen;
00627                 if ((q+s>pofs) && (pofs >= q)) {
00628                         s-=pofs-q;
00629                         s=MIN(size, s);
00630                         memcpy(b+c, l->lineend+(pofs-q), s);
00631                         size-=s;
00632                         c+=s;
00633                 }
00634                 line++;
00635                 pofs=0;
00636         }
00637         ofs += c;
00638         return c;
00639 }
00640 
00641 void ht_ltextfile::reread()
00642 {
00643         lines->empty();
00644         orig_lines->empty();
00645         dirty=false;
00646         FILEOFS ofs=0;
00647         int ll, pll=-1, ln=0;
00648         bool firstline=true;
00649         byte buf[TEXTFILE_MAX_LINELEN+1];
00650 
00651         lexer_state state=0;
00652         ht_ltextfile_line *e, *ce;
00653 
00654         if (lexer) state=lexer->getinitstate();
00655 
00656         UINT l=0;
00657         while ((l=find_linelen_forwd(buf, sizeof buf, ofs, &ll))) {
00658                 if (streamfile->seek(ofs) != 0) break;
00659                 UINT x=streamfile->read(buf, l-ll);
00660                 buf[x]=0;
00661 
00662                 e=new ht_ltextfile_line();
00663                 e->is_in_memory=false;
00664                 e->instate=state;
00665                 e->on_disk.ofs=ofs;
00666                 e->on_disk.len=l-ll;
00667                 e->nofs=ofs;
00668                 e->lineendlen=ll;
00669                 assert( (UINT)ll <= sizeof e->lineend);
00670                 streamfile->read(e->lineend, ll);
00671                 lines->append(e);
00672                 ce=new ht_ltextfile_line();
00673                 *ce = *e;
00674                 orig_lines->append(ce);
00675 
00676                 if (lexer) {
00677                         text_pos p;
00678                         char *bufp=(char*)buf;
00679                         UINT toklen;
00680                         bool start_of_line=true;
00681                         p.line=ln;
00682                         p.pofs=0;
00683                         while (lexer->gettoken(bufp, l-ll-(bufp-(char*)buf), p, start_of_line, &state, &toklen)) {
00684                                 bufp+=toklen;
00685                                 p.pofs+=toklen;
00686                                 start_of_line=false;
00687                         }
00688                 }
00689 
00690                 ofs+=l;
00691                 pll=ll;
00692                 firstline=false;
00693                 ln++;
00694         }
00695 
00696         if (pll || firstline) {
00697                 ll=0;
00698                 e=new ht_ltextfile_line();
00699                 e->is_in_memory=false;
00700                 e->instate=state;
00701                 e->on_disk.ofs=ofs;
00702                 e->on_disk.len=l-ll;
00703                 e->nofs=ofs;
00704                 e->lineendlen=ll;
00705                 lines->append(e);
00706                 ce=new ht_ltextfile_line();
00707                 *ce = *e;
00708                 orig_lines->append(ce);
00709         }
00710 }
00711 
00712 void ht_ltextfile::split_line(UINT a, UINT pos, void *line_end, int line_end_len)
00713 {
00714         if (pos == 0) {
00715                 insert_lines(a, 1, &line_end, &line_end_len);
00716         } else {
00717                 UINT l=getlinelength(a);
00718                 if (pos>l) pos=l;
00719                 char *aline=(char*)malloc(pos+1);
00720                 UINT alinelen;
00721                 getline(a, 0, aline, pos+1, &alinelen, NULL);
00722         
00723                 insert_lines(a, 1, &line_end, &line_end_len);
00724                 insert_chars(a, 0, aline, alinelen);
00725 
00726                 delete_chars(a+1, 0, pos);
00727                 free(aline);
00728         }
00729 }
00730 
00731 int     ht_ltextfile::seek(FILEOFS offset)
00732 {
00733         ofs = offset;
00734         return 0;
00735 }
00736 
00737 void ht_ltextfile::set_layered(ht_streamfile *streamfile)
00738 {
00739         ht_layer_streamfile::set_layered(streamfile);
00740         reread();
00741 }
00742 
00743 void ht_ltextfile::set_layered_assume(ht_streamfile *streamfile, bool changes_applied)
00744 {
00745         if (changes_applied) {
00746                 orig_lines->empty();
00747                 UINT c = lines->count();
00748                 for (UINT i=0; i<c; i++) {
00749                         ht_ltextfile_line *l = fetch_line_nofs_ok(i);
00750                         ht_ltextfile_line *m = new ht_ltextfile_line();
00751                         l->on_disk.ofs = l->nofs;
00752                         if (l->is_in_memory) {
00753                                 l->on_disk.len = l->in_memory.len;
00754                                 free(l->in_memory.data);
00755                                 l->is_in_memory = false;
00756                         }
00757                         *m = *l;
00758                         orig_lines->append(m);
00759                 }
00760                 cache_invd();
00761         }
00762         ht_layer_streamfile::set_layered(streamfile);
00763 }
00764 
00765 void ht_ltextfile::set_lexer(ht_syntax_lexer *l)
00766 {
00767         if (lexer != l) {
00768                 lexer = l;
00769                 dirty_parse(0);
00770         }
00771 }
00772 
00773 FILEOFS ht_ltextfile::tell()
00774 {
00775         return ofs;
00776 }
00777 
00778 int     ht_ltextfile::truncate(UINT newsize)
00779 {
00780         /* FIXME: nyi */
00781         return ENOSYS;
00782 }
00783 
00784 void ht_ltextfile::update_parse(UINT target)
00785 {
00786         ht_ltextfile_line *e;
00787         UINT line = first_parse_dirty_line;
00788 
00789         lexer_state instate=0;
00790         if (line) {
00791                 instate = next_instate(line-1);
00792 // FIXME: function help works with this already...
00793 /*              e = fetch_line(line);
00794                 instate = e->instate;*/
00795         } else {
00796                 if (lexer) instate = lexer->getinitstate();
00797         }
00798 
00799         while (line<=target) {
00800                 e = fetch_line(line);
00801                 if (!e) break;
00802 //              if (e->instate==instate) break; /* FIXME: valid simplification ?!... */
00803                 e->instate = instate;
00804                 first_parse_dirty_line = line+1;
00805                 instate = next_instate(line);
00806                 line++;
00807         }
00808         e = fetch_line(line);
00809         if (e) e->instate = instate;
00810 }
00811 
00812 void ht_ltextfile::update_nofs(UINT target)
00813 {
00814         ht_ltextfile_line *e;
00815         UINT line=first_nofs_dirty_line;
00816 
00817         FILEOFS nofs;
00818         if (line) {
00819                 e=fetch_line(line-1);
00820                 nofs=next_nofs(e);
00821         } else {
00822                 nofs=0;
00823         }
00824 
00825         while (line<=target) {
00826                 e=fetch_line(line);
00827                 if (!e) break;
00828                 e->nofs=nofs;
00829                 first_nofs_dirty_line=line+1;
00830                 nofs=next_nofs(e);
00831                 line++;
00832         }
00833 }
00834 
00835 int ht_ltextfile::vcntl(UINT cmd, va_list vargs)
00836 {
00837         switch (cmd) {
00838                 case FCNTL_MODS_INVD:
00839                                 cache_invd();
00840                                 return 0;
00841                 case FCNTL_MODS_FLUSH:
00842                                 cache_flush();
00843                                 return 0;
00844                 case FCNTL_MODS_IS_DIRTY: {
00845                                 FILEOFS o=va_arg(vargs, FILEOFS);
00846                                 UINT s=va_arg(vargs, UINT);
00847                                 bool *b=va_arg(vargs, bool*);
00848                                 *b = dirty;
00849                                 o = 0;  // gcc warns otherwise
00850                                 s = 0;    // gcc warns otherwise
00851                                 return 0;
00852                 }
00853                 case FCNTL_MODS_CLEAR_DIRTY: {
00854                         dirty = false;
00855                         return 0;
00856                 }
00857         }
00858         return ht_textfile::vcntl(cmd, vargs);
00859 }
00860 
00861 UINT    ht_ltextfile::write(const void *buf, UINT size)
00862 {
00863         FILEOFS o = tell();
00864         UINT line;
00865         UINT pofs;
00866         byte *b = (byte*)buf;
00867         UINT r = 0;
00868         if (convert_ofs2line(o, &line, &pofs)) {
00869                 r = size;
00870                 while (size) {
00871                         int lelen;
00872                         UINT s;
00873                         byte *c = match_lineend_forwd(b, size, &lelen);
00874                         if (c) {
00875                                 s = c-b;
00876                                 split_line(line, pofs, c, lelen);
00877                         } else {
00878                                 s = size;
00879                                 lelen = 0;
00880                         }
00881                         insert_chars(line, pofs, b, s);
00882                         s += lelen;
00883                         b += s;
00884                         size -= s;
00885                         line++;
00886                         pofs = 0;
00887                 }
00888         }
00889         ofs += r;
00890         return r;
00891 }

Generated on Fri May 7 21:15:45 2004 by doxygen 1.3.5