#pragma implementation #include #include #include #include "tledit.h" #include #include "component.h" #include "tledit.m" PUBLIC PARAM::PARAM(const char *_name, const char *_type, const char *_desc) { name.setfrom (_name); type.setfrom (_type); desc.setfrom (_desc); } PUBLIC PARAM::PARAM() { } PUBLIC PARAM *PARAMS::getitem(int no) const { return (PARAM*)ARRAY::getitem(no); } static const unsigned char K_SECTION[]="section"; static const unsigned char K_COMPONENT[]="component"; static const unsigned char K_NAME[]="name"; static const unsigned char K_RETURN[]="return"; static const unsigned char K_DESCRIPTION[]="description"; static const unsigned char K_SUMMARY[]="summary"; static const unsigned char K_PROTOTYPE[]="prototype"; static const unsigned char K_PARAM[]="param"; static const unsigned char K_FUNCTAG[]="functag"; static const unsigned char K_FHELPER[]="fhelper"; static const unsigned char K_METHOD[]="method"; static const unsigned char K_TYPE[]="type"; static const unsigned char K_OPT[]="opt"; static const unsigned char K_OBJ[]="obj"; enum COMPONENT_WALK_STATE{ STATE_NONE, STATE_SECTION, STATE_COMPONENT, STATE_FUNCTAG, STATE_FHELPER, STATE_PROTOTYPE, STATE_METHOD, }; struct _F_component_walk_private { xmlNodePtr cur; COMPONENT_WALK_STATE state; bool modified; int functag_no; // Use to count the functags in a component int fhelper_no; // Use to count the fhelpers in a component int proto_no; // Use to count the prototypes in a component int param_no; int method_no; _F_component_walk_private(){ modified = false; state = STATE_NONE; cur = NULL; method_no = param_no = proto_no = fhelper_no = functag_no = 0; } }; const char *_F_component_walk::getprop (const char *key) { xmlChar *p = xmlGetProp (priv->cur,(xmlChar*)key); return (const char *)p; } /* Return the content of a node. The caller must free the result */ static char *component_getcontent( xmlNodePtr cur, const unsigned char *key) { char *ret = NULL; xmlNodePtr sub = cur->xmlChildrenNode; while (sub != NULL){ // fprintf (stderr,"getcontent :%s:\n",sub->name); if (xmlStrcmp(sub->name,key)==0){ ret = (char *)xmlNodeGetContent(sub); break; } sub = sub->next; } return ret; } /* Update the content of a node. Add a node if none found. */ static void component_setcontent( xmlNodePtr cur, const unsigned char *key, const char *val) { xmlNodePtr sub = cur->xmlChildrenNode; if (sub == NULL){ xmlNewChild (cur,NULL,key,(const xmlChar*)val); }else{ bool found = false; while (sub != NULL){ // fprintf (stderr,"getcontent :%s:\n",sub->name); if (xmlStrcmp(sub->name,key)==0){ xmlNodeSetContent(sub,(const xmlChar*)val); found = true; break; } sub = sub->next; } if (!found){ xmlNewChild (cur,NULL,key,(const xmlChar*)val); } } } const char *_F_component_walk::getsummary () { return component_getcontent (priv->cur,K_SUMMARY); } const char *_F_component_walk::getdescription () { return component_getcontent (priv->cur,K_DESCRIPTION); } /* Update the summary of the current node. This is generally called in a functag, fhelper and component context */ void _F_component_walk::setsummary (const char *text) { if (priv->state == STATE_COMPONENT || priv->state == STATE_FUNCTAG || priv->state == STATE_METHOD || priv->state == STATE_SECTION || priv->state == STATE_FHELPER){ priv->modified = true; component_setcontent (priv->cur,K_SUMMARY,text); }else{ tlmp_error (MSG_U(E_SETSUMMARY ,"Programming error: setsummary called in context %d\n") ,priv->state); } } /* Set the description of the current node. This is generally called in a functag, fhelper and component context */ void _F_component_walk::setdescription (const char *text) { if (priv->state == STATE_COMPONENT || priv->state == STATE_FUNCTAG || priv->state == STATE_METHOD || priv->state == STATE_PROTOTYPE || priv->state == STATE_SECTION || priv->state == STATE_FHELPER){ priv->modified = true; component_setcontent (priv->cur,K_DESCRIPTION,text); }else{ tlmp_error (MSG_U(E_SETDESCRIPTION ,"Programming error: setdescription called in context %d\n") ,priv->state); } } /* Update the parameters of the current node. This is generally called in a functag, fhelper and prototype context */ void _F_component_walk::setparams (PARAMS ¶ms) { if (priv->state == STATE_PROTOTYPE || priv->state == STATE_FUNCTAG || priv->state == STATE_METHOD || priv->state == STATE_FHELPER){ PARAMS filled; filled.neverdelete(); for (int i=0; iname.is_filled()) filled.add (p); } priv->modified = true; xmlNodePtr sub = priv->cur->xmlChildrenNode; int no = 0; while (sub != NULL){ xmlNodePtr next = sub->next; if (xmlStrcmp(sub->name,K_PARAM)==0){ PARAM *p = filled.getitem(no); if (p != NULL){ xmlSetProp (sub,K_NAME,(const xmlChar*)p->name.get()); xmlSetProp (sub,K_TYPE,(const xmlChar*)p->type.get()); component_setcontent (sub,K_DESCRIPTION,p->desc.get()); }else{ xmlUnlinkNode (sub); xmlFreeNode (sub); } no++; } sub = next; } for (int i=no; icur,NULL,K_PARAM,NULL); xmlSetProp (n,K_NAME,(const xmlChar*)p->name.get()); xmlSetProp (n,K_TYPE,(const xmlChar*)p->type.get()); component_setcontent (n,K_DESCRIPTION,p->desc.get()); } }else{ tlmp_error (MSG_U(E_SETPARAMS ,"Programming error: setparams called in context %d\n") ,priv->state); } } /* Update the return type of the current node. This is generally called in a functag, fhelper and prototype context */ void _F_component_walk::setreturn (const char *type) { if (priv->state == STATE_PROTOTYPE || priv->state == STATE_FUNCTAG || priv->state == STATE_METHOD || priv->state == STATE_FHELPER){ priv->modified = true; xmlSetProp (priv->cur,K_RETURN,(const xmlChar*)type); }else{ tlmp_error (MSG_U(E_SETRETURN ,"Programming error: setreturn called in context %d\n") ,priv->state); } } /* Update the "optional" flag of the current node. This is generally called in a functag. */ void _F_component_walk::setoptional (bool optional) { if (priv->state == STATE_FUNCTAG){ priv->modified = true; xmlSetProp (priv->cur,K_OPT,(const xmlChar*)(optional ? "1" : "0")); }else{ tlmp_error (MSG_U(E_SETOPTIONAL ,"Programming error: setoptional called in context %d\n") ,priv->state); } } /* Update the "obj" flag of the current node. This is generally called in a component. */ void _F_component_walk::setobj (bool is_obj) { if (priv->state == STATE_COMPONENT){ priv->modified = true; xmlSetProp (priv->cur,K_OBJ,(const xmlChar*)(is_obj ? "1" : "0")); }else{ tlmp_error (MSG_U(E_SETOBJ ,"Programming error: setobj called in context %d\n") ,priv->state); } } /* Update the "optional" flag of the current node. This is generally called in a functag. */ void _F_component_walk::setname (const char *name) { if (priv->state == STATE_COMPONENT || priv->state == STATE_FUNCTAG || priv->state == STATE_METHOD || priv->state == STATE_FHELPER){ priv->modified = true; xmlSetProp (priv->cur,K_NAME,(const xmlChar*)name); }else{ tlmp_error (MSG_U(E_SETNAME ,"Programming error: setname called in context %d\n") ,priv->state); } } /* Delete the current node (and all child */ void _F_component_walk::delnode() { } void _F_component_walk::addfunctag (const char *name) { if (priv->state == STATE_COMPONENT){ priv->modified = true; xmlNodePtr n = xmlNewChild (priv->cur,NULL,K_FUNCTAG,NULL); xmlSetProp (n,K_NAME,(const xmlChar *)name); }else{ tlmp_error (MSG_U(E_ADDFUNCTAG ,"Programming error: addfunctag called in context %d\n") ,priv->state); } } void _F_component_walk::addfhelper (const char *name) { if (priv->state == STATE_COMPONENT){ priv->modified = true; xmlNodePtr n = xmlNewChild (priv->cur,NULL,K_FHELPER,NULL); xmlSetProp (n,K_NAME,(const xmlChar *)name); }else{ tlmp_error (MSG_U(E_ADDFHELPER ,"Programming error: addfhelper called in context %d\n") ,priv->state); } } void _F_component_walk::addmethod (const char *name) { if (priv->state == STATE_COMPONENT){ priv->modified = true; xmlNodePtr n = xmlNewChild (priv->cur,NULL,K_METHOD,NULL); xmlSetProp (n,K_NAME,(const xmlChar *)name); }else{ tlmp_error (MSG_U(E_ADDMETHOD ,"Programming error: addmethod called in context %d\n") ,priv->state); } } void _F_component_walk::addprototype () { if (priv->state == STATE_COMPONENT){ priv->modified = true; xmlNewChild (priv->cur,NULL,K_PROTOTYPE,NULL); }else{ tlmp_error (MSG_U(E_ADDPROTOTYPE ,"Programming error: addprototype called in context %d\n") ,priv->state); } } void _F_component_walk::addcomponent (const char *name) { if (priv->state == STATE_SECTION){ priv->modified = true; xmlNodePtr n = xmlNewChild (priv->cur,NULL,K_COMPONENT,NULL); xmlSetProp (n,K_NAME,(const xmlChar *)name); }else{ tlmp_error (MSG_U(E_ADDCOMPONENT ,"Programming error: addcomponent called in context %d\n") ,priv->state); } } void _F_component_walk::getxml (SSTRING &s) { s.setempty(); xmlDocPtr doc = xmlNewDoc((const unsigned char*)"1.0"); if (doc != NULL){ xmlDocSetRootElement (doc,priv->cur); xmlNodePtr next = priv->cur->next; priv->cur->next = NULL; xmlChar *buf; int size; xmlDocDumpMemory (doc,&buf,&size); if (buf != NULL){ s.setfrom ((const char *)buf); free (buf); } xmlDocSetRootElement (doc,NULL); xmlFreeDoc(doc); priv->cur->next = next; } } void _F_component_walk::section( const char *name, const char *summary, const char *descrip, COMPONENT_WALK_INFO &info, bool &end, bool &skip) { } void _F_component_walk::component( int no, const char *name, const char *summary, const char *descrip, bool is_obj, COMPONENT_WALK_INFO &info, bool &end, bool &skip) { } void _F_component_walk::prototype( int no, const char *name, const char *rettype, const char *descrip, COMPONENT_WALK_INFO &info, bool &end, bool &skip) { skip = true; } void _F_component_walk::functag( int no, const char *name, const char *rettype, const char *summary, const char *descrip, bool optional, COMPONENT_WALK_INFO &info, bool &end, bool &skip) { skip = true; } void _F_component_walk::method( int no, const char *name, const char *rettype, const char *summary, const char *descrip, COMPONENT_WALK_INFO &info, bool &end, bool &skip) { skip = true; } void _F_component_walk::fhelper( int no, const char *name, const char *summary, const char *descrip, const char *rettype, COMPONENT_WALK_INFO &info, bool &end, bool &skip) { skip = true; } void _F_component_walk::param( int no, const char *name, const char *type, const char *descrip, COMPONENT_WALK_INFO &info, bool &end, bool &skip) { } PUBLIC COMPONENT_WALK_INFO::COMPONENT_WALK_INFO() { level = 0; section = ""; func = ""; } static int cmp_nodes (const void *p1, const void *p2) { xmlNodePtr n1 = *(xmlNodePtr*)p1; xmlNodePtr n2 = *(xmlNodePtr*)p2; int ret = xmlStrcmp(n1->name,n2->name); if (ret == 0){ char *cname1 = (char *)xmlGetProp(n1,K_NAME); char *cname2 = (char *)xmlGetProp(n2,K_NAME); if (cname1 == NULL && cname2 == NULL){ ret = 0; }else if (cname1 != NULL && cname2 == NULL){ ret = 1; }else if (cname1 == NULL && cname2 != NULL){ ret = -1; }else{ ret = strcmp(cname1,cname2); } free (cname1); free (cname2); } return ret; } static void component_trim (SSTRING &s, const char *val) { if (val == NULL){ s.setempty(); }else{ val = str_skip(val); s.setfrom(val); s.strip_end (); } } static void component_walk ( _F_component_walk &c, xmlNodePtr cur, COMPONENT_WALK_STATE state, bool &end, COMPONENT_WALK_INFO &info, int sel) // Topics selected: COMPWALK_SEL_xxxxx { if (cur == NULL) return; info.level++; int nbnodes = 0; { // First we count the number of nodes at this level xmlNodePtr next = cur; while (next != NULL){ nbnodes++; next = next->next; } } xmlNodePtr tbsorted[nbnodes],tbother[nbnodes]; int nbsorted = 0,nbother=0; { // Now we extract the sortable ones xmlNodePtr next = cur; while (next != NULL){ if (xmlStrcmp(next->name,K_FUNCTAG)==0 || xmlStrcmp(next->name,K_FHELPER)==0 || xmlStrcmp(next->name,K_METHOD)==0 || xmlStrcmp(next->name,K_COMPONENT)==0){ tbsorted[nbsorted++] = next; }else{ tbother[nbother++] = next; } next = next->next; } } qsort (tbsorted,nbsorted,sizeof(tbsorted[0]),cmp_nodes); if (nbother > 0){ memcpy (tbsorted+nbsorted,tbother,sizeof(tbsorted[0])*nbother); } int nb = nbsorted + nbother; for (int i=0; icur = cur; c.priv->state = state; xmlNodePtr sub = cur->xmlChildrenNode; char *cname = (char *)xmlGetProp(cur,K_NAME); char *ptdescrip = component_getcontent (cur,K_DESCRIPTION); SSTRING tmp_descrip; component_trim (tmp_descrip,ptdescrip); const char *descrip = tmp_descrip.get(); char *ptsummary = component_getcontent (cur,K_SUMMARY); SSTRING tmp_summary; component_trim (tmp_summary,ptsummary); const char *summary = tmp_summary.get(); // printf ("cur->name :%s: :%s: :%s:\n",cur->name,cname,summary); bool skip = false; if (xmlStrcmp(cur->name,K_SECTION)==0){ int n = info.sections.getnb(); info.sections.add (new SSTRING(cname)); info.section = cname; if (info.level == 1) c.priv->state = STATE_SECTION; c.section (cname,summary,descrip,info,end,skip); if (!skip && !end) component_walk (c,sub,state,end,info,sel); info.sections.remove_del(n); info.section = ""; if (n > 1){ info.section = info.sections.getitem(n-2)->get(); } }else if (xmlStrcmp(cur->name,K_COMPONENT)==0){ info.component = cname; c.priv->state = STATE_COMPONENT; c.priv->functag_no = c.priv->fhelper_no = c.priv->proto_no = 0; c.priv->method_no = 0; bool is_obj = false; xmlChar *pt = xmlGetProp(cur,K_OBJ); if (pt != NULL) is_obj = atoi((const char*)pt)!=0; c.component (i,cname,summary,descrip,is_obj,info,end,skip); if (!skip && !end) component_walk (c,sub,STATE_COMPONENT,end,info,sel); info.component = ""; }else if (xmlStrcmp(cur->name,K_FUNCTAG)==0){ if ((sel & COMPWALK_SEL_FUNCTAG) != 0){ info.func = cname; const char *rettype = ""; xmlChar *pt = xmlGetProp(cur,K_RETURN); if (pt != NULL) rettype = (const char*)pt; bool optional = false; pt = xmlGetProp(cur,K_OPT); if (pt != NULL) optional = atoi((const char*)pt)!=0; c.priv->state = STATE_FUNCTAG; c.priv->param_no = 0; c.functag (c.priv->functag_no++,cname,rettype,summary,descrip,optional,info,end,skip); if (!skip && !end) component_walk (c,sub,STATE_FUNCTAG,end,info,sel); info.func = ""; } }else if (xmlStrcmp(cur->name,K_FHELPER)==0){ if ((sel & COMPWALK_SEL_FHELPER) != 0){ info.func = cname; const char *rettype = ""; xmlChar *pt = xmlGetProp(cur,K_RETURN); if (pt != NULL) rettype = (const char*)pt; c.priv->state = STATE_FHELPER; c.priv->param_no = 0; c.fhelper (c.priv->fhelper_no++,cname,rettype,summary,descrip,info,end,skip); if (!skip && !end) component_walk (c,sub,STATE_FHELPER,end,info,sel); info.func = ""; } }else if (xmlStrcmp(cur->name,K_PROTOTYPE)==0){ if ((sel & COMPWALK_SEL_PROTOTYPE) != 0){ const char *rettype = ""; xmlChar *pt = xmlGetProp(cur,K_RETURN); if (pt != NULL) rettype = (const char*)pt; c.priv->state = STATE_PROTOTYPE; c.priv->param_no = 0; c.prototype (c.priv->proto_no++,info.component,rettype,descrip,info,end,skip); if (!skip && !end) component_walk (c,sub,STATE_PROTOTYPE,end,info,sel); } }else if (xmlStrcmp(cur->name,K_METHOD)==0){ if ((sel & COMPWALK_SEL_METHOD) != 0){ info.func = cname; const char *rettype = ""; xmlChar *pt = xmlGetProp(cur,K_RETURN); if (pt != NULL) rettype = (const char*)pt; c.priv->state = STATE_METHOD; c.priv->param_no = 0; c.method (c.priv->method_no++,cname,rettype,summary,descrip,info,end,skip); if (!skip && !end) component_walk (c,sub,STATE_METHOD,end,info,sel); info.func = ""; } }else if (xmlStrcmp(cur->name,K_PARAM)==0){ if (state != STATE_FUNCTAG && state != STATE_FHELPER && state != STATE_METHOD && state != STATE_PROTOTYPE){ }else{ const char *type = ""; xmlChar *pt = xmlGetProp(cur,K_TYPE); if (pt != NULL) type = (const char*)pt; c.param (c.priv->param_no++,cname,type,descrip,info,end,skip); } } free (cname); free (ptsummary); free (ptdescrip); } info.level--; } int component_walk (_F_component_walk &c, const char *fname, int sel) { int ret = -1; _F_component_walk_private priv; c.priv = &priv; xmlDocPtr doc = xmlParseFile(fname); if (doc != NULL){ ret = 0; xmlNodePtr cur = xmlDocGetRootElement(doc); bool end = false; COMPONENT_WALK_STATE state = STATE_NONE; COMPONENT_WALK_INFO info; component_walk (c,cur,state,end,info,sel); if (priv.modified){ SSTRING tmp; tmp.setfromf ("%s.bak",fname); //fprintf (stderr,"ren :%s: :%s: %d\n",fname,tmp.get(),file_exist(tmp.get())); if (!file_exist(tmp.get()) || rename (fname,tmp.get())!=-1){ xmlSaveFile (fname,doc); ret = 1; } } xmlFreeDoc(doc); } return ret; } /* Parse XML from a string TLMP does not allow inheriting from a component _F_ definition yet... so we have to fiddle with the prototype, instead of having component_walkbuf(). Return -1 if some errors, 0 if ok, 1 if the document was modified */ int component_walk (_F_component_walk &c, SSTRING &s, int sel) { int ret = -1; _F_component_walk_private priv; c.priv = &priv; xmlDocPtr doc = xmlParseMemory((char*)s.get(),s.getlen()); if (doc != NULL){ ret = 0; xmlNodePtr cur = xmlDocGetRootElement(doc); bool end = false; COMPONENT_WALK_STATE state = STATE_NONE; COMPONENT_WALK_INFO info; component_walk (c,cur,state,end,info,sel); if (priv.modified){ xmlChar *buf; int size; xmlDocDumpMemory (doc,&buf,&size); if (buf != NULL){ s.setfrom ((const char *)buf); free (buf); ret = 1; } } xmlFreeDoc(doc); } return ret; } int component_walk (_F_component_walk &c, const char *fname) { return component_walk (c,fname,COMPWALK_SEL_ALL); } void component_walk (_F_component_walk &c, const SSTRINGS &fnames, int sel) { for (int i=0; iget(),sel); } } void component_walk (_F_component_walk &c, const SSTRINGS &fnames) { component_walk (c,fnames,COMPWALK_SEL_ALL); } /* Locate all the *.comp file in a project. For now, it executes a utility called component_find if available. This utility enumerate the .comp file known. */ void component_find (_F_component_find &c) { glocal _F_component_find *c = &c; ("/home/jack/bin/component_find",10,true); glocal.c->onecomp (line); return 0; }