#include #include #include #include #include #include #include #include "tledit.h" #include "tledit.m" PUBLIC TLNODE::TLNODE ( TLNODE_TYPE _type, const char *_start, const char *_title, const char *_rest, const char *_comment) { type = _type; start.setfrom (_start); title.setfrom (_title); rest.setfrom (_rest); comment.setfrom (_comment); } PUBLIC void TLNODE::set ( TLNODE_TYPE _type, const char *_start, const char *_title, const char *_rest, const char *_comment) { type = _type; start.setfrom (_start); title.setfrom (_title); rest.setfrom (_rest); comment.setfrom (_comment); } /* Remove the common tab indentation of a text and insert the prefix. */ PUBLIC void TLNODE::indent (const char *prefix, SSTRING &newtext) { // We must unindent the text const char *pt = text.get(); bool start = true; int nbtab = 0; int minimum = 100; int nbline = 1; while (*pt != '\0'){ if (start){ if (*pt == '\t'){ nbtab++; }else if (*pt >= ' '){ start = false; if (nbtab < minimum) minimum = nbtab; }else if (*pt == '\n'){ nbtab = 0; } }else if (*pt == '\n'){ nbtab = 0; start = true; nbline++; } pt++; } start = true; pt = text.get(); char tmp[text.getlen()+nbline*strlen(prefix)+1]; char *dst = tmp; nbtab = 0; while (*pt != '\0'){ char car = *pt++; if (car == '\n'){ start = true; nbtab = 0; }else if (start){ if (car == '\t' && nbtab < minimum){ nbtab++; continue; }else{ dst = stpcpy (dst,prefix); start = false; } } *dst++ = car; } *dst = '\0'; newtext.setfrom (tmp); } /* Present a node and the sub-node optionally */ PUBLIC int TLNODE::nodeedit(bool viewsub, FRAMEWORK_INFO &info) { DIALOG dia; SSTRING newtext; if (viewsub){ gettext (newtext,true); }else{ gettext (newtext,false); //indent ("",newtext); } dia.newf_textarea (NULL,newtext,60,20); info.msgs.waitfor (dia); int nof=0; int ret = -1; while (1){ MENU_STATUS code = dia.edit (title.get(),"",help_nil,nof); if (code == MENU_ESCAPE || code == MENU_CANCEL){ break; }else if (code==MENU_ACCEPT){ replace (newtext.get(),viewsub); ret = 0; break; }else if (code == MENU_MESSAGE){ if (info.c->must_end(info.msgs)){ break; } } } return ret; } PUBLIC void TLNODE::replace (const char *newtext, bool viewsub) { if (viewsub){ sub.remove_all(); } text.setfrom (""); SSTREAM_BUF ss(newtext); read (ss,true); } PUBLIC TLNODE *TLNODES::getitem (int no) const { return (TLNODE*)ARRAY::getitem(no); } PUBLIC int TLNODE::write(SSTREAM &ss, int level, int showsub) { int nextlevel = level+1; int extra_level = 0; const char *extra = ""; if (level == 0){ // trickery because stuff between should // not be indented extra_level = 1; extra = "\t"; } char tabs[level+1],texttabs[level+3]; memset (tabs,'\t',level); tabs[level] = '\0'; const char *pttexttabs = tabs; if (type == TLNODE_GLOCAL){ ss.printf ("%s%s\n",extra,tabs); memset (texttabs,'\t',level+extra_level+1); texttabs[level+extra_level+1] = '\0'; pttexttabs = texttabs; }else if (type == TLNODE_F){ ss.printf ("%s\n",tabs,title.get()); }else if (type == TLNODE_MAIN){ ss.printf ("\n"); nextlevel = 0; }else if (type == TLNODE_OBJ){ ss.printf ("%s%s%s%s%s%s\n",extra,tabs,start.get(),title.get() ,rest.get() ,comment.is_empty() ? "" : " // " ,comment.get()); nextlevel = level+extra_level; }else if (type == TLNODE_CALL){ ss.printf ("%s%s%s%s%s%s\n",extra,tabs,start.get(),title.get() ,rest.get() ,comment.is_empty() ? "" : " // " ,comment.get()); nextlevel = level+extra_level; } SSTRING newtext; indent (pttexttabs,newtext); if (showsub > 0 || type == TLNODE_TEXT) ss.printf ("%s",newtext.get()); if (showsub > 0){ sub.ss_write (ss,nextlevel,showsub-1); if (type == TLNODE_GLOCAL){ ss.printf ("%s%s\n",extra,tabs); }else if (type == TLNODE_CALL){ ss.printf ("%s%s\n",extra,tabs); }else if (type == TLNODE_F){ ss.printf ("%s\n",tabs); }else if (type == TLNODE_MAIN){ ss.printf ("\n"); }else if (type == TLNODE_OBJ){ ss.printf ("%s%s\n",extra,tabs); } } return 0; } PUBLIC int TLNODES::ss_write(SSTREAM &ss, int level, int showsub) { for (int i=0; iwrite(ss,level,showsub); } return 0; } PUBLIC int TLNODE::write(const char *fname) { int ret = 0; if (file_exist (fname)){ // Produce a backup. At some point, a configurable component // will take over SSTRING backup; backup.setfromf ("%s.bak",fname); ret = file_copy (fname,backup.get()); } if (ret == 0){ FILE *fout = fopen (fname,"w"); if (fout != NULL){ SSTREAM_FILE ss (fout); ret = write (ss,0,1000); fclose (fout); } } return ret; } class TLNODE_CTX{ public: TLNODE *curnode; TLNODE *stack[100]; int nbstack; bool replace; /*~PROTOBEG~ TLNODE_CTX */ public: TLNODE_CTX (void); void append (const char *line); void next (TLNODE_TYPE type, const char *line, const char *mark, int skip); void next (TLNODE_TYPE type, const char *title); void pop (void); void push (void); void setfirst (TLNODE *first, bool _replace); /*~PROTOEND~ TLNODE_CTX */ }; PUBLIC TLNODE_CTX::TLNODE_CTX () { nbstack = 0; curnode = NULL; } PUBLIC void TLNODE_CTX::setfirst (TLNODE *first, bool _replace) { nbstack = _replace ? 0 : 1; stack[0] = first; curnode = first; replace = _replace; } PUBLIC void TLNODE_CTX::pop() { if (nbstack == 1){ if (!replace){ tlmp_error (MSG_U(E_UNBALANCED,"Un-balanced tlcc file, can't edit\n")); } }else{ nbstack--; curnode = stack[nbstack-1]; } } static const char *tlnode_copyto (char *dst, const char *line) { while (isspace (*line)) line++; while (*line != '\0' && *line != '>') *dst++ = *line++; *dst = '\0'; if (*line == '>') line++; line = str_skip(line); return line; } PUBLIC void TLNODE_CTX::push() { stack[nbstack] = curnode; nbstack++; } PUBLIC void TLNODE_CTX::next( TLNODE_TYPE type, const char *line, // Complete line const char *mark, // Start of < tag int skip) // How many bytes to skip the tag { char word[200],tmprest[200],tmpstart[200]; const char *title = mark + skip; const char *rest = tlnode_copyto (word,title); const char *comment = strstr (rest,"//"); const char *start = ""; if (comment == NULL){ comment = ""; }else{ strcpy (tmprest,rest); tmprest[comment-rest] = '\0'; rest = tmprest; comment = str_skip(comment + 2); } if (line < mark){ line = str_skip(line); if (line < mark){ strcpy (tmpstart,line); tmpstart[mark-line] = '\0'; start = tmpstart; } } if (nbstack==0){ curnode->set (type,start,word,rest,comment); }else{ TLNODE *node = new TLNODE (type,start,word,rest,comment); stack[nbstack-1]->sub.add (node); curnode = node; } } PUBLIC void TLNODE_CTX::next(TLNODE_TYPE type, const char *title) { next (type,title,title,0); } PUBLIC void TLNODE_CTX::append(const char *line) { curnode->text.append (line); } static bool tlnode_matchone(const char *line, const char *keyword) { int len = strlen(keyword); bool ret = false; while (1){ line = strchr(line,'<'); if (line == NULL) break; line++; if (strncmp(line,keyword,len)==0){ line += len; line = str_skip(line); if (*line == '>'){ ret = true; break; } } } return ret; } PUBLIC int TLNODE::read (SSTREAM &ss, bool replace) { glocal TLNODE_CTX ctx; glocal bool funcdecl = false; // Special parsing for stuff after glocal.ctx.setfirst (this,replace); int ret = (ss,true); const char *pt; if (tlnode_matchone(line,"mod")){ glocal.ctx.next(TLNODE_MAIN,""); glocal.funcdecl = true; }else if (tlnode_matchone(line,"/mod")){ glocal.ctx.pop(); glocal.ctx.next(TLNODE_TEXT,""); }else if ((pt=strstr(line,"text.get(); const char *pt = strchr (s,'('); if (pt != NULL){ while (pt > s && isspace(pt[-1])) pt--; const char *end = pt; while (pt > s && (isalpha(pt[-1]) || isdigit(pt[1]) || pt[-1] == '_' || pt[-1] == ':')){ pt--; } glocal.ctx.curnode->title.setfrom(pt,(int)(end-pt)); } glocal.ctx.push(); glocal.ctx.next(TLNODE_TEXT,""); glocal.funcdecl = false; } } return 0; return ret; } PUBLIC int TLNODE::read (const char *fname) { int ret = -1; FILE *fin = xconf_fopen (fname,"r"); if (fin != NULL){ SSTREAM_FILE ss (fin); ret = read (ss,false); fclose (fin); } return ret; } static int tlnode_walk ( _F_tlnode_walk &c, TLNODE *node, int level, int count, bool &end) { if (node->type != TLNODE_TEXT){ c.onenode (node,level,count,end); count++; } for (int i=0; isub.getnb() && !end; i++){ TLNODE *su = node->sub.getitem(i); count = tlnode_walk (c,su,level+1,count,end); } return count; } int tlnode_walk (_F_tlnode_walk &c, TLNODE *node) { int level = 0; int count = 0; bool end = false; return tlnode_walk (c,node,level,count,end); } PUBLIC void TLNODE::gettext (SSTRING &txt, bool showsub) { SSTREAM_BUF ss; write (ss,0,showsub ? 1000 : 1); txt.setfrom (ss.getbuf()); } PUBLIC void TLNODE::gettext (SSTRING &txt) { gettext (txt,true); } #ifdef TEST int main (int argc, char *argv[]) { int ret = (argc, argv,"tlmpwork"); xconf_error(msg); fprintf (stderr,"/tmp/x file.tlcc\n"); if (argc != 1){ usage(); }else{ TLNODE node (TLNODE_TEXT,"","","",""); node.read (argv[0]); (&node); printf ("onenode: %d %d\n",count,level); SSTRING txt; node->gettext (txt,false); printf ("text:\n%s\n",txt.get()); node->replace (txt.get(),false); end = count >= 1; node.write ("/tmp/tlnode.tst"); } return 0; return ret; } #endif