#help_index "DolDoc/File"
public U0 DocLoad(CDoc *doc,U8 *src2,I64 size)
{//Fetch doc from raw mem buf.
I64 i;
U8 *src;
Bool unlock=DocLock(doc);
CDocBin *tmpb;
doc->find_replace->filter_lines=0;
if (src2) {
DocPutS(doc,src2); //Too big DocPrint() is wasteful.
src=src2+StrLen(src2)+1;
i=size-(offset(CDocBin.end)-offset(CDocBin.start));
while (src<=src2+i) {
tmpb=CAlloc(sizeof(CDocBin),doc->mem_task);
MemCpy(&tmpb->start,src,offset(CDocBin.end)-offset(CDocBin.start));
src+=offset(CDocBin.end)-offset(CDocBin.start);
tmpb->data=MAlloc(tmpb->size,doc->mem_task);
if (tmpb->size) {
MemCpy(tmpb->data,src,tmpb->size);
src+=tmpb->size;
}
QueIns(tmpb,doc->bin_head.last);
if (tmpb->num>=doc->cur_bin_num)
doc->cur_bin_num=tmpb->num+1;
}
}
if (!(doc->flags & (DOCF_PLAIN_TEXT|DOCF_PLAIN_TEXT_TABS)))
DocBinsValidate(doc);
DocTop(doc); //Calls DocRecalc(). DOCT_CURSOR will be set.
if (unlock)
DocUnlock(doc);
}
public CDoc *DocRead(U8 *name=NULL,I64 flags=0)
{//Fetch doc from disk. See flags.
CDoc *doc=DocNew;
U8 *src,*name2;
I64 size=0;
CDirContext *dirc;
if (!name) name=blkdev.tmp_filename;
doc->flags|=flags;
name2=FileNameAbs(name);
StrCpy(doc->filename.name,name2);
if (src=FileRead(name2,&size,&doc->file_attr)) {
if (dirc=DirContextNew(name2)) {
DocLoad(doc,src,size);
DirContextDel(dirc);
}
Free(src);
}
Free(name2);
return doc;
}
public U8 *DocSave(CDoc *doc,I64 *_size=NULL)
{//Store doc to raw mem buf.
CDocEntry *doc_e,*doc_e1;
CDocBin *b;
Bool unlock=DocLock(doc);
I64 ch,cnt=1;//terminator
U8 *st,*res,*dst,*src;
if (!(doc->flags & (DOCF_PLAIN_TEXT|DOCF_PLAIN_TEXT_TABS)))
DocBinsValidate(doc);
if (doc->flags&DOCF_NO_CURSOR)
DocRecalc(doc);
else {
DocRecalc(doc,RECALCF_ADD_CURSOR);
if (doc->head.next->type_u8==DOCT_CURSOR)
DocEntryDel(doc,doc->head.next); //If no cursor, DocLoad() puts at top.
}
for (doc_e=doc->head.next;doc_e!=doc;doc_e=doc_e->next) {
if (!Bt(doldoc.type_flags_data,doc_e->type_u8)) {
switch (doc_e->type_u8) {
case DOCT_TAB:
case DOCT_PAGE_BREAK:
case DOCT_CURSOR:
cnt++;
break;
case DOCT_NEW_LINE:
if (doc->flags&DOCF_CARRIAGE_RETURN)
cnt+=2;
else
cnt++;
break;
case DOCT_SOFT_NEW_LINE:
break;
case DOCT_TEXT:
if (!(doc_e->de_flags & ~(DOCEF_TAG|DOCG_BL_IV_UL|DOCEF_WORD_WRAP|
DOCEF_HIGHLIGHT|DOCEF_SKIP|DOCEF_FILTER_SKIP))&&
!(doc_e->type&DOCG_BL_IV_UL)) {
cnt+=StrLen(doc_e->tag);
if (!(doc->flags & (DOCF_PLAIN_TEXT|DOCF_PLAIN_TEXT_TABS)) ||
doc->flags&DOCF_DBL_DOLLARS)
cnt+=StrOcc(doc_e->tag,'$');
break;
}
default:
st=Doc2PlainText(doc,doc_e);
cnt+=StrLen(st)+2;
Free(st);
}
}
}
for (b=doc->bin_head.next;b!=&doc->bin_head;b=b->next)
if (b->use_cnt>b->tmp_use_cnt)
cnt+=offset(CDocBin.end)-offset(CDocBin.start)+b->size;
res=MAlloc(cnt);
dst=res;
doc_e=doc->head.next;
while (doc_e!=doc) {
doc_e1=doc_e->next;
if (!Bt(doldoc.type_flags_data,doc_e->type_u8))
switch (doc_e->type_u8) {
case DOCT_CURSOR:
DocEntryDel(doc,doc_e);
*dst++=CH_CURSOR;
break;
case DOCT_TAB:
*dst++='\t';
break;
case DOCT_NEW_LINE:
if (doc->flags&DOCF_CARRIAGE_RETURN)
*dst++='\r';
*dst++='\n';
break;
case DOCT_SOFT_NEW_LINE:
break;
case DOCT_TEXT:
if (!(doc_e->de_flags & ~(DOCEF_TAG|DOCG_BL_IV_UL|DOCEF_WORD_WRAP|
DOCEF_HIGHLIGHT|DOCEF_SKIP|DOCEF_FILTER_SKIP)) &&
!(doc_e->type&DOCG_BL_IV_UL)) {
src=doc_e->tag;
while (ch=*src++) {
*dst++=ch;
if (ch=='$' && (!(doc->flags & (DOCF_PLAIN_TEXT|
DOCF_PLAIN_TEXT_TABS)) || doc->flags&DOCF_DBL_DOLLARS))
*dst++=ch;
}
break;
}
default:
*dst++='$';
st=Doc2PlainText(doc,doc_e);
StrCpy(dst,st);
dst+=StrLen(st);
*dst++='$';
Free(st);
}
doc_e=doc_e1;
}
*dst++=0;
b=doc->bin_head.next;
if (b!=&doc->bin_head) {
do {
if (b->use_cnt>b->tmp_use_cnt) {
MemCpy(dst,&b->start,offset(CDocBin.end)-offset(CDocBin.start));
dst+=offset(CDocBin.end)-offset(CDocBin.start);
MemCpy(dst,b->data,b->size);
dst+=b->size;
}
b=b->next;
} while (b!=&doc->bin_head);
} else
cnt--; //No terminator
if (_size) *_size=cnt;
if (unlock)
DocUnlock(doc);
return res;
}
public Bool DocWrite(CDoc *doc,Bool prompt=FALSE)
{//Store doc to disk.
I64 size;
U8 *buf;
if (prompt && !DocForm(&doc->filename) ||
doc->filename.name[0]=='A' && doc->filename.name[2]==':')
return FALSE; //CANCEL || LK_DOC,LK_DOC_ANCHOR,LK_DOC_FIND,LK_DOC_LINE?
buf=DocSave(doc,&size);
FileWrite(doc->filename.name,buf,size,0,doc->file_attr);
Free(buf);
return TRUE;
}
#help_index "DolDoc"
public U0 DocInsDoc(CDoc *doc=NULL,CDoc *doc2)
{//Insert copy of doc2 into doc at insert pt, cur_entry.
//TODO: DocRst
U8 *dst;
Bool unlock_doc,unlock_doc2=DocLock(doc2);
CDocEntry *doc_ne,*doc_e=doc2->head.next,*doc_ce;
if (!doc) doc=DocPut;
unlock_doc=DocLock(doc),
DocRemSoftNewLines(doc,NULL);
doc_ce=doc->cur_entry;
if (doc_ce->type_u8==DOCT_TEXT && doc->cur_col>doc_ce->min_col) {
if (doc->cur_col<doc_ce->max_col) {
dst=doc_ce->tag+doc->cur_col;
doc_ne=DocEntryNewTag(doc,doc_ce,dst);
*dst=0;
doc_ne->type=DOCT_TEXT | doc_ce->type & 0xFFFFFF00;
doc_ce->max_col=doc->cur_col;
QueIns(doc_ne,doc_ce);
doc->cur_entry=doc_ne;
doc->cur_col=doc_ne->min_col;
} else
if (doc_ce!=doc)
doc->cur_entry=doc_ce->next;
}
while (doc_e!=doc2) {
if (doc_e->type_u8!=DOCT_SOFT_NEW_LINE) {
doc_ne=DocEntryCopy(doc,doc_e);
QueIns(doc_ne,doc->cur_entry->last);
}
doc_e=doc_e->next;
}
DocRecalc(doc);
if (unlock_doc2)
DocUnlock(doc2);
if (unlock_doc)
DocUnlock(doc);
}
#help_index "DolDoc/Compiler;Compiler/Directive"
public U0 StreamDoc(CDoc *doc)
{//Inject doc into compile stream. Use inside #exe{}.
//TODO: DocRst
Bool unlock_doc=DocLock(doc);
CDocEntry *doc_e=doc->head.next;
while (doc_e!=doc) {
if (doc_e->type_u8==DOCT_TEXT)
StreamPrint("%s",doc_e->tag);
else if (doc_e->type_u8==DOCT_NEW_LINE)
StreamPrint("\n");
else if (doc_e->type_u8==DOCT_TAB)
StreamPrint("\t");
doc_e=doc_e->next;
}
if (unlock_doc)
DocUnlock(doc);
}
#help_index "DolDoc"
Bool DocCaptureUndo(CDoc *doc,Bool force=FALSE)
{
Bool res=FALSE,unlock;
I64 time_stamp,flags;
CDocUndo *u;
if (doc->flags&DOCF_ALLOW_UNDO) {
unlock=DocLock(doc);
time_stamp=GetTSC;
if (doc->flags&DOCF_UNDO_DIRTY &&
time_stamp>doc->undo_head.last->time_stamp+cnts.time_stamp_freq<<4 ||
force) {
u=CAlloc(sizeof(CDocUndo),doc->mem_task);
u->time_stamp=time_stamp;
flags=doc->flags;
doc->flags&=~DOCF_NO_CURSOR;
u->body=DocSave(doc,&u->size);
doc->flags=flags;
QueIns(u,doc->undo_head.last);
doc->flags&=~DOCF_UNDO_DIRTY;
doc->undo_cnt++;
u->doc_flags=doc->flags;
res=TRUE;
if (doc->flags&DOCF_AUTO_SAVE)
DocWrite(doc);
}
if (unlock)
DocUnlock(doc);
}
return res;
}
U0 DocUndoRestore(CDoc *doc)
{
Bool unlock=DocLock(doc);
CDocUndo *u=doc->undo_head.last,*u_next,*u_last;
if (u!=&doc->undo_head) {
QueRem(u);
u_next=doc->undo_head.next;
u_last=doc->undo_head.last;
QueInit(&doc->undo_head);
DocRst(doc,TRUE);
doc->flags=u->doc_flags&~DOCF_NO_CURSOR;
DocLoad(doc,u->body,u->size);
doc->flags=u->doc_flags;
DocUndoDel(doc,u);
doc->undo_head.next=u_next;
doc->undo_head.last=u_last;
}
DocUndoCntSet(doc);
doc->flags&=~DOCF_UNDO_DIRTY;
if (unlock)
DocUnlock(doc);
}
#help_index "Graphics/GR Files;DolDoc/Output;StdOut/DolDoc"
public Bool DocType(CDoc *doc=NULL,U8 *filename,I64 trailing_new_lines=1)
{//Output txt or graphic file to document.
Bool res=FALSE;
CDoc *doc2;
if (!doc && !(doc=DocPut) || doc->doc_signature!=DOC_SIGNATURE_VAL)
return FALSE;
if (FilesFindMatch(filename,FILEMASK_TXT)) {
doc2=DocRead(filename);
DocInsDoc(doc,doc2);
if (IsRaw)
DocDump(doc2,100000);
DocDel(doc2);
res=TRUE;
} else if (FilesFindMatch(filename,"*.GR*")) {
DocGR(doc,filename);
res=TRUE;
}
if (res)
DocPrint(doc,"%h*c",trailing_new_lines,'\n');
return res;
}
#help_index "Graphics/GR Files;"\
"File/Cmd Line (Typically);DolDoc/Cmd Line (Typically);"\
"StdOut;Cmd Line (Typically)"
public Bool Type(U8 *filename,I64 trailing_new_lines=1)
{//Output txt or graphic file to command line.
return DocType(,filename,trailing_new_lines);
}
#help_index "DolDoc/File"
public U8 *DocLineRead(U8 *filename,I64 line,CTask *mem_task=NULL)
{//Extract line from stored doc file. (Slow.)
U8 *res=NULL;
CDoc *doc=DocRead(filename,DOCF_PLAIN_TEXT_TABS|DOCF_NO_CURSOR);
if (DocGoToLine(doc,line) && doc->cur_entry->type_u8==DOCT_TEXT)
res=StrNew(doc->cur_entry->tag,mem_task);
DocDel(doc);
return res;
}
public U8 *DocLineWrite(U8 *filename,I64 line,U8 *st)
{//Write line to stored doc file. (Slow.)
U8 *res=NULL;
CDoc *doc=DocRead(filename,DOCF_PLAIN_TEXT_TABS|DOCF_NO_CURSOR);
if (DocGoToLine(doc,line)) {
if (doc->cur_entry->type_u8==DOCT_TEXT) {
Free(doc->cur_entry->tag);
doc->cur_entry->tag=StrNew(st);
} else
DocPrint(doc,"%s",st);
DocTop(doc);
DocWrite(doc);
}
DocDel(doc);
return res;
}