/******************************************************************** * FUNCTION write_cur_token * * Write the full value of the current token to the session * * INPUTS: * scb == session control block * pcb == YANG parser control block * elem == TRUE if this is element content; FALSE if attribute *********************************************************************/ static void write_cur_token (ses_cb_t *scb, yang_pcb_t *pcb, boolean elem) { const xmlChar *prefix, *value; prefix = TK_CUR_MOD(pcb->tkc); if (prefix != NULL) { if (elem) { ses_putcstr(scb, prefix, -1); } else { ses_putastr(scb, prefix, -1); } ses_putchar(scb, ':'); } value = TK_CUR_VAL(pcb->tkc); if (value != NULL) { if (elem) { ses_putcstr(scb, value, -1); } else { ses_putastr(scb, value, -1); } } } /* write_cur_token */
/******************************************************************** * FUNCTION write_yin_stmt * * Go through the token chain and write YIN stmts * recursively if needed, until 1 YANG stmt is handled * * INPUTS: * pcb == parser control block of module to convert * This is returned from ncxmod_load_module_ex * cp == conversion parms to use * scb == session control block for writing output * startindent == start indent count * done == address of done return var to use * * RETURNS: * status *********************************************************************/ static status_t write_yin_stmt (yang_pcb_t *pcb, const yangdump_cvtparms_t *cp, ses_cb_t *scb, int32 startindent, boolean *done) { const yin_mapping_t *mapping; ncx_import_t *import; ext_template_t *extension; const xmlChar *prefix, *modprefix; status_t res; boolean loopdone; res = NO_ERR; *done = FALSE; /* expecting a keyword [string] stmt-end sequence * or the very last closing right brace */ if (TK_CUR_TYP(pcb->tkc) == TK_TT_RBRACE) { if (tk_next_typ(pcb->tkc) == TK_TT_NONE) { *done = TRUE; return NO_ERR; } else { return ERR_NCX_WRONG_TKTYPE; } } else if (!TK_CUR_ID(pcb->tkc)) { return ERR_NCX_WRONG_TKTYPE; } /* check the keyword type */ switch (TK_CUR_TYP(pcb->tkc)) { case TK_TT_TSTRING: /* YANG keyword */ mapping = yin_find_mapping(TK_CUR_VAL(pcb->tkc)); if (mapping == NULL) { return ERR_NCX_DEF_NOT_FOUND; } /* output keyword part */ start_yin_elem(scb, mapping->keyword, startindent); /* output [string] part if expected */ if (mapping->argname == NULL) { if (tk_next_typ(pcb->tkc) == TK_TT_LBRACE) { ses_putchar(scb, '>'); } } else { /* move token pointer to the argument string */ res = advance_token(pcb); if (res != NO_ERR) { return res; } /* write the string part * do not add any extra whiespace to the XML string */ if (mapping->elem) { ses_putchar(scb, '>'); /* encode argname,value as an element */ start_yin_elem(scb, mapping->argname, startindent + cp->indent); ses_putchar(scb, '>'); write_cur_token(scb, pcb, TRUE); end_yin_elem(scb, mapping->argname, -1); } else { /* encode argname,value as an attribute */ ses_putchar(scb, ' '); ses_putstr(scb, mapping->argname); ses_putchar(scb, '='); ses_putchar(scb, '"'); write_cur_token(scb, pcb, FALSE); ses_putchar(scb, '"'); if (tk_next_typ(pcb->tkc) != TK_TT_SEMICOL) { ses_putchar(scb, '>'); } /* else end with empty element */ } } /* move token pointer to the stmt-end char */ res = advance_token(pcb); if (res != NO_ERR) { return res; } switch (TK_CUR_TYP(pcb->tkc)) { case TK_TT_SEMICOL: /* advance to next stmt, this one is done */ res = advance_token(pcb); if (res != NO_ERR) { return res; } if (mapping->elem) { /* end the complex element */ end_yin_elem(scb, mapping->keyword, startindent); } else { /* end the empty element */ ses_putstr(scb, (const xmlChar *)" />"); } break; case TK_TT_LBRACE: /* advance to next sub-stmt, this one has child nodes */ res = advance_token(pcb); if (res != NO_ERR) { return res; } /* write the nested sub-stmts as child nodes */ if (TK_CUR_TYP(pcb->tkc) != TK_TT_RBRACE) { loopdone = FALSE; while (!loopdone) { res = write_yin_stmt(pcb, cp, scb, startindent + cp->indent, done); if (res != NO_ERR) { return res; } if (TK_CUR_TYP(pcb->tkc) == TK_TT_RBRACE) { loopdone = TRUE; } } } /* move to next stmt, this one is done */ res = advance_token(pcb); if (res != NO_ERR) { return res; } /* end the complex element */ end_yin_elem(scb, mapping->keyword, startindent); break; default: return SET_ERROR(ERR_INTERNAL_VAL); } break; case TK_TT_MSTRING: /* extension keyword */ prefix = TK_CUR_MOD(pcb->tkc); modprefix = ncx_get_mod_prefix(pcb->top); if (modprefix != NULL && !xml_strcmp(prefix, modprefix)) { /* local module */ extension = ext_find_extension(pcb->top, TK_CUR_VAL(pcb->tkc)); } else { import = ncx_find_pre_import(pcb->top, prefix); if (import == NULL || import->mod == NULL) { return ERR_NCX_IMP_NOT_FOUND; } extension = ext_find_extension(import->mod, TK_CUR_VAL(pcb->tkc)); } if (extension == NULL) { return ERR_NCX_DEF_NOT_FOUND; } /* got the extension for this external keyword * output keyword part */ start_ext_elem(scb, prefix, TK_CUR_VAL(pcb->tkc), startindent); /* output [string] part if expected */ if (extension->arg == NULL) { if (tk_next_typ(pcb->tkc) == TK_TT_LBRACE) { ses_putchar(scb, '>'); } } else { /* move token pointer to the argument string */ res = advance_token(pcb); if (res != NO_ERR) { return res; } /* write the string part * do not add any extra whiespace chars to the string */ if (extension->argel) { ses_putchar(scb, '>'); /* encode argname,value as an element */ start_ext_elem(scb, prefix, extension->arg, startindent + cp->indent); ses_putchar(scb, '>'); write_cur_token(scb, pcb, TRUE); end_ext_elem(scb, prefix, extension->arg, -1); } else { /* encode argname,value as an attribute */ ses_putchar(scb, ' '); ses_putstr(scb, extension->arg); ses_putchar(scb, '='); ses_putchar(scb, '"'); write_cur_token(scb, pcb, FALSE); ses_putchar(scb, '"'); if (tk_next_typ(pcb->tkc) != TK_TT_SEMICOL) { ses_putchar(scb, '>'); } /* else end with empty element */ } } /* move token pointer to the stmt-end char */ res = advance_token(pcb); if (res != NO_ERR) { return res; } switch (TK_CUR_TYP(pcb->tkc)) { case TK_TT_SEMICOL: /* advance to next stmt, this one is done */ res = advance_token(pcb); if (res != NO_ERR) { return res; } if (extension->arg != NULL && extension->argel) { /* end the complex element */ end_ext_elem(scb, prefix, extension->name, startindent); } else { /* end the empty element */ ses_putstr(scb, (const xmlChar *)" />"); } break; case TK_TT_LBRACE: /* advance to next sub-stmt, this one has child nodes */ res = advance_token(pcb); if (res != NO_ERR) { return res; } /* write the nested sub-stmts as child nodes */ if (TK_CUR_TYP(pcb->tkc) != TK_TT_RBRACE) { loopdone = FALSE; while (!loopdone) { res = write_yin_stmt(pcb, cp, scb, startindent + cp->indent, done); if (res != NO_ERR) { return res; } if (TK_CUR_TYP(pcb->tkc) == TK_TT_RBRACE) { loopdone = TRUE; } } } /* move to next stmt, this one is done */ res = advance_token(pcb); if (res != NO_ERR) { return res; } /* end the complex element */ end_ext_elem(scb, prefix, extension->name, startindent); break; default: return SET_ERROR(ERR_INTERNAL_VAL); } break; default: return SET_ERROR(ERR_INTERNAL_VAL); } return res; } /* write_yin_stmt */
/******************************************************************** * FUNCTION parse_parm * * Parse, and fill one val_value_t struct during * processing of a parmset * * Error messages are printed by this function!! * Do not duplicate error messages upon error return * * * INPUTS: * tkc == token chain * val == container val to fill in * keepvals == TRUE to save existing parms in 'ps', as needed * FALSE to overwrite old parms in 'ps', as needed * * RETURNS: * status of the operation *********************************************************************/ static status_t parse_parm (tk_chain_t *tkc, val_value_t *val, boolean keepvals) { obj_template_t *obj; const xmlChar *modname; val_value_t *curparm, *newparm; status_t res; ncx_iqual_t iqual; boolean match, usewarning, isdefault; /* get the next token, which must be a TSTRING * representing the parameter name */ if (TK_CUR_TYP(tkc) != TK_TT_TSTRING) { res = ERR_NCX_WRONG_TKTYPE; ncx_conf_exp_err(tkc, res, "parameter name"); return res; } curparm = NULL; usewarning = ncx_warning_enabled(ERR_NCX_CONF_PARM_EXISTS); /* check if this TSTRING is a parameter in this parmset * make sure to always check for prefix:identifier * This is automatically processed in tk.c */ if (TK_CUR_MOD(tkc)) { modname = xmlns_get_module (xmlns_find_ns_by_prefix(TK_CUR_MOD(tkc))); if (modname) { curparm = val_find_child(val, modname, TK_CUR_VAL(tkc)); } } else { curparm = val_find_child(val, val_get_mod_name(val), TK_CUR_VAL(tkc)); } if (curparm) { obj = curparm->obj; } else { obj = obj_find_child(val->obj, TK_CUR_MOD(tkc), TK_CUR_VAL(tkc)); } if (!obj) { res = ERR_NCX_UNKNOWN_PARM; if (TK_CUR_MOD(tkc)) { log_error("\nError: parameter '%s:%s' not found", TK_CUR_MOD(tkc), TK_CUR_VAL(tkc)); } else { log_error("\nError: parameter '%s' not found", TK_CUR_VAL(tkc)); } ncx_conf_exp_err(tkc, res, "parameter name"); return res; } /* got a valid parameter name, now create a new parm * even if it may not be kept. There are corner-cases * that require the new value be parsed before knowing * if a parm value is a duplicate or not */ newparm = val_new_value(); if (!newparm) { res = ERR_INTERNAL_MEM; ncx_print_errormsg(tkc, NULL, res); return res; } val_init_from_template(newparm, obj); /* parse the parameter value */ res = parse_val(tkc, obj, newparm); if (res != NO_ERR) { val_free_value(newparm); return res; } /* check if a potential current value exists, or just * add the newparm to the parmset */ if (curparm) { isdefault = val_set_by_default(curparm); iqual = obj_get_iqualval(obj); if (iqual == NCX_IQUAL_ONE || iqual == NCX_IQUAL_OPT) { /* only one allowed, check really a match */ match = TRUE; if (val_has_index(curparm) && !val_index_match(newparm, curparm)) { match = FALSE; } if (!match) { val_add_child(newparm, val); } else if (isdefault) { dlq_remove(curparm); val_free_value(curparm); val_add_child(newparm, val); } else if (keepvals) { if (usewarning) { /* keep current value and toss new value */ log_warn("\nWarning: Parameter '%s' already exists. " "Not using new value\n", curparm->name); if (LOGDEBUG2) { val_dump_value(newparm, NCX_DEF_INDENT); log_debug2("\n"); } } val_free_value(newparm); } else { if (usewarning) { /* replace current value and warn old value tossed */ log_warn("\nconf: Parameter '%s' already exists. " "Overwriting with new value\n", curparm->name); if (LOGDEBUG2) { val_dump_value(newparm, NCX_DEF_INDENT); log_debug2("\n"); } } dlq_remove(curparm); val_free_value(curparm); val_add_child(newparm, val); } } else { /* mutliple instances allowed */ val_add_child(newparm, val); } } else { val_add_child(newparm, val); } return NO_ERR; } /* parse_parm */
/******************************************************************** * FUNCTION parse_val * * Parse, and fill one val_value_t struct during * processing of a text config file * * Error messages are printed by this function!! * Do not duplicate error messages upon error return * * The value name is the current token. * Based on the value typdef, the res of the tokens * comprising the value statement will be processed * * INPUTS: * tkc == token chain * obj == the object template struct to use for filling in 'val' * val == initialized value struct, without any value, * which will be filled in by this function * nsid == namespace ID to use for this value * valname == name of the value struct * * RETURNS: * status of the operation *********************************************************************/ static status_t parse_val (tk_chain_t *tkc, obj_template_t *obj, val_value_t *val) { obj_template_t *chobj; val_value_t *chval; const xmlChar *valname, *useval; typ_def_t *typdef; status_t res; ncx_btype_t btyp; boolean done; xmlns_id_t nsid; btyp = obj_get_basetype(obj); nsid = obj_get_nsid(obj); valname = obj_get_name(obj); typdef = obj_get_typdef(obj); /* check if there is an index clause expected */ if (typ_has_index(btyp)) { res = parse_index(tkc, obj, val, nsid); if (res != NO_ERR) { return res; } } /* get next token, NEWLINE is significant at this point */ res = adv_tk(tkc); if (res != NO_ERR) { return res; } /* the current token should be the value for a leaf * or a left brace for the start of a complex type * A NEWLINE is treated as if the user entered a * zero-length string for the value. (Unless the * base type is NCX_BT_EMPTY, in which case the NEWLINE * is the expected token */ if (typ_is_simple(btyp)) { /* form for a leaf is: foo [value] NEWLINE */ if (TK_CUR_TYP(tkc)==TK_TT_NEWLINE) { useval = NULL; } else { useval = TK_CUR_VAL(tkc); } res = val_set_simval(val, typdef, nsid, valname, useval); if (res != NO_ERR) { log_error("\nError: '%s' cannot be set to '%s'", valname, (TK_CUR_VAL(tkc)) ? TK_CUR_VAL(tkc) : EMPTY_STRING); if (btyp == NCX_BT_EMPTY) { ncx_conf_exp_err(tkc, res, "empty"); } else { ncx_conf_exp_err(tkc, res, "simple value string"); } return res; } /* get a NEWLINE unless current token is already a NEWLINE */ if (TK_CUR_TYP(tkc) != TK_TT_NEWLINE) { res = adv_tk(tkc); if (res != NO_ERR) { return res; } if (TK_CUR_TYP(tkc) != TK_TT_NEWLINE) { res = ERR_NCX_WRONG_TKTYPE; ncx_conf_exp_err(tkc, res, "\\n"); } } } else { /* complex type is foo { ... } or * foo index1 index2 { ... } * If there is an index, it was already parsed */ res = consume_tk(tkc, TK_TT_LBRACE); if (res != NO_ERR) { ncx_conf_exp_err(tkc, res, "left brace"); return res; } /* get all the child nodes specified for this complex type */ res = NO_ERR; done = FALSE; while (!done && res==NO_ERR) { /* start out looking for a child node name or a * right brace to end the sub-section */ if (tk_next_typ(tkc)==TK_TT_NEWLINE) { /* skip the NEWLINE token */ (void)adv_tk(tkc); } else if (tk_next_typ(tkc)==TK_TT_RBRACE) { /* found end of sub-section */ done = TRUE; } else { /* get the next token */ res = adv_tk(tkc); if (res != NO_ERR) { continue; } /* make sure cur token is an identifier string * if so, find the child node and call this function * recursively to fill it in and add it to * the parent 'val' */ if (TK_CUR_ID(tkc)) { /* parent 'typdef' must have a child with a name * that matches the current token vale */ chobj = obj_find_child(obj, TK_CUR_MOD(tkc), TK_CUR_VAL(tkc)); if (chobj) { chval = val_new_value(); if (!chval) { res = ERR_INTERNAL_MEM; ncx_print_errormsg(tkc, NULL, res); } else { val_init_from_template(chval, chobj); res = parse_val(tkc, chobj, chval); if (res == NO_ERR) { val_add_child(chval, val); } else { val_free_value(chval); } } } else { /* string is not a child name in this typdef */ res = ERR_NCX_DEF_NOT_FOUND; ncx_conf_exp_err(tkc, res, "identifier string"); } } else { /* token is not an identifier string */ res = ERR_NCX_WRONG_TKTYPE; ncx_conf_exp_err(tkc, res, "identifier string"); } } } /* end loop through all the child nodes */ /* expecting a right brace to finish the complex value */ if (res == NO_ERR) { res = consume_tk(tkc, TK_TT_RBRACE); if (res != NO_ERR) { ncx_conf_exp_err(tkc, res, "right brace"); return res; } } } return res; } /* parse_val */