/******************************************************************** * FUNCTION find_alias * * Find the alias record * * INPUTS: * name == alias name to find (not assumed to be z-terminated * namelen == length of name string * RETURNS: * alias record; NULL if not found *********************************************************************/ static alias_cb_t * find_alias (const xmlChar *name, uint32 namelen) { dlq_hdr_t *aliasQ = get_aliasQ(); alias_cb_t *curalias; if (aliasQ == NULL) { SET_ERROR(ERR_INTERNAL_VAL); return NULL; } for (curalias = (alias_cb_t *)dlq_firstEntry(aliasQ); curalias != NULL; curalias = (alias_cb_t *)dlq_nextEntry(curalias)) { uint32 curlen = xml_strlen(curalias->name); int ret = xml_strncmp(curalias->name, name, namelen); if (ret == 0) { if (curlen == namelen) { return curalias; } } else if (ret > 0) { /* already past where this name should be sorted */ return NULL; } } return NULL; } /* find_alias */
/******************************************************************** * FUNCTION do_unset (local RPC) * * unset def * * Handle the unset command; remove the specified alias * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the unset command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ extern status_t do_unset (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset, *parm; status_t res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (res == NO_ERR && valset) { parm = val_find_child(valset, YANGCLI_MOD, NCX_EL_NAME); if (parm) { const xmlChar *varstr = VAL_STR(parm); alias_cb_t *alias = find_alias(varstr, xml_strlen(varstr)); if (alias) { dlq_remove(alias); free_alias(alias); log_info("\nDeleted alias '%s'\n", varstr); } else { res = ERR_NCX_INVALID_VALUE; log_error("\nError: unknown alias '%s'\n", varstr); } } /* else missing parameter already reported */ } /* else no valset already reported */ if (valset) { val_free_value(valset); } return res; } /* do_unset */
/******************************************************************** * FUNCTION read_txid_file * * Read the transaction ID file and return the current ID value found * * INPUTS: * txidfile == full filespec of the transaction ID file * curid == address of return ID * * OUTPUTS: * *curid == return current ID (if return NO_ERR * * RETURNS: * status *********************************************************************/ static status_t read_txid_file (const xmlChar *txidfile, cfg_transaction_id_t *curid) { assert( txidfile && "txidfile is NULL" ); assert( curid && "curid is NULL" ); *curid = 0; status_t res = NO_ERR; FILE *fil = fopen((const char *)txidfile, "r"); if (!fil) { res = errno_to_status(); log_error("\nError: Open txid file for read failed (%s)", get_error_string(res)); return res; } char buffer [128]; if (fgets(buffer, sizeof buffer, fil)) { /* expecting just 1 line containing the ASCII encoding of * the transaction ID */ log_debug4("\nRead transaction ID line '%s'", buffer); uint32 len = xml_strlen((const xmlChar *)buffer); if (len > 1) { /* strip ending newline */ buffer[len-1] = 0; ncx_num_t num; ncx_init_num(&num); res = ncx_convert_num((xmlChar *)buffer, NCX_NF_DEC, NCX_BT_UINT64, &num); if (res == NO_ERR) { agt_cfg_txid = num.ul; *curid = num.ul; log_debug3("\nGot transaction ID line '%llu'", (unsigned long long)num.ul); } else { log_error("\nError: txid is not valid (%s)", get_error_string(res)); } ncx_clean_num(NCX_BT_UINT64, &num); } else { res = ERR_NCX_INVALID_NUM; log_error("\nError: txid is not valid (%s)", get_error_string(res)); } } else { res = errno_to_status(); log_error("\nError: Read txid file failed (%s)", get_error_string(res)); } fclose(fil); return res; } /* read_txid_file */
/******************************************************************** * build a prefix map using the xmplns directives in a message. * * \param msg the message in progrss * \param attrs the the top-level attrs list (e;g, rpc_in_attrs) * \return status *********************************************************************/ static status_t build_prefix_map_from_xmlns_directives( xml_msg_hdr_t* msg, xml_attrs_t* attrs ) { xmlns_id_t invid = xmlns_inv_id(); xml_attr_t *attr = (xml_attr_t *)xml_first_attr(attrs); for ( ; attr; attr = (xml_attr_t *)xml_next_attr(attr)) { /* make sure this is an XMLNS attribute with or wo a prefix */ if (xml_strncmp(XMLNS, attr->attr_qname, XMLNS_LEN)) { continue; } /* find the namespace associated with the prefix note: it is not an error to have extra xmlns decls in the <rpc>elem; still need to make sure not to reuse the prefix anyway */ xmlns_t *nsrec = def_reg_find_ns(attr->attr_val); /* check if this attribute has a prefix */ if (attr->attr_qname == attr->attr_name) { /* no prefix in the name so this must be the default namespace */ if ( !nsrec ) { /* the default namespace is not one of ours, so it will not be * used in the reply */ attr->attr_xmlns_ns = invid; } else { attr->attr_xmlns_ns = nsrec->ns_id; } continue; } /* there is a prefix, so get the prefix len. * The entire prefix was saved as the attr_name */ uint32 plen = xml_strlen(attr->attr_name); /* get a new prefix map */ xmlns_pmap_t *newpmap = xmlns_new_pmap(plen+1); if (!newpmap) { return ERR_INTERNAL_MEM; } /* save the prefix and the xmlns ID */ xml_strncpy(newpmap->nm_pfix, attr->attr_name, plen); if ( !nsrec ) { newpmap->nm_id = invid; attr->attr_xmlns_ns = invid; } else { newpmap->nm_id = nsrec->ns_id; attr->attr_xmlns_ns = nsrec->ns_id; } newpmap->nm_topattr = TRUE; add_pmap(msg, newpmap); } return NO_ERR; }
/******************************************************************** * FUNCTION xml_msg_clean_defns_attr * * Get rid of an xmlns=foo default attribute * * INPUTS: * attrs == xmlns_attrs_t Q to process * * OUTPUTS: * *attrs will be cleaned as needed, * * RETURNS: * status *********************************************************************/ status_t xml_msg_clean_defns_attr (xml_attrs_t *attrs) { xml_attr_t *attr, *nextattr; uint32 len, len2; #ifdef DEBUG if (!attrs) { return SET_ERROR(ERR_INTERNAL_PTR); } #endif len = xml_strlen(XMLNS); for (attr = (xml_attr_t *)xml_first_attr(attrs); attr != NULL; attr = nextattr) { nextattr = (xml_attr_t *)xml_next_attr(attr); len2 = xml_strlen(attr->attr_qname); if (len2 >= len) { if (!xml_strncmp(attr->attr_qname, XMLNS, len)) { if (len == len2) { /* this xmlns=foo is getting toosed so * the netconf NSID can be the default */ dlq_remove(attr); xml_free_attr(attr); return NO_ERR; } /* else xmlns:foo=bar found */ } /* else not xmlns */ } /* else not 'xmlns' */ } return NO_ERR; } /* xml_msg_clean_defns_attr */
/******************************************************************** * FUNCTION set_alias * * Set an alias value field * * INPUTS: * alias == alias record to use * valstr == value string to use * * RETURNS: * status *********************************************************************/ static status_t set_alias (alias_cb_t *alias, const xmlChar *valstr) { status_t res = NO_ERR; if (alias->value) { m__free(alias->value); alias->value = NULL; } alias->quotes = 0; if (valstr) { if (*valstr == '"' || *valstr == '\'') { /* preseve quotes used */ alias->quotes = (*valstr == '"') ? 2 : 1; /* check trim quoted string */ uint32 len = xml_strlen(valstr); if (len > 2) { const xmlChar *endstr = &valstr[len-1]; if (*endstr == *valstr) { /* remove paired quotes */ alias->value = xml_strndup(valstr+1, len-2); if (alias->value == NULL) { res = ERR_INTERNAL_MEM; } } else { /* improper string; unmatched quotes */ res = ERR_NCX_INVALID_VALUE; } } else { /* else got just a quote char */ res = ERR_NCX_INVALID_VALUE; } } else { alias->value = xml_strdup(valstr); if (alias->value == NULL) { res = ERR_INTERNAL_MEM; } } } /* else cleared value if not already */ return res; } /* set_alias */
/******************************************************************** * FUNCTION find_feature_entry * * Find a feature_entry_t * * INPUTS: * featstr == feature string parm to use * featQ == Q of feature_entry_t to use * * RETURNS: * pointer to found entry or NULL if not found *********************************************************************/ static feature_entry_t * find_feature_entry (const xmlChar *featstr, dlq_hdr_t *featQ) { uint32 len = 0; boolean splitdone = FALSE; status_t res = split_feature_string(featstr, &len); if (res == NO_ERR) { splitdone = TRUE; } feature_entry_t *feature_entry = (feature_entry_t *)dlq_firstEntry(featQ); for (; feature_entry != NULL; feature_entry = (feature_entry_t *)dlq_nextEntry(feature_entry)) { if (splitdone && feature_entry->modname) { /* match the module name */ uint32 len2 = xml_strlen(feature_entry->modname); if (len != len2) { continue; } if (xml_strncmp(feature_entry->modname, featstr, len)) { continue; } } /* match the feature name */ if (splitdone) { if (xml_strcmp(feature_entry->feature, &featstr[len+1])) { continue; } } else { if (xml_strcmp(feature_entry->feature, featstr)) { continue; } } return feature_entry; } return NULL; } /* find_feature_entry */
static void func_parse_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { std::string res; if (strcmp(element_name, "基本词义")==0 || strcmp(element_name, "CY")==0) { if (((PwUserData*)user_data)->first_jbcy) { ((PwUserData*)user_data)->first_jbcy = false; } else { res="\n<span foreground=\"blue\"><基本词义></span>"; } // ToDo: These need to fix! } else if (strcmp(element_name, "继承用法")==0) { res="\n<span foreground=\"blue\"><继承用法></span>"; } else if (strcmp(element_name, "习惯用语")==0) { res="\n<span foreground=\"blue\"><习惯用语></span>"; } else if (strcmp(element_name, "词性变化")==0) { res="\n<span foreground=\"blue\"><词性变化></span>"; } else if (strcmp(element_name, "特殊用法")==0) { res="\n<span foreground=\"blue\"><特殊用法></span>"; } else if (strcmp(element_name, "参考词汇")==0) { res="\n<span foreground=\"blue\"><参考词汇></span>"; } else if (strcmp(element_name, "常用词组")==0) { res="\n<span foreground=\"blue\"><常用词组></span>"; } else if (strcmp(element_name, "语源")==0) { res="\n<span foreground=\"blue\"><语源></span>"; } else if (strcmp(element_name, "派生")==0) { res="\n<span foreground=\"blue\"><派生></span>"; } else if (strcmp(element_name, "用法")==0) { res="\n<span foreground=\"blue\"><用法></span>"; } else if (strcmp(element_name, "注释")==0) { res="\n<span foreground=\"blue\"><注释></span>"; } if (!res.empty()) { *(((PwUserData*)user_data)->pango) += res; ((PwUserData*)user_data)->cur_pos += xml_strlen(res.c_str()); } }
/******************************************************************** * FUNCTION show_alias * * Output 1 alias by name * * INPUTS: * name == name of alias to show *********************************************************************/ void show_alias (const xmlChar *name) { show_alias_name(name, xml_strlen(name)); } /* show_alias */
/******************************************************************** * FUNCTION do_aliases (local RPC) * * aliases * aliases clear * aliases show * aliases load[=filespec] * aliases save[=filespec] * * Handle the aliases command, based on the parameter * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the aliases command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_aliases (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset; status_t res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (res == NO_ERR && valset) { /* get the 1 of N 'alias-action' choice */ val_value_t *parm; const xmlChar *parmval = NULL; boolean done = FALSE; /* aliases show */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_SHOW); if (parm) { show_aliases(); done = TRUE; } /* aliases clear */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_CLEAR); if (parm) { dlq_hdr_t *aliasQ = get_aliasQ(); if (!dlq_empty(aliasQ)) { free_aliases(); log_info("\nDeleted all aliases from memory\n"); update_yangcli_param_change_flag (ALIASES_FILE, TRUE); }else { log_info("\nNo aliases found\n"); } done = TRUE; } } /* aliases load */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_LOAD); if (parm) { if (xml_strlen(VAL_STR(parm))) { parmval = VAL_STR(parm); } else { parmval = get_aliases_file(); } res = load_aliases(parmval, !val_set_by_default(parm)); if (res == NO_ERR) { log_info("\nLoaded aliases OK from '%s'\n", parmval); } else { log_error("\nLoad aliases from '%s' failed (%s)\n", parmval, get_error_string(res)); } done = TRUE; } } /* aliases save */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_SAVE); if (parm) { if (xml_strlen(VAL_STR(parm))) { parmval = VAL_STR(parm); } else { parmval = get_aliases_file(); } res = save_aliases(parmval); if (res == NO_ERR) { log_info("\nSaved aliases OK to '%s'\n", parmval); } else if (res != ERR_NCX_CANCELED) { log_error("\nSave aliases to '%s' failed (%s)\n", parmval, get_error_string(res)); } done = TRUE; } } if (!done) { /* no parameters; show all aliases */ show_aliases(); } } if (valset) { val_free_value(valset); } return res; } /* do_aliases */
/******************************************************************** * FUNCTION tstamp_convert_to_utctime * * Check if the specified string is a valid dateTime or * date-and-time string is valid and if so, convert it * to * * INPUTS: * buff == pointer to buffer to check * isNegative == address of return negative date flag * res == address of return status * * OUTPUTS: * *isNegative == TRUE if a negative dateTime string is given * FALSE if no starting '-' sign found * *res == return status * * RETURNS: * malloced pointer to converted date time string * or NULL if some error *********************************************************************/ xmlChar * tstamp_convert_to_utctime (const xmlChar *timestr, boolean *isNegative, status_t *res) { assert(timestr && "timestr is NULL!"); assert(isNegative && "isNegative is NULL!"); assert(res && "res is NULL!"); *res = NO_ERR; struct tm convertedtime; memset(&convertedtime, 0x0, sizeof(struct tm)); if (*timestr == '-') { *isNegative = TRUE; timestr++; } else { *isNegative = FALSE; } xmlChar *buffer = NULL; const char *retptr = NULL; uint32 len = xml_strlen(timestr); if (len == 20) { /* could be in canonical form */ retptr = strptime((const char *)timestr, "%FT%TZ", &convertedtime); if (retptr && *retptr == '\0') { buffer = xml_strdup(timestr); if (!buffer) { *res = ERR_INTERNAL_MEM; return NULL; } else { return buffer; } } else { *res = ERR_NCX_INVALID_VALUE; return NULL; } } else if (len > 20) { retptr = strptime((const char *)timestr, "%FT%T", &convertedtime); if (retptr == NULL || *retptr == '\0') { *res = ERR_NCX_INVALID_VALUE; return NULL; } /* check is frac-seconds entered, and skip it */ if (*retptr == '.') { retptr++; if (!isdigit((int)*retptr)) { *res = ERR_NCX_INVALID_VALUE; return NULL; } retptr++; /* got a start digit */ while (isdigit((int)*retptr)) { retptr++; } } /* check if a timezone offset is present */ retptr = strptime(retptr, "%z", &convertedtime); if (retptr == NULL) { *res = ERR_NCX_INVALID_VALUE; return NULL; } /* check where retptr ended up */ if (*retptr == '\0') { /* OK read all the bytes */ ; } else if (*retptr == ':') { if (strcmp(retptr, ":00")) { /* the linux strptime function does * not process the 'time-minute' field in the * time string; since this is so rare * just treat as a special error */ *res = ERR_NCX_OPERATION_NOT_SUPPORTED; return NULL; } /* else time-minute field == '00' and no error */ } else { *res = ERR_NCX_INVALID_VALUE; return NULL; } buffer = m__getMem(TSTAMP_MIN_SIZE); if (!buffer) { *res = ERR_INTERNAL_MEM; return NULL; } time_t utime = mktime(&convertedtime); if (utime == (utime)-1) { *res = ERR_NCX_INVALID_VALUE; m__free(buffer); return NULL; } struct tm *curtime = gmtime(&utime); time_to_string(curtime, buffer); return buffer; } else { /* improper length */ *res = ERR_NCX_INVALID_VALUE; return NULL; } } /* tstamp_convert_to_utctime */
/******************************************************************** * FUNCTION set_initial_transaction_id * * Set the last_transaction_id for the running config * Will check for sys:transaction-id leaf in config->root * * RETURNS: * status *********************************************************************/ static status_t set_initial_transaction_id (void) { cfg_template_t *cfg = cfg_get_config_id(NCX_CFGID_RUNNING); if (cfg == NULL) { return ERR_NCX_CFG_NOT_FOUND; } if (cfg->root == NULL) { return ERR_NCX_EMPTY_VAL; } agt_profile_t *profile = agt_get_profile(); status_t res = NO_ERR; boolean foundfile = FALSE; /* figure out which transaction ID file to use */ if (profile->agt_startup_txid_file == NULL) { /* search for the default startup-cfg.xml filename */ xmlChar *fname = ncxmod_find_data_file(NCX_DEF_STARTUP_TXID_FILE, FALSE, &res); if (fname == NULL || res != NO_ERR || *fname == 0) { /* need to set the default startup transaction ID file name */ log_debug("\nSetting initial transaction ID file to default"); if (fname) { m__free(fname); } res = NO_ERR; fname = agt_get_startup_filespec(&res); if (fname == NULL || res != NO_ERR) { if (res == NO_ERR) { res = ERR_NCX_OPERATION_FAILED; } log_error("\nFailed to set initial transaction ID file (%s)", get_error_string(res)); if (fname) { m__free(fname); } return res; } /* get dir part and append the TXID file name to it */ uint32 fnamelen = xml_strlen(fname); xmlChar *str = &fname[fnamelen - 1]; while (str >= fname && *str && *str != NCX_PATHSEP_CH) { str--; } if (*str != NCX_PATHSEP_CH) { log_error("\nFailed to set initial transaction ID file"); m__free(fname); return ERR_NCX_INVALID_VALUE; } /* copy base filespec + 1 for the path-sep-ch */ uint32 baselen = (uint32)(str - fname) + 1; uint32 newlen = baselen + xml_strlen(NCX_DEF_STARTUP_TXID_FILE); xmlChar *newstr = m__getMem(newlen + 1); if (newstr == NULL) { m__free(fname); return ERR_INTERNAL_MEM; } str = newstr; str += xml_strncpy(str, fname, baselen); xml_strcpy(str, NCX_DEF_STARTUP_TXID_FILE); m__free(fname); profile->agt_startup_txid_file = newstr; // pass off memory here } else { foundfile = TRUE; profile->agt_startup_txid_file = fname; // pass off memory here } } /* initialize the starting transaction ID in the config module */ res = agt_cfg_init_transactions(profile->agt_startup_txid_file, foundfile); if (res != NO_ERR) { log_error("\nError: cfg-init transaction ID failed (%s)", get_error_string(res)); } return res; } /* set_initial_transaction_id */
static void func_parse_passthrough(GMarkupParseContext *context, const gchar *passthrough_text, gsize text_len, gpointer user_data, GError **error) { if (!g_str_has_prefix(passthrough_text, "<![CDATA[")) return; const gchar *element = g_markup_parse_context_get_element(context); if (!element) return; const gchar *text = passthrough_text+9; gsize len = text_len-9-3; while (g_ascii_isspace(*text)) { text++; len--; } while (len>0 && g_ascii_isspace(*(text+len-1))) { len--; } if (len==0) return; std::string *pango = ((PwUserData*)user_data)->pango; std::string::size_type &cur_pos = ((PwUserData*)user_data)->cur_pos; if (strcmp(element, "词典音标")==0 || strcmp(element, "CB")==0) { if (!pango->empty()) { *pango+='\n'; cur_pos++; } *pango+="[<span foreground=\"blue\">"; cur_pos++; gchar *str = toUtfPhonetic(text, len); *pango+=str; cur_pos+=xml_strlen(str); g_free(str); *pango+="</span>]"; cur_pos++; } else if (strcmp(element, "单词原型")==0 || strcmp(element, "YX")==0) { const gchar *oword = ((PwUserData*)user_data)->oword; if (strncmp(oword, text, len)) { if (!pango->empty()) { *pango+='\n'; cur_pos++; } *pango+="<b>"; gchar *str = g_markup_escape_text(text, len); pango->append(str); cur_pos+=xml_strlen(str); g_free(str); *pango+="</b>"; } } else if (strcmp(element, "单词词性")==0 || strcmp(element, "DX")==0) { if (!pango->empty()) { *pango+='\n'; cur_pos++; } *pango+="<i>"; powerword_markup_add_text(text, len, pango, cur_pos, ((PwUserData*)user_data)->links_list); *pango+="</i>"; } else if (strcmp(element, "汉语拼音")==0 || strcmp(element, "PY")==0) { if (!pango->empty()) { *pango+='\n'; cur_pos++; } *pango+="<span foreground=\"blue\" underline=\"single\">"; powerword_markup_add_text(text, len, pango, cur_pos, ((PwUserData*)user_data)->links_list); *pango+="</span>"; } else if (strcmp(element, "例句原型")==0 || strcmp(element, "LY")==0) { if (!pango->empty()) { *pango+='\n'; cur_pos++; } *pango+="<span foreground=\"#008080\">"; powerword_markup_add_text(text, len, pango, cur_pos, ((PwUserData*)user_data)->links_list); *pango+="</span>"; } else if (strcmp(element, "例句解释")==0 || strcmp(element, "LS")==0) { if (!pango->empty()) { *pango+='\n'; cur_pos++; } *pango+="<span foreground=\"#01259A\">"; powerword_markup_add_text(text, len, pango, cur_pos, ((PwUserData*)user_data)->links_list); *pango+="</span>"; /*} else if (strcmp(element, "相关词")==0) { if (!res->empty()) *res+='\n'; std::string tabstr; tabstr+=text[0]; for (gsize i=1;i<len;i++) { if (text[i]=='&') tabstr+="\t&"; else tabstr+=text[i]; } gchar *str = powerword_markup_escape_text(tabstr.c_str(), tabstr.length()); res->append(str); g_free(str);*/ } else /*} else if ( strcmp(element, "解释项")==0 || strcmp(element, "跟随解释")==0 || strcmp(element, "相关词")==0 || strcmp(element, "预解释")==0 || strcmp(element, "繁体写法")==0 || strcmp(element, "台湾音标")==0 || strcmp(element, "图片名称")==0 || strcmp(element, "跟随注释")==0 || strcmp(element, "音节分段")==0 || strcmp(element, "AHD音标")==0 || strcmp(element, "国际音标")==0 || strcmp(element, "美国音标")==0 || strcmp(element, "子解释项")==0 || strcmp(element, "同义词")==0 || strcmp(element, "日文发音")==0 || strcmp(element, "惯用型原型")==0 || strcmp(element, "惯用型解释")==0 || strcmp(element, "另见")==0 ) {*/ { if (!pango->empty()) { *pango+='\n'; cur_pos++; } powerword_markup_add_text(text, len, pango, cur_pos, ((PwUserData*)user_data)->links_list); } }
static void powerword_markup_add_text(const gchar *text, gssize length, std::string *pango, std::string::size_type &cur_pos, LinksPosList *links_list) { const gchar *p; const gchar *end; p = text; end = text + length; GString *str; str = g_string_sized_new (length); const gchar *n; bool find; bool previous_islink = false; std::string marktags; guint currentmarktag = 0; while (p != end) { const gchar *next; next = g_utf8_next_char (p); switch (*p) { case '}': if (currentmarktag==0) { g_string_append (str, "}"); previous_islink = false; } else { currentmarktag--; switch (marktags[currentmarktag]) { case 'b': case 'B': g_string_append (str, "</b>"); previous_islink = false; break; case 'I': g_string_append (str, "</i>"); previous_islink = false; break; case '+': g_string_append (str, "</sup>"); previous_islink = false; break; case '-': g_string_append (str, "</sub>"); previous_islink = false; break; case 'x': g_string_append (str, "</span>"); previous_islink = false; break; case 'l': case 'D': case 'L': case 'U': g_string_append (str, "</span>"); previous_islink = true; break; default: previous_islink = false; break; } } break; case '&': find = false; if (next!=end) { n = g_utf8_next_char(next); if (n!=end && *n == '{') { find=true; currentmarktag++; if (marktags.length()<currentmarktag) marktags+=*next; else marktags[currentmarktag-1]=*next; switch (*next) { case 'b': case 'B': g_string_append (str, "<b>"); next = n+1; break; case 'I': g_string_append (str, "<i>"); next = n+1; break; case '+': g_string_append (str, "<sup>"); next = n+1; break; case '-': g_string_append (str, "<sub>"); next = n+1; break; case 'x': g_string_append (str, "<span foreground=\"blue\" underline=\"single\">"); next = n+1; break; case 'X': case '2': { const gchar *tag_end = n+1; while (tag_end!=end) { if (*tag_end=='}') break; else tag_end++; } g_string_append (str, "<span foreground=\"blue\">"); gchar *tag_str; if (*next == 'X') { tag_str = toUtfPhonetic(n+1, tag_end - (n+1)); } else { tag_str = toUtfPhonetic2(n+1, tag_end - (n+1)); } g_string_append (str, tag_str); g_free(tag_str); g_string_append (str, "</span>"); currentmarktag--; if (tag_end!=end) next = tag_end+1; else next = end; previous_islink = false; break; } case 'l': case 'D': case 'L': case 'U': if (previous_islink) g_string_append (str, "\t"); if (*next == 'l' || *next == 'D') g_string_append (str, "<span foreground=\"blue\" underline=\"single\">"); else g_string_append (str, "<span foreground=\"#008080\" underline=\"single\">"); *pango += str->str; cur_pos += xml_strlen(str->str); g_string_erase(str, 0, -1); { const gchar *tag_end = n+1; while (tag_end!=end) { if (*tag_end=='}') break; else tag_end++; } char *tmpstr = g_markup_escape_text(n+1, tag_end - (n+1)); size_t xml_len = xml_strlen(tmpstr); std::string link("query://"); link.append(n+1, tag_end - (n+1)); links_list->push_back(LinkDesc(cur_pos, xml_len, link)); *pango += tmpstr; cur_pos += xml_len; g_free(tmpstr); g_string_append (str, "</span>"); currentmarktag--; if (tag_end!=end) next = tag_end+1; else next = end; previous_islink = true; break; } /*case ' ': case '9': case 'S':*/ default: next = n+1; break; } } } if (!find) { previous_islink = false; g_string_append (str, "&"); } break; case '<': previous_islink = false; g_string_append (str, "<"); break; case '>': previous_islink = false; g_string_append (str, ">"); break; case '\'': previous_islink = false; g_string_append (str, "'"); break; case '"': previous_islink = false; g_string_append (str, """); break; default: previous_islink = false; g_string_append_len (str, p, next - p); break; } p = next; } if (currentmarktag>0) { do { currentmarktag--; switch (marktags[currentmarktag]) { case 'b': case 'B': g_string_append (str, "</b>"); break; case 'I': g_string_append (str, "</i>"); break; case '+': g_string_append (str, "</sup>"); break; case '-': g_string_append (str, "</sub>"); break; case 'x': case 'l': case 'D': case 'L': case 'U': g_string_append (str, "</span>"); break; default: break; } } while (currentmarktag>0); } *pango += str->str; cur_pos += xml_strlen(str->str); g_string_free (str, TRUE); }
/******************************************************************** * FUNCTION xml_msg_gen_new_prefix * * Generate a new namespace prefix * * INPUTS: * msg == message to search and generate a prefix for * nsid == namespace ID to generate prefix for * retbuff == address of return buffer * buffsize == buffer size * OUTPUTS: * if *retbuff is NULL it will be created * else *retbuff is filled in with the new prefix if NO_ERR * * RETURNS: * status *********************************************************************/ status_t xml_msg_gen_new_prefix (xml_msg_hdr_t *msg, xmlns_id_t nsid, xmlChar **retbuff, uint32 buffsize) { const xmlChar *defpfix; xmlChar startch; int32 nlen, i; xmlChar numbuff[NCX_MAX_NUMLEN], *buff; xmlns_id_t testid; #ifdef DEBUG if (!msg || !retbuff) { return SET_ERROR(ERR_INTERNAL_PTR); } #endif if (*retbuff) { buff = *retbuff; } else { buff = m__getMem(NCX_MAX_NUMLEN+1); if (!buff) { return ERR_INTERNAL_MEM; } else { buffsize = NCX_MAX_NUMLEN+1; *retbuff = buff; } } /* first see if a default prefix was registered with the namespace * and use it if not already in the prefix map */ defpfix = xmlns_get_ns_prefix(nsid); if (defpfix && *defpfix) { testid = find_prefix_val(msg, defpfix); if (testid == 0 || testid==nsid) { if (xml_strlen(defpfix) < buffsize) { xml_strcpy(buff, defpfix); return NO_ERR; } else { return ERR_BUFF_OVFL; } } } /* default already in use for something else so generate a prefix */ nlen = snprintf((char *)numbuff, NCX_MAX_NUMLEN, "%u", (uint32)nsid); if (nlen < 0) { return ERR_NCX_INVALID_NUM; } if ((uint32)(nlen+2) >= buffsize) { return ERR_BUFF_OVFL; } /* copy the number to the prefix buffer w/ trailing zero */ for (i=0; i<=nlen; i++) { buff[i+1] = numbuff[i]; } /* set the start letter in the prefix buffer */ startch = 'n'; /* try to generate a unique prefix */ for (i=0; i<=MAX_PREFIX_TRIES; i++) { /* adjust the label value */ buff[0] = startch++; if (startch > 'z') { startch = 'a'; } /* check if the prefix is in use */ if (!find_prefix_val(msg, buff)) { return NO_ERR; } } return ERR_NCX_OPERATION_FAILED; } /* xml_msg_gen_new_prefix */
/******************************************************************** * FUNCTION load_aliases * * Load the aliases from the specified filespec * * INPUT: * fspec == input filespec to use (NULL == default) * file_error == TRUE if the file must be found * FALSE if finding the default file and it * is not required to be present * RETURNS: * status *********************************************************************/ status_t load_aliases (const xmlChar *fspec, boolean file_error) { FILE *fp; xmlChar *fullspec, *buffer; status_t res = NO_ERR; buffer = m__getMem(NCX_MAX_LINELEN+1); if (buffer == NULL) { log_error("\nError: malloc failed\n"); return ERR_INTERNAL_MEM; } if (fspec == NULL) { fspec = get_aliases_file(); } fullspec = ncx_get_source(fspec, &res); if (res == NO_ERR && fullspec) { fp = fopen((const char *)fullspec, "r"); if (fp) { #define MAX_ALIAS_ERRORS 5 boolean done = FALSE; uint32 errorcnt = 0; while (!done) { char *retstr = fgets((char *)buffer, NCX_MAX_LINELEN+1, fp); if (retstr) { uint32 len = xml_strlen(buffer); if (len) { if (*buffer != '#' && *buffer != '\n') { if (buffer[len-1] == '\n') { buffer[len-1] = 0; } res = handle_alias_parm(buffer, TRUE, FALSE); if (res != NO_ERR) { if (++errorcnt == MAX_ALIAS_ERRORS) { log_error("\nError: skipping aliases; " "too many errors\n"); done = TRUE; } } } // else skip a newline or comment line } // else skip empty line } else { done = TRUE; } } fclose(fp); /* Save mtime of this aliases file */ res = update_def_yangcli_file_mtime (ALIASES_FILE, fullspec); } else if (file_error) { log_error("\nError: Aliases file '%s' could not be opened\n", fullspec); res = ERR_FIL_OPEN; } else if (LOGDEBUG) { log_debug("\nAliases file '%s' could not be opened\n", fullspec); } } else { log_error("\nError: Expand source '%s' failed (%s)", fspec, get_error_string(res)); } if (fullspec) { m__free(fullspec); } if (buffer) { m__free(buffer); } return res; } /* load_aliases */
/******************************************************************** * FUNCTION expand_alias * * Check if the first token is an alias name * If so, construct a new command line with the alias contents * * INPUT: * line == command line to check and possibly convert * res == address of return status * * OUTPUTS: * *res == return status (ERR_NCX_SKIPPED if nothing done) * * RETURNS: * pointer to malloced command string if *res==NO_ERR * NULL if *res==ERR_NCX_SKIPPED or some real error *********************************************************************/ xmlChar * expand_alias (xmlChar *line, status_t *res) { xmlChar *start, *p = line, *newline; alias_cb_t *alias; uint32 namelen, newlen; boolean done = FALSE; /* skip any leading whitespace; not expected from yangcli */ while (*p && xml_isspace(*p)) { p++; } if (*p == 0) { *res = ERR_NCX_SKIPPED; return NULL; } /* look for end of name */ start = p; if (!ncx_valid_fname_ch(*p++)) { *res = ERR_NCX_SKIPPED; return NULL; } while (*p && !done) { if (xml_isspace(*p)) { done = TRUE; } else if (!ncx_valid_name_ch(*p)) { *res = ERR_NCX_SKIPPED; return NULL; } else { p++; } } /* look for the alias */ namelen = (uint32)(p - start); alias = find_alias(start, namelen); if (alias == NULL) { *res = ERR_NCX_SKIPPED; return NULL; } /* replace the alias name with its contents and make a new string */ if (alias->value) { newlen = xml_strlen(p) + xml_strlen(alias->value); } else { newlen = xml_strlen(p); } newline = m__getMem(newlen + 1); if (newline == NULL) { *res = ERR_INTERNAL_MEM; return NULL; } start = newline; if (alias->value) { start += xml_strcpy(start, alias->value); } xml_strcpy(start, p); if (LOGDEBUG2) { log_debug2("\nExpanded alias '%s'; new line: '%s'", alias->name, newline); } *res = NO_ERR; return newline; } /* expand_alias */
/******************************************************************** * FUNCTION consume_node * * Internal consume XML node function * see agt_xml_consume_node for details. * * EXTRA INPUTS: * eoferr == TRUE if an End of File error should be generated * == FALSE if not * nserr == TRUE if bad namespace should be checked * == FALSE if not * clean == TRUE is a string should be cleaned before returned * == FALSE if a string node should be returned as-is * * RETURNS: * status of the operation * Try to fail on fatal errors only *********************************************************************/ static status_t consume_node (ses_cb_t *scb, boolean advance, xml_node_t *node, ncx_layer_t layer, xml_msg_hdr_t *msghdr, boolean eoferr, boolean nserr, boolean clean) { int ret, nodetyp; const xmlChar *badns; xmlChar *valstr, *namestr; uint32 len; status_t res, res2; boolean done; /* init local vars */ done = FALSE; res = NO_ERR; res2 = NO_ERR; badns = NULL; /* loop past any unused xmlTextReader node types */ while (!done) { /* check if a new node should be read */ if (advance) { /* advance the node pointer */ ret = xmlTextReaderRead(scb->reader); if (ret != 1) { /* do not treat this as an internal error */ res = ERR_XML_READER_EOF; if (msghdr && eoferr) { /* generate an operation-failed error */ agt_record_error(scb, msghdr, layer, res, NULL, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } return res; } } /* get the node depth to match the end node correctly */ node->depth = xmlTextReaderDepth(scb->reader); if (node->depth == -1) { /* this never actaully happens */ SET_ERROR(ERR_XML_READER_INTERNAL); node->depth = 0; } /* get the internal nodetype, check it and convert it */ nodetyp = xmlTextReaderNodeType(scb->reader); switch (nodetyp) { case XML_ELEMENT_NODE: /* classify element as empty or start */ if (xmlTextReaderIsEmptyElement(scb->reader)) { node->nodetyp = XML_NT_EMPTY; } else { node->nodetyp = XML_NT_START; } done = TRUE; break; case XML_ELEMENT_DECL: node->nodetyp = XML_NT_END; done = TRUE; break; case XML_TEXT_NODE: /* case XML_DTD_NODE: */ node->nodetyp = XML_NT_STRING; done = TRUE; break; default: /* unused node type -- keep trying */ if (LOGDEBUG3) { log_debug3("\nxml_consume_node: skip unused node (%s)", xml_get_node_name(nodetyp)); } advance = TRUE; } } /* finish the node, depending on its type */ switch (node->nodetyp) { case XML_NT_START: case XML_NT_END: case XML_NT_EMPTY: /* get the element QName */ namestr = xml_strdup(xmlTextReaderConstName(scb->reader)); if (!namestr) { res = ERR_INTERNAL_MEM; } else { node->qname = namestr; /* check for namespace prefix in the name * only error returned is unknown-namespace */ len = 0; res = xml_check_ns(scb->reader, namestr, &node->nsid, &len, &badns); if (!nserr && res != NO_ERR) { node->nsid = xmlns_inv_id(); len = 0; res = NO_ERR; } /* set the element name to the char after the prefix, if any */ node->elname = (const xmlChar *)(namestr+len); /* get all the attributes, except for XML_NT_END */ if (res == NO_ERR && node->nodetyp != XML_NT_END) { res2 = get_all_attrs(scb, node, &node->attrs, layer, msghdr, nserr); } /* Set the node module */ if (res == NO_ERR) { if (node->nsid) { node->module = xmlns_get_module(node->nsid); } else { /* no entry, use the default module (ncx) */ node->module = NCX_DEF_MODULE; } } } break; case XML_NT_STRING: /* get the text value -- this is a malloced string */ node->simval = NULL; valstr = xmlTextReaderValue(scb->reader); if (valstr) { if (clean) { node->simfree = xml_copy_clean_string(valstr); } else { node->simfree = xml_strdup(valstr); } if (node->simfree) { node->simlen = xml_strlen(node->simfree); node->simval = (const xmlChar *)node->simfree; } /* see if this is a QName string; if so save the NSID */ xml_check_qname_content(scb->reader, node); xmlFree(valstr); } if (!node->simval) { /* prevent a NULL ptr reference */ node->simval = EMPTY_STRING; node->simlen = 0; node->simfree = NULL; } break; default: break; } if ((res != NO_ERR) && msghdr) { if (badns) { /* generate an operation-failed error */ agt_record_error(scb, msghdr, layer, res, node, NCX_NT_STRING, badns, NCX_NT_NONE, NULL); } else { agt_record_error(scb, msghdr, layer, res, node, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } } if (LOGDEBUG4) { log_debug4("\nxml_consume_node: return (%d)", (res==NO_ERR) ? res2 : res); if (scb->state != SES_ST_INIT) { xml_dump_node(node); } } /* return general error first, then attribute error * It doesn't really matter since the caller will * assume all error reports have been queued upon return */ return (res==NO_ERR) ? res2 : res; } /* consume_node */