Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Recursive UBF API
0003  *
0004  * @file recursive.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 
0035 /*---------------------------Includes-----------------------------------*/
0036 #include <string.h>
0037 #include <stdio.h>
0038 #include <stdlib.h>
0039 #include <memory.h>
0040 
0041 #include <ubf.h>
0042 #include <ubf_int.h>    /* Internal headers for UBF... */
0043 #include <fdatatype.h>
0044 #include <ferror.h>
0045 #include <fieldtable.h>
0046 #include <ndrstandard.h>
0047 #include <ndebug.h>
0048 #include <cf.h>
0049 
0050 #include "xatmi.h"
0051 /*---------------------------Externs------------------------------------*/
0052 /*---------------------------Macros-------------------------------------*/
0053 #if BBADFLDOCC<0
0054 #define R_IS_NEXT_EOS(X) (BBADFLDOCC==*(X) || BBADFLDOCC==*(X+1) || BBADFLDOCC==*(X+2))
0055 #else
0056 #define R_IS_NEXT_EOS(X) (BBADFLDOCC==*(X) || BBADFLDOCC==*(X+2))
0057 #endif
0058 
0059 #define DEBUG_STR_MAX   512 /**< Max debug string len                   */
0060 
0061 #define VIEW_FLD_FOUND  1
0062 #define VIEW_FLD_CNAME_PARSED  2
0063 
0064 #define STATE_NONE  1
0065 #define STATE_OCC  2
0066 #define STATE_OCCANY  3
0067 #define STATE_VIEW  4
0068 
0069 #define IS_VALID_ID(X)  ( X>='a' && X<='z' || X>='0' && X<='9' || X>='A' && X<='Z' || X=='_')
0070 #define IS_VALID_NUM(X)  ( X>='0' && X<='9' )
0071 
0072 #define RESOLVE_FIELD   \
0073 if (0==j)\
0074 {\
0075     UBF_LOG(log_error, "Missing field name at position %d", i);\
0076     ndrx_Bset_error_fmt(BSYNTAX, "Missing field name at position %d", i);\
0077     EXFAIL_OUT(ret);\
0078 }\
0079 tmp[j]=EXEOS;\
0080 if (is_view)\
0081 {\
0082     if (VIEW_FLD_CNAME_PARSED==is_view)\
0083     {\
0084         UBF_LOG(log_error, "Sub-fields of view sub-field are not allowed at position %d", i);\
0085         ndrx_Bset_error_fmt(BEBADOP, "Sub-fields of view sub-field are not allowed at position %d", i);\
0086         EXFAIL_OUT(ret);\
0087     }\
0088     rfldid->cname=NDRX_STRDUP(tmp);\
0089     if (NULL==rfldid->cname)\
0090     {\
0091         int err;\
0092         err=errno;\
0093         UBF_LOG(log_error, "Failed to malloc: %s", strerror(errno));\
0094         ndrx_Bset_error_fmt(BEUNIX, "Failed to malloc: %s", strerror(errno));\
0095         EXFAIL_OUT(ret);\
0096     }\
0097     is_view=VIEW_FLD_CNAME_PARSED;\
0098     UBF_LOG(log_debug, "Parsed view field [%s] is_view=%d", rfldid->cname, is_view);\
0099 }\
0100 else \
0101 {\
0102     if (BBADFLDID==(parsedid=Bfldid (tmp)))\
0103     {\
0104         UBF_LOG(log_error, "Failed to resolve [%s] nrfld=%d", tmp, nrflds);\
0105         EXFAIL_OUT(ret);\
0106     }\
0107     if (BFLD_VIEW==Bfldtype(parsedid))\
0108     {\
0109         is_view=VIEW_FLD_FOUND;\
0110     } /* cache last field */\
0111     UBF_LOG(log_debug, "Resolved field [%s] to [%d] is_view=%d", tmp, parsedid, is_view);\
0112     rfldid->bfldid=parsedid;\
0113 }\
0114 j=0;\
0115 nrflds++;
0116 
0117 /** 
0118  * Add field to ndrx_ubf_rfldid_t, so lets build full version in any case 
0119  * Also needs to test the case if we parsed the view field, then 
0120  * nothing to add to growlist
0121  */
0122 #define RESOLVE_ADD   if (VIEW_FLD_CNAME_PARSED!=is_view)\
0123 {\
0124     ndrx_growlist_append(&(rfldid->fldidocc), &parsedid);\
0125     ndrx_growlist_append(&(rfldid->fldidocc), &parsedocc);\
0126     rfldid->bfldid=parsedid;\
0127     rfldid->occ=parsedocc;\
0128 }\
0129 else \
0130 {\
0131     rfldid->cname_occ=parsedocc;\
0132 }\
0133 j=0;\
0134 added=EXTRUE;
0135 
0136 /*---------------------------Enums--------------------------------------*/
0137 /*---------------------------Typedefs-----------------------------------*/
0138 /*---------------------------Globals------------------------------------*/
0139 /*---------------------------Statics------------------------------------*/
0140 exprivate int validate_rfield(ndrx_ubf_rfldid_t *rfldid);
0141 
0142 /**
0143  * Free up the rfield parsed data
0144  * @param rfldid recursive field id
0145  */
0146 expublic void ndrx_ubf_rfldid_free(ndrx_ubf_rfldid_t *rfldid)
0147 {
0148     if (NULL!=rfldid->cname)
0149     {
0150         NDRX_FREE(rfldid->cname);
0151         rfldid->cname=NULL;
0152     }
0153     
0154     if (NULL!=rfldid->fldnm)
0155     {
0156         NDRX_FREE(rfldid->fldnm);
0157         rfldid->fldnm=NULL;
0158     }
0159     
0160     ndrx_growlist_free(&(rfldid->fldidocc));
0161 }
0162 
0163 /**
0164  * Check the rfield before adding
0165  * @return EXSUCCEED/EXFAIL
0166  */
0167 exprivate int validate_rfield(ndrx_ubf_rfldid_t *rfldid)
0168 {
0169     int ret = EXSUCCEED;    
0170     BFLDID *grow_fields = (BFLDID *)rfldid->fldidocc.mem;
0171 
0172     /* if we are here, then previous must be BFLD_VIEW or BFLD_UBF (if any)
0173      * other sub-fields are not supported!
0174      */
0175     if (rfldid->fldidocc.maxindexused>-1)
0176     {
0177         /* first is field, and then occ follows, thus check fieldid */
0178         int typ=Bfldtype(grow_fields[rfldid->fldidocc.maxindexused-1]);
0179 
0180         if (BFLD_UBF!=typ && BFLD_VIEW!=typ)
0181         {
0182             ndrx_Bset_error_fmt(BEBADOP, "Subfield only allowed for ubf or view types, "
0183                     "but got type %s at field id position %d",
0184                     G_dtype_str_map[typ].fldname, rfldid->fldidocc.maxindexused);
0185 
0186             UBF_LOG(log_error, "Subfield only allowed for ubf or view types, "
0187                     "but got type %s at field id position %d",
0188                     G_dtype_str_map[typ].fldname, rfldid->fldidocc.maxindexused);
0189             EXFAIL_OUT(ret);
0190         }
0191 
0192     }
0193 out:
0194     return ret;
0195 }
0196 
0197 /**
0198  * Parse the field reference
0199  * TODO: Add check for invalid sub-field -> it must be UBF, otherwise
0200  * give BEBADOP
0201  * @param rfldidstr field reference: fld[occ].fld[occ].fld.fld[occ]
0202  * @param rfldid parsed reference
0203  * @param bfldid leaf field id
0204  * @param occ leaf occurrence
0205  * @return EXFAIL (error), EXSUCCEED (ok)
0206  */
0207 expublic int ndrx_ubf_rfldid_parse(char *rfldidstr, ndrx_ubf_rfldid_t *rfldid)
0208 {
0209     int ret = EXSUCCEED;
0210     int i, j, len, state, prev_state, terminator;
0211     char tmp[PATH_MAX];
0212     BFLDID parsedid=BBADFLDID;
0213     BFLDOCC parsedocc;
0214     int *rfldidseq;
0215     int nrflds=0;
0216     int is_view=EXFALSE;
0217     int added;
0218     BFLDID *grow_fields;
0219     
0220     UBF_LOG(log_debug, "Parsing field id sequence: [%s]", rfldidstr);
0221     ndrx_growlist_init(&(rfldid->fldidocc), 10, sizeof(int));
0222     rfldid->cname = NULL;
0223     rfldid->fldnm = NDRX_STRDUP(rfldidstr);
0224         
0225     if (NULL==rfldid->fldnm)
0226     {
0227         int err = errno;
0228         
0229         ndrx_Bset_error_fmt(BEUNIX, "Failed to malloc rfldidstr: %s", strerror(err));
0230         UBF_LOG(log_error, "Failed to malloc rfldidstr: %s", strerror(err));
0231         EXFAIL_OUT(ret);
0232     }
0233     
0234     len=strlen(rfldidstr);
0235     
0236     if (len>sizeof(tmp)-1)
0237     {
0238         ndrx_Bset_error_fmt(BSYNTAX, "Field id too max len %d max %d: [%s] ",
0239                 len, sizeof(tmp)-1, rfldidstr);
0240         UBF_LOG(log_error, "Field id too max len %d max %d: [%s] ",
0241                 len, sizeof(tmp)-1, rfldidstr);
0242         EXFAIL_OUT(ret);
0243     }
0244     
0245     prev_state=state=STATE_NONE;
0246     j=0;
0247     added=EXFALSE;
0248     for (i=0; i<len+1; i++)
0249     {
0250         if (STATE_NONE==state)
0251         {
0252             /* terminal field comes first... */
0253             if (0x0 ==rfldidstr[i])
0254             {
0255                 if (j>0)
0256                 {
0257                     /* finish field, got 0 occ */
0258                     tmp[j]=EXEOS;
0259                     RESOLVE_FIELD;
0260                     parsedocc=0;
0261                     RESOLVE_ADD;
0262                 }
0263                 
0264                 /* we are done... */
0265                 break;
0266             }
0267             
0268             /* error! sub-fields of view not supported 
0269              * this is some leading field and if added, check the types.
0270              * TODO: might want in future support BFLD_PTR...
0271              */
0272             if (added)
0273             {
0274                 if (VIEW_FLD_CNAME_PARSED==is_view)
0275                 {
0276                     ndrx_Bset_error_fmt(BEBADOP, "Subfield for view-field "
0277                             "not expected: [%s] nrfld=%d pos=%d", 
0278                             rfldidstr, nrflds, i);
0279                     UBF_LOG(log_error, "Subfield for view-field not expected: "
0280                             "[%s] nrfld=%d pos=%d", 
0281                             rfldidstr, nrflds, i);
0282                     EXFAIL_OUT(ret);
0283                 }
0284             
0285                 /* validate that we might have sub-fields at given position. */
0286                 if (EXSUCCEED!=validate_rfield(rfldid))
0287                 {
0288                     EXFAIL_OUT(ret);
0289                 }
0290                 added=EXFALSE;
0291             }
0292             
0293             if (IS_VALID_ID(rfldidstr[i]))
0294             {
0295                 tmp[j]=rfldidstr[i];
0296                 j++;
0297             }
0298             else if ('['==rfldidstr[i])
0299             {
0300                 /* finish field, count occ */
0301                 tmp[j]=EXEOS;
0302                 RESOLVE_FIELD;
0303                 prev_state=state;
0304                 state=STATE_OCC;
0305             }
0306             else if ('.'==rfldidstr[i])
0307             {
0308                 /* finish field, got 0 occ */
0309                 tmp[j]=EXEOS;
0310                 
0311                 /* do not resolve if previous was occurrence */
0312                 if (STATE_OCC!=prev_state && STATE_OCCANY!=prev_state)
0313                 {
0314                     if (EXEOS==tmp[0])
0315                     {
0316                         /* previous was just dot... (..) thus have a syntax
0317                          * error
0318                          */
0319                         ndrx_Bset_error_fmt(BSYNTAX, "Invalid dot notation (..) at %d", i);
0320                         UBF_LOG(log_error, "Invalid dot notation (..) at %d", i);
0321                         EXFAIL_OUT(ret);
0322                     }
0323 
0324                     RESOLVE_FIELD;
0325                     parsedocc=0;
0326                     RESOLVE_ADD;
0327                 }
0328                 else
0329                 {
0330                     /* reset buffer */
0331                     j=0;
0332                     /* reset previous state.. */
0333                     prev_state=state;
0334                 }
0335             }
0336             else
0337             {
0338                 /* error! invalid character expected C identifier, '.', or '[' */
0339                 ndrx_Bset_error_fmt(BSYNTAX, "Invalid character found [%c] in [%s] pos=%d",
0340                         rfldidstr[i], rfldidstr, i);
0341                 UBF_LOG(log_error, "Invalid character found [%c] in [%s] pos=%d",
0342                         rfldidstr[i], rfldidstr, i);
0343                 EXFAIL_OUT(ret);
0344             }
0345         }
0346         else if (STATE_OCC==state)
0347         {
0348             if (IS_VALID_NUM(rfldidstr[i]))
0349             {
0350                 tmp[j]=rfldidstr[i];
0351                 j++;
0352             }
0353             else if ('?'==rfldidstr[i])
0354             {
0355                 
0356                 tmp[j]=rfldidstr[i];
0357                 j++;
0358                 if (j>0)
0359                 {
0360                     tmp[j]=EXEOS;
0361                     ndrx_Bset_error_fmt(BSYNTAX, "Invalid occurrence: [%s] at pos=%d", 
0362                             tmp, i);
0363                     UBF_LOG(log_error, "Invalid occurrence: [%s] at pos=%d", 
0364                             tmp, i);
0365                     EXFAIL_OUT(ret);
0366                 }
0367                 
0368                 parsedocc=-2; /* any occurrence */
0369                 state=STATE_OCCANY;
0370             }
0371             else if (']'==rfldidstr[i])
0372             {
0373                 /* Finish off the field + occ */
0374                 tmp[j]=EXEOS;
0375                 parsedocc=atoi(tmp);
0376                 RESOLVE_ADD;
0377                 prev_state=state;
0378                 state=STATE_NONE;
0379             }
0380             else if (0x0 ==rfldidstr[i])
0381             {
0382                 tmp[j]=rfldidstr[i];
0383                 ndrx_Bset_error_fmt(BSYNTAX, "Unclosed occurrence [%s] at pos=%d", 
0384                         tmp[j], i);
0385                 UBF_LOG(log_error, "Unclosed occurrence [%s] at pos=%d", 
0386                         tmp[j], i);
0387                 EXFAIL_OUT(ret);
0388             }
0389             else
0390             {
0391                 /* error! Invalid character, expected number, '?' or ']' */
0392                 tmp[j]=rfldidstr[i];
0393                 j++;
0394                 tmp[j]=EXEOS;
0395                 ndrx_Bset_error_fmt(BSYNTAX, "Invalid occurrence: [%s] at pos=%d", 
0396                             tmp, i);
0397                 UBF_LOG(log_error, "Invalid occurrence: [%s] at pos=%d", 
0398                         tmp, i);
0399                 EXFAIL_OUT(ret);
0400             }
0401         }
0402         else if (STATE_OCCANY==state)
0403         {
0404             if (']'==rfldidstr[i])
0405             {
0406                 /* Finish off the field + occ, already parsed.. */
0407                 RESOLVE_ADD;
0408                 prev_state=state;
0409                 state=STATE_NONE;
0410             }
0411             else if (0x0 ==rfldidstr[i])
0412             {
0413                 tmp[j]=rfldidstr[i];
0414                 ndrx_Bset_error_fmt(BSYNTAX, "Unclosed occurrence [%s] at pos=%d", 
0415                         tmp[j], i);
0416                 UBF_LOG(log_error, "Unclosed occurrence [%s] at pos=%d", 
0417                         tmp[j], i);
0418                 EXFAIL_OUT(ret);
0419             }
0420             else
0421             {
0422                 /* error! Invalid character, expected [?] */
0423                 tmp[j]=rfldidstr[i];
0424                 tmp[j]=EXEOS;
0425                 ndrx_Bset_error_fmt(BSYNTAX, "Invalid any occurrence: [%s] at pos=%d", 
0426                             tmp, i);
0427                 UBF_LOG(log_error, "Invalid any occurrence: [%s] at pos=%d", 
0428                         tmp, i);
0429                 EXFAIL_OUT(ret);
0430             }
0431         }
0432     }
0433     
0434     /* Terminate the memory sequence... */
0435     
0436     /* Unload the field... */
0437     terminator=BBADFLDOCC;
0438     ndrx_growlist_append(&(rfldid->fldidocc), &terminator);
0439     
0440     rfldidseq=(int *)rfldid->fldidocc.mem;
0441     
0442     /* get the last two identifiers.. */
0443     if (rfldid->fldidocc.maxindexused<2)
0444     {
0445          ndrx_Bset_error_fmt(BSYNTAX, "Empty field name parsed (%d)!",
0446                  rfldid->fldidocc.maxindexused);
0447         UBF_LOG(log_error, "Empty field name parsed (%d)!",
0448                 rfldid->fldidocc.maxindexused);
0449         EXFAIL_OUT(ret);
0450     }
0451     
0452     rfldid->nrflds=nrflds;
0453     
0454     grow_fields = (BFLDID *)rfldid->fldidocc.mem;
0455     /* -1 terminator, -1 occ */
0456     rfldid->bfldid = grow_fields[rfldid->fldidocc.maxindexused-2];
0457     
0458 out:
0459 
0460     /* free up un-needed resources */
0461     if (EXSUCCEED!=ret)
0462     {
0463         ndrx_ubf_rfldid_free(rfldid);
0464     }
0465 
0466     UBF_LOG(log_debug, "returns %d bfldid=%d, occ=%d, nrflds=%d, cname=[%s]", 
0467         ret, rfldid->bfldid, rfldid->occ, nrflds, rfldid->cname?rfldid->cname:"(null)");
0468     return ret;
0469 }
0470 
0471 /**
0472  * Find the buffer for the final FLDID/OCC
0473  * i.e. fld1,occ1,fld2,occ2,fld3,occ3.
0474  * Thus our function is to return the UBF buffer presented by fld2.
0475  * During the search ensure that sub-buffers are UBFs actually
0476  * @param p_ub parent UBF buffer to search for field
0477  * @param fldidocc sequence of fld1,occ1,fld2,occ2,fld3,occ3.
0478  * @param fldid_leaf terminating field e.g. fld3
0479  * @param occ_leaf terminating field e.g. occ3
0480  * @return PTR to UBF buffer found
0481  */
0482 exprivate UBFH * ndrx_ubf_R_find(UBFH *p_ub, BFLDID *fldidocc, 
0483         BFLDID *fldid_leaf, BFLDOCC *occ_leaf, BFLDLEN *len)
0484 {
0485     int ret = EXSUCCEED;
0486     BFLDID bfldid;
0487     BFLDID occ;
0488     int pos=0;
0489     int typ;
0490     
0491     /* lookup ahead do we have EOF */
0492     while (!R_IS_NEXT_EOS(fldidocc))
0493     {
0494         /* first is fld id */
0495         bfldid=*fldidocc;
0496         
0497         if (BBADFLDOCC==*fldidocc)
0498         {
0499             UBF_LOG(log_error, "Invalid recursive field identifier sequence, "
0500                     "expected BFLDID, got BBADFLDOCC(%d) at pos %d", BBADFLDOCC, pos);
0501             ndrx_Bset_error_fmt(BBADFLD, "Invalid recursive field identifier sequence, "
0502                     "expected BFLDID, got BBADFLDOCC(%d) at pos %d", BBADFLDOCC, pos);
0503             p_ub=NULL;
0504             goto out;
0505         }
0506 
0507         /* second is occurrence */
0508         fldidocc++;
0509         pos++;
0510         
0511 /* can check if <0, as >=0 is valid occ */
0512 #if BBADFLDOCC<0
0513         if (BBADFLDOCC==*fldidocc)
0514         {
0515             UBF_LOG(log_error, "Invalid recursive occurrence sequence, "
0516                     "expected occ, got BBADFLDOCC(%d) at pos %d", BBADFLDOCC, pos);
0517             ndrx_Bset_error_fmt(BBADFLD, "Invalid recursive field identifier sequence, "
0518                     "expected occ, got BBADFLDOCC(%d) at pos %d", BBADFLDOCC, pos);
0519             p_ub=NULL;
0520             goto out;
0521         }
0522 #endif
0523 
0524         occ=*fldidocc;
0525         /* find the buffer */
0526         typ = Bfldtype(bfldid);
0527         if (BFLD_UBF!=typ)
0528         {
0529             UBF_LOG(log_error, "Expected BFLD_UBF (%d) at position %d in "
0530                     "sequence but got: %d type", BFLD_UBF, pos, typ);
0531             ndrx_Bset_error_fmt(BEBADOP, "Expected BFLD_UBF (%d) at "
0532                     "position %d in sequence but got: %d type", BFLD_UBF, pos, typ);
0533             p_ub=NULL;
0534             goto out;
0535         }
0536         
0537         p_ub = (UBFH *)ndrx_Bfind(p_ub, bfldid, occ, len, NULL);
0538         
0539         if (NULL==p_ub)
0540         {
0541             UBF_LOG(log_error, "Buffer not found at position of field sequence %d", pos);
0542             p_ub=NULL;
0543             goto out;
0544         }
0545 
0546         /* step to next pair */
0547         fldidocc++;
0548         pos++;
0549         
0550     }
0551     
0552     if (NULL!=p_ub)
0553     {
0554         if(BBADFLDOCC==*fldidocc)
0555         {
0556             UBF_LOG(log_error, "Field ID not present at position %d in sequence (BBADFLDOCC (%d) found)",
0557                     pos, BBADFLDOCC);
0558             ndrx_Bset_error_fmt(BBADFLD, "Field ID not present at position %d in sequence (BBADFLDOCC (%d) found)",
0559                     pos, BBADFLDOCC);
0560             p_ub=NULL;
0561             goto out;
0562         }
0563         
0564         *fldid_leaf=*fldidocc;
0565         
0566         fldidocc++;
0567         pos++;
0568         
0569 #if BBADFLDOCC<0
0570         if (BBADFLDOCC==*fldidocc)
0571         {
0572             UBF_LOG(log_error, "Occurrence not present at position %d in sequence (BBADFLDID (%d) found)",
0573                     pos, BBADFLDOCC);
0574             ndrx_Bset_error_fmt(BBADFLD, "Occurrence not present at position %d in sequence (BBADFLDID (%d) found)",
0575                     pos, BBADFLDOCC);
0576             p_ub=NULL;
0577             goto out;
0578         }
0579 #endif
0580         
0581         *occ_leaf=*fldidocc;    
0582         
0583         
0584         fldidocc++;
0585         pos++;
0586     }
0587     
0588     UBF_LOG(log_debug, "Leaf fldid=%d occ=%d", *fldid_leaf, *occ_leaf);
0589     
0590 out:
0591     
0592     UBF_LOG(log_debug, "Returning status=%d p_ub=%p", ret, p_ub);
0593     
0594     return p_ub;
0595 }
0596 
0597 /**
0598  * Construct the full debug string as the path 
0599  * FIELD1[OCC1].FIELD2[OCC2]
0600  * @param fldidocc
0601  * @param debug_buf
0602  * @param debug_buf_len
0603  * @return 
0604  */
0605 exprivate void ndrx_ubf_sequence_str(BFLDID *fldidocc, 
0606         char *debug_buf, size_t debug_buf_len)
0607 {
0608     int pos=0;
0609     char *nam;
0610     char tmp[128];
0611     int err=Berror;
0612     debug_buf[0]=EXEOS;
0613     
0614     while (BBADFLDOCC!=*fldidocc)
0615     {
0616         /* field id: */
0617         nam=Bfname(*fldidocc);
0618 
0619         if (pos>0)
0620         {
0621             NDRX_STRCAT_S(debug_buf, debug_buf_len, ".");
0622         }
0623 
0624         NDRX_STRCAT_S(debug_buf, debug_buf_len, nam);
0625         
0626         /* step to occ */
0627         fldidocc++;
0628         pos++;
0629         
0630 #if BBADFLDOCC < 0
0631         if (*fldidocc==BBADFLDOCC)
0632         {
0633             break;
0634         }
0635 #endif
0636 
0637         NDRX_STRCAT_S(debug_buf, debug_buf_len, "[");
0638         snprintf(tmp, sizeof(tmp), "%d", *fldidocc);
0639         NDRX_STRCAT_S(debug_buf, debug_buf_len, tmp);
0640         NDRX_STRCAT_S(debug_buf, debug_buf_len, "]");
0641         
0642         /* step to next */
0643         fldidocc++;
0644         pos++;
0645         
0646     }
0647     Berror=err;
0648 }
0649 
0650 /**
0651  * Recursive field field get
0652  * @param p_ub parent UBF buffer
0653  * @param fldidocc array of: <field_id1>,<occ1>,..<field_idN><occN>,BBADFLDOCC
0654  * @param buf buffer where to return the value
0655  * @param len in input buffer len, on output bytes written
0656  * @return EXSUCCEED/EXFAIL
0657  */
0658 expublic int ndrx_Bgetr (UBFH * p_ub, BFLDID *fldidocc,
0659                             char * buf, BFLDLEN * buflen)
0660 {
0661     
0662     int ret = EXSUCCEED;
0663     
0664     BFLDID bfldid;
0665     BFLDOCC occ;
0666     BFLDLEN len_data;
0667     char debugbuf[DEBUG_STR_MAX]="";
0668     
0669     p_ub=ndrx_ubf_R_find(p_ub, fldidocc, &bfldid, &occ, &len_data);
0670     
0671     if (NULL==p_ub)
0672     {
0673         if (debug_get_ubf_level() > log_info)
0674         {
0675             ndrx_ubf_sequence_str(fldidocc, debugbuf, sizeof(debugbuf));
0676             UBF_LOG(log_info, "Field not found, sequence: %s", debugbuf);
0677         }
0678         
0679         EXFAIL_OUT(ret);
0680     }
0681     
0682     ret=Bget(p_ub, bfldid, occ, buf, buflen);
0683     
0684 out:
0685     return ret;
0686 }
0687 
0688 
0689 /**
0690  * Recursive field field get, with convert
0691  * @param p_ub parent UBF buffer
0692  * @param fldidocc array of: <field_id1>,<occ1>,..<field_idN><occN>,BBADFLDOCC
0693  * @param buf buffer where to return the value
0694  * @param len in input buffer len, on output bytes written
0695  * @param usrtype user type to convert data to
0696  * @return EXSUCCEED/EXFAIL
0697  */
0698 expublic int ndrx_CBgetr (UBFH * p_ub, BFLDID *fldidocc,
0699                             char * buf, BFLDLEN * buflen, int usrtype)
0700 {
0701     int ret = EXSUCCEED;
0702     BFLDID bfldid;
0703     BFLDOCC occ;
0704     BFLDLEN len_data;
0705     char debugbuf[DEBUG_STR_MAX]="";
0706     
0707     p_ub=ndrx_ubf_R_find(p_ub, fldidocc, &bfldid, &occ, &len_data);
0708     
0709     if (NULL==p_ub)
0710     {
0711         if (debug_get_ubf_level() > log_info)
0712         {
0713             ndrx_ubf_sequence_str(fldidocc, debugbuf, sizeof(debugbuf));
0714             UBF_LOG(log_info, "Field not found, sequence: %s", debugbuf);
0715         }
0716         
0717         EXFAIL_OUT(ret);
0718     }
0719     
0720     ret=CBget(p_ub, bfldid, occ, buf, buflen, usrtype);
0721     
0722 out:
0723     return ret;
0724 }
0725 
0726 /**
0727  * Recursive get string field and alloc
0728  * @param p_ub parent UBF buffer
0729  * @param fldidocc array of: <field_id1>,<occ1>,..<field_idN><occN>,BBADFLDOCC
0730  * @param usrtype user type to cast to
0731  * @param extralen on input number of bytes to allocate extra
0732  *  on output number of bytes copied to data block
0733  * @return EXSUCCEED/EXFAIL
0734  */
0735 expublic char * ndrx_CBgetallocr (UBFH *p_ub, BFLDID *fldidocc, int usrtype, BFLDLEN *extralen)
0736 {
0737     char *ret = NULL;
0738     BFLDID bfldid;
0739     BFLDOCC occ;
0740     BFLDLEN len_data;
0741     char debugbuf[DEBUG_STR_MAX]="";
0742     
0743     p_ub=ndrx_ubf_R_find(p_ub, fldidocc, &bfldid, &occ, &len_data);
0744     
0745     if (NULL==p_ub)
0746     {
0747         if (debug_get_ubf_level() > log_info)
0748         {
0749             ndrx_ubf_sequence_str(fldidocc, debugbuf, sizeof(debugbuf));
0750             UBF_LOG(log_info, "Field not found, sequence: %s", debugbuf);
0751         }
0752         goto out;
0753     }
0754     
0755     /* read the field and allocate */
0756     ret=CBgetalloc(p_ub, bfldid, occ, usrtype, extralen);
0757     
0758 out:
0759     return ret;
0760 }
0761 
0762 /**
0763  * Recursive find implementation
0764  * @param p_ub root UBF buffer
0765  * @param fldidocc field sequence
0766  * @param p_len data len
0767  * @return ptr to data
0768  */
0769 expublic char* ndrx_Bfindr (UBFH *p_ub, BFLDID *fldidocc, BFLDLEN *p_len)
0770 {
0771     char* ret = NULL;
0772     BFLDID bfldid;
0773     BFLDOCC occ;
0774     BFLDLEN len_data;
0775     char debugbuf[DEBUG_STR_MAX]="";
0776     
0777     p_ub=ndrx_ubf_R_find(p_ub, fldidocc, &bfldid, &occ, &len_data);
0778     
0779     if (NULL==p_ub)
0780     {
0781         if (debug_get_ubf_level() > log_info)
0782         {
0783             ndrx_ubf_sequence_str(fldidocc, debugbuf, sizeof(debugbuf));
0784             UBF_LOG(log_info, "Field not found, sequence: %s", debugbuf);
0785         }
0786         
0787         goto out;
0788     }
0789     
0790     ret=Bfind (p_ub, bfldid, occ, p_len);
0791     
0792 out:
0793     return ret;
0794 }
0795 
0796 /**
0797  * Recursive find implementation
0798  * @param p_ub root UBF buffer
0799  * @param fldidocc field sequence
0800  * @param p_len data len
0801  * @param usrtype user type
0802  * @return ptr to data
0803  */
0804 expublic char* ndrx_CBfindr (UBFH *p_ub, BFLDID *fldidocc, BFLDLEN *p_len, int usrtype)
0805 {
0806     char* ret = NULL;
0807     BFLDID bfldid;
0808     BFLDOCC occ;
0809     BFLDLEN len_data;
0810     char debugbuf[DEBUG_STR_MAX]="";
0811     
0812     p_ub=ndrx_ubf_R_find(p_ub, fldidocc, &bfldid, &occ, &len_data);
0813     
0814     if (NULL==p_ub)
0815     {
0816         if (debug_get_ubf_level() > log_info)
0817         {
0818             ndrx_ubf_sequence_str(fldidocc, debugbuf, sizeof(debugbuf));
0819             UBF_LOG(log_info, "Field not found, sequence: %s", debugbuf);
0820         }
0821         
0822         goto out;
0823     }
0824     
0825     ret=CBfind (p_ub, bfldid, occ, p_len, usrtype);
0826     
0827 out:
0828     return ret;
0829 }
0830 
0831 /**
0832  * Test field presence in recursive fldidocc sequence
0833  * @param p_ub UBF buffer
0834  * @param fldidocc fldid,occ,fldocc,...,BBADFLDID
0835  * @return EXFALSE/EXTRUE
0836  */ 
0837 expublic int ndrx_Bpresr (UBFH *p_ub, BFLDID *fldidocc)
0838 {
0839     char ret = EXSUCCEED;
0840     BFLDID bfldid;
0841     BFLDOCC occ;
0842     BFLDLEN len_data;
0843     char debugbuf[DEBUG_STR_MAX]="";
0844     
0845     p_ub=ndrx_ubf_R_find(p_ub, fldidocc, &bfldid, &occ, &len_data);
0846     
0847     if (NULL==p_ub)
0848     {
0849         if (debug_get_ubf_level() > log_info)
0850         {
0851             ndrx_ubf_sequence_str(fldidocc, debugbuf, sizeof(debugbuf));
0852             UBF_LOG(log_info, "Field not found, sequence: %s", debugbuf);
0853         }
0854         
0855         ret=EXFALSE;
0856         goto out;
0857     }
0858     
0859     ret=Bpres(p_ub, bfldid, occ);
0860     
0861 out:
0862     return ret;
0863 }
0864 
0865 /**
0866  * Retrieve field from view which is set in UBF buffer
0867  * @param p_ub UBF buffer
0868  * @param fldidocc fldid,occ,fldid,occ (last if BFLD_VIEW field)
0869  * @param cname field name in view
0870  * @param occ occurrence of view field
0871  * @param buf buffer where to unload the view data
0872  * @param len buffer length 
0873  * @param usrtype user type of buf to unload to
0874  * @param flags optional BVACCESS_NOTNULL
0875  * @return EXSUCCEED/EXFAIL
0876  */
0877 expublic int ndrx_CBvgetr(UBFH *p_ub, BFLDID *fldidocc, char *cname, BFLDOCC occ, 
0878              char *buf, BFLDLEN *len, int usrtype, long flags)
0879 {
0880     int ret = EXSUCCEED;
0881     BFLDID bfldid;
0882     BFLDOCC iocc;
0883     BFLDLEN len_data;
0884     BVIEWFLD *vdata;
0885     int typ;
0886     char debugbuf[DEBUG_STR_MAX]="";
0887     
0888     p_ub=ndrx_ubf_R_find(p_ub, fldidocc, &bfldid, &iocc, &len_data);
0889     
0890     if (NULL==p_ub)
0891     {
0892         if (debug_get_ubf_level() > log_info)
0893         {
0894             ndrx_ubf_sequence_str(fldidocc, debugbuf, sizeof(debugbuf));
0895             UBF_LOG(log_info, "Field not found, sequence: %s", debugbuf);
0896         }
0897         
0898         goto out;
0899     }
0900     
0901     /* check the field type, must be view */
0902     typ = Bfldtype(bfldid);
0903     if (BFLD_VIEW!=typ)
0904     {
0905         ndrx_Bset_error_fmt(BEBADOP, "Expected BFLD_VIEW(%d) got %d",
0906                 BFLD_VIEW, typ);
0907         UBF_LOG(log_error, "Expected BFLD_VIEW(%d) got %d",
0908                 BFLD_VIEW, typ);
0909         EXFAIL_OUT(ret);
0910     }
0911     
0912     /* retrieve the VIEW */
0913     vdata = (BVIEWFLD *)Bfind(p_ub, bfldid, iocc, &len_data);
0914     
0915     if (NULL==vdata)
0916     {
0917         UBF_LOG(log_error, "Failed to find %d fld occ %d", bfldid, iocc);
0918         EXFAIL_OUT(ret);
0919     }
0920     
0921     UBF_LOG(log_debug, "Reading view field [%s] field [%s] occ [%d] dataptr=%p",
0922             vdata->vname, cname, occ, vdata->data);
0923     
0924     ret = CBvget(vdata->data, vdata->vname, cname, occ, buf, len, usrtype, flags);
0925     
0926 out:
0927             
0928     UBF_LOG(log_debug, "returns %d", ret);
0929 
0930     return ret;
0931 }
0932 
0933 /**
0934  * Retrieve field from view which is set in UBF buffer
0935  * @param p_ub UBF buffer
0936  * @param fldidocc fldid,occ,fldid,occ (last if BFLD_VIEW field)
0937  * @param cname field name in view
0938  * @param occ occurrence of view field
0939  * @param usrtype user type of buf to unload to
0940  * @param flags optional BVACCESS_NOTNULL
0941  * @param extralen extra len to alloc and output len
0942  * @return NULL on error, ptr to data
0943  */
0944 expublic char *ndrx_CBvgetallocr(UBFH *p_ub, BFLDID *fldidocc, char *cname, BFLDOCC occ, 
0945              int usrtype, long flags, BFLDLEN *extralen)
0946 {
0947     char * ret = NULL;
0948     BFLDID bfldid;
0949     BFLDOCC iocc;
0950     BFLDLEN len_data;
0951     BVIEWFLD *vdata;
0952     int typ;
0953     char debugbuf[DEBUG_STR_MAX]="";
0954     
0955     p_ub=ndrx_ubf_R_find(p_ub, fldidocc, &bfldid, &iocc, &len_data);
0956     
0957     if (NULL==p_ub)
0958     {
0959         if (debug_get_ubf_level() > log_info)
0960         {
0961             ndrx_ubf_sequence_str(fldidocc, debugbuf, sizeof(debugbuf));
0962             UBF_LOG(log_info, "Field not found, sequence: %s", debugbuf);
0963         }
0964         
0965         goto out;
0966     }
0967     
0968     /* check the field type, must be view */
0969     typ = Bfldtype(bfldid);
0970     if (BFLD_VIEW!=typ)
0971     {
0972         ndrx_Bset_error_fmt(BEBADOP, "Expected BFLD_VIEW(%d) got %d",
0973                 BFLD_VIEW, typ);
0974         UBF_LOG(log_error, "Expected BFLD_VIEW(%d) got %d",
0975                 BFLD_VIEW, typ);
0976         goto out;
0977     }
0978     
0979     /* retrieve the VIEW */
0980     vdata = (BVIEWFLD *)Bfind(p_ub, bfldid, iocc, &len_data);
0981     
0982     if (NULL==vdata)
0983     {
0984         UBF_LOG(log_error, "Failed to find %d fld occ %d", bfldid, iocc);
0985         goto out;
0986     }
0987     
0988     UBF_LOG(log_debug, "Reading view field [%s] field [%s] occ [%d] dataptr=%p",
0989             vdata->vname, cname, occ, vdata->data);
0990     
0991     ret = CBvgetalloc(vdata->data, vdata->vname, cname, occ, usrtype, flags, extralen);
0992     
0993 out:
0994             
0995     UBF_LOG(log_debug, "returns %p", ret);
0996 
0997     return ret;
0998 }
0999 
1000 /**
1001  * Recursive UBF buffer extract view and test for view field presence
1002  * @param p_ub UBF buffer to search for sub-view
1003  * @param fldidocc fldid,occ,fldid,occ,BBADFLDID sequence the last fldid shall match
1004  *  the view.
1005  * @param cname View field name to test
1006  * @param occ occurrence to test
1007  * @return EXFAIL (on error), EXFALSE (field 
1008  */
1009 expublic int ndrx_Bvnullr(UBFH *p_ub, BFLDID *fldidocc, char *cname, BFLDOCC occ)
1010 {
1011     int ret = EXSUCCEED;
1012     BFLDID bfldid;
1013     BFLDOCC iocc;
1014     BFLDLEN len_data;
1015     BVIEWFLD *vdata;
1016     int typ;
1017     char debugbuf[DEBUG_STR_MAX]="";
1018     
1019     p_ub=ndrx_ubf_R_find(p_ub, fldidocc, &bfldid, &iocc, &len_data);
1020     
1021     if (NULL==p_ub)
1022     {
1023         if (debug_get_ubf_level() > log_info)
1024         {
1025             ndrx_ubf_sequence_str(fldidocc, debugbuf, sizeof(debugbuf));
1026             UBF_LOG(log_info, "Field not found, sequence: %s", debugbuf);
1027         }
1028         
1029         goto out;
1030     }
1031     
1032     /* check the field type, must be view */
1033     typ = Bfldtype(bfldid);
1034     if (BFLD_VIEW!=typ)
1035     {
1036         ndrx_Bset_error_fmt(BEBADOP, "Expected BFLD_VIEW(%d) got %d",
1037                 BFLD_VIEW, typ);
1038         UBF_LOG(log_error, "Expected BFLD_VIEW(%d) got %d",
1039                 BFLD_VIEW, typ);
1040         EXFAIL_OUT(ret);
1041     }
1042     
1043     /* retrieve the VIEW */
1044     vdata = (BVIEWFLD *)Bfind(p_ub, bfldid, iocc, &len_data);
1045     
1046     if (NULL==vdata)
1047     {
1048         UBF_LOG(log_error, "Failed to find %d fld occ %d", bfldid, iocc);
1049         EXFAIL_OUT(ret);
1050     }
1051     
1052     UBF_LOG(log_debug, "Reading view field [%s] field [%s] occ [%d] dataptr=%p",
1053             vdata->vname, cname, occ, vdata->data);
1054     
1055     ret = Bvnull(vdata->data,  cname, occ, vdata->vname);
1056     
1057 out:
1058             
1059     UBF_LOG(log_debug, "returns %d", ret);
1060 
1061     return ret;
1062 }
1063 
1064 /* vim: set ts=4 sw=4 et smartindent: */