Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief UBF library
0003  *   Bfprint & Bextread implementations.
0004  *
0005  * @file bprint_impl.c
0006  */
0007 /* -----------------------------------------------------------------------------
0008  * Enduro/X Middleware Platform for Distributed Transaction Processing
0009  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0010  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0011  * This software is released under one of the following licenses:
0012  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0013  * See LICENSE file for full text.
0014  * -----------------------------------------------------------------------------
0015  * AGPL license:
0016  *
0017  * This program is free software; you can redistribute it and/or modify it under
0018  * the terms of the GNU Affero General Public License, version 3 as published
0019  * by the Free Software Foundation;
0020  *
0021  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0022  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0023  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0024  * for more details.
0025  *
0026  * You should have received a copy of the GNU Affero General Public License along 
0027  * with this program; if not, write to the Free Software Foundation, Inc.,
0028  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0029  *
0030  * -----------------------------------------------------------------------------
0031  * A commercial use license is available from Mavimax, Ltd
0032  * contact@mavimax.com
0033  * -----------------------------------------------------------------------------
0034  */
0035 
0036 /*---------------------------Includes-----------------------------------*/
0037 /* needed for asprintf */
0038 #ifndef _GNU_SOURCE
0039 #define _GNU_SOURCE
0040 #endif
0041 #include <stdio.h>
0042 
0043 #include <string.h>
0044 
0045 #include <stdlib.h>
0046 #include <memory.h>
0047 #include <errno.h>
0048 
0049 #include <ubf.h>
0050 #include <ubf_int.h>    /* Internal headers for UBF... */
0051 #include <fdatatype.h>
0052 #include <ferror.h>
0053 #include <fieldtable.h>
0054 #include <ndrstandard.h>
0055 #include <ndebug.h>
0056 #include <cf.h>
0057 #include <utils.h>
0058 #include <ubf_tls.h>
0059 #include <ubfview.h>
0060 
0061 #include "atmi_int.h"
0062 /*---------------------------Externs------------------------------------*/
0063 /*---------------------------Macros-------------------------------------*/
0064 
0065 #define OUTPUT_FORMAT_WDATA fmt_wdata, ndrx_Bfname_int(bfldid), p
0066 #define OUTPUT_FORMAT_NDATA fmt_ndata, ndrx_Bfname_int(bfldid)
0067 
0068 /*---------------------------Enums--------------------------------------*/
0069 /*---------------------------Typedefs-----------------------------------*/
0070 /*---------------------------Globals------------------------------------*/
0071 /*---------------------------Statics------------------------------------*/
0072 /*---------------------------Prototypes---------------------------------*/
0073 
0074 /**
0075  * Internal implementation of Bfprintf - print buffer to file.
0076  * Have to use buffering for non-printable characters, because printing one-by-one
0077  * is slow?
0078  * Also will re-use Fnext for iterating throught the buffer.
0079  * @param p_ub - UBF buffer
0080  * @param outf - file descriptor to print to
0081  * @param p_writef callback function which overrides outf (i.e. it can be set to
0082  *  NULL for particular case). Then for data output callback is used.
0083  *  if do_write is set, the data in buffer will be written to output.
0084  *  'buffer' may be reallocated.
0085  * @param dataptr1 optional argument to p_writef if callback present
0086  * @param level this is recursive level used for printing embedded buffers
0087  * @return SUCCEED/FAIL
0088  */
0089 expublic int ndrx_Bfprint (UBFH *p_ub, FILE * outf,
0090           ndrx_plugin_tplogprintubf_hook_t p_writef, void *dataptr1, int level)
0091 {
0092     int ret=EXSUCCEED;
0093     BFLDID bfldid;
0094     BFLDLEN  len;
0095     BFLDOCC occ;
0096     char *p;
0097     int fldtype;
0098     char *cnv_buf = NULL;
0099     char *tmp_buf = NULL;
0100     BFLDLEN cnv_len;
0101     char fmt_wdata[256];
0102     char fmt_ndata[256];
0103     int i;
0104     BVIEWFLD *vdata;
0105     Bnext_state_t bprint_state;
0106     int temp_len;
0107     
0108     UBF_TLS_ENTRY;
0109     
0110     UBF_LOG(log_debug, "%s enter at level %d", __func__, level);
0111     
0112     memset(&bprint_state, 0, sizeof(bprint_state));
0113     
0114     for (i=0; i<level; i++)
0115     {
0116         fmt_wdata[i]='\t';
0117         fmt_ndata[i]='\t';
0118     }
0119     
0120     fmt_wdata[i]=EXEOS;
0121     fmt_ndata[i]=EXEOS;
0122     
0123     NDRX_STRCAT_S(fmt_wdata, sizeof(fmt_wdata), "%s\t%s\n");
0124     NDRX_STRCAT_S(fmt_ndata, sizeof(fmt_ndata), "%s\t\n");
0125 
0126     UBF_LOG(log_debug, "fmt_wdata=[%s] fmt_ndata=[%s]", fmt_wdata, fmt_ndata);
0127     
0128     bfldid = BFIRSTFLDID;
0129 
0130     while(1==ndrx_Bnext(&bprint_state, 
0131             p_ub, &bfldid, &occ, NULL, &len, &p))
0132     {
0133         if (NULL!=tmp_buf)
0134         {
0135             NDRX_FREE(tmp_buf);
0136             tmp_buf = NULL;
0137         }
0138 
0139         if (NULL!=cnv_buf)
0140         {
0141             NDRX_FREE(cnv_buf);
0142             cnv_buf = NULL;
0143         }
0144 
0145         fldtype=bfldid>>EFFECTIVE_BITS;
0146 
0147         /* All other data types needs to be converted */
0148         if (BFLD_VIEW==fldtype)
0149         {
0150             vdata = (BVIEWFLD *)p;
0151             /* for value we print the view name */
0152             p=vdata->vname;
0153             len=strlen(vdata->vname)+1;
0154         }
0155         else if (BFLD_UBF==fldtype)
0156         {
0157             /* for UBFs we just print the field name */
0158             len = 0;
0159         }
0160         else if (BFLD_STRING!=fldtype && BFLD_CARRAY!=fldtype)
0161         {
0162             cnv_buf=ndrx_Btypcvt(&cnv_len, BFLD_STRING, p, fldtype, len);
0163 
0164             if (NULL==cnv_buf)
0165             {
0166                 /* we failed to convert - FAIL! No buffers should be allocated
0167                  * at the moment. */
0168                 break; /* <<< BREAK */
0169             }
0170             else
0171             {
0172                 p=cnv_buf;
0173             }
0174             
0175             /* escape char data... */
0176             if (BFLD_CHAR==fldtype &&
0177                     (temp_len = ndrx_get_nonprintable_char_tmpspace(p, cnv_len)) &&
0178                     temp_len!=cnv_len)
0179             {
0180                 UBF_LOG(log_debug, "Containing special characters -"
0181                                 " needs to temp buffer for prefixing");
0182                 tmp_buf=NDRX_MALLOC(temp_len+1); /* adding +1 for EOS */
0183                 if (NULL==tmp_buf)
0184                 {
0185                     ndrx_Bset_error_fmt(BMALLOC, "%s: Failed to allocate ",
0186                             __func__, temp_len+1);
0187                     EXFAIL_OUT(ret);
0188                 }
0189 
0190                 /* build the printable string */
0191                 ndrx_build_printable_string(tmp_buf, temp_len+1, p, len);
0192                 p = tmp_buf;
0193             }
0194             
0195             len=cnv_len;
0196         }
0197         /* now check are we printable? */
0198         else if (BFLD_STRING==fldtype || BFLD_CARRAY==fldtype)
0199         {
0200             /* For strings we must count off trailing EOS */
0201             if (BFLD_STRING==fldtype)
0202             {
0203                 len--;
0204             }
0205 
0206             temp_len = ndrx_get_nonprintable_char_tmpspace(p, len);
0207 
0208             if (temp_len!=len) /* for carray we need EOS at end! */
0209             {
0210                 UBF_LOG(log_debug, "Containing special characters -"
0211                                     " needs to temp buffer for prefixing");
0212                 tmp_buf=NDRX_MALLOC(temp_len+1); /* adding +1 for EOS */
0213                 if (NULL==tmp_buf)
0214                 {
0215                     ndrx_Bset_error_fmt(BMALLOC, "%s: Failed to allocate ",
0216                             __func__, temp_len+1);
0217                     EXFAIL_OUT(ret);
0218                 }
0219 
0220                 /* build the printable string */
0221                 ndrx_build_printable_string(tmp_buf, temp_len+1, p, len);
0222                 p = tmp_buf;
0223             }
0224             else if (BFLD_CARRAY==fldtype) /* we need EOS for carray... */
0225             {
0226                 tmp_buf=NDRX_MALLOC(temp_len+1); /* adding +1 for EOS */
0227                 
0228                 memcpy(tmp_buf, p, temp_len);
0229                 
0230                 if (NULL==tmp_buf)
0231                 {
0232                     ndrx_Bset_error_fmt(BMALLOC, "%s: Failed to allocate ", 
0233                             __func__, temp_len+1);
0234                     EXFAIL_OUT(ret);
0235                 }
0236                 tmp_buf[temp_len] = EXEOS;
0237                 p = tmp_buf;
0238             }
0239         }
0240 
0241         /* value is kept in p */
0242         if (len>0)
0243         {
0244 /* #define OUTPUT_FORMAT_WDATA "%s\t%s\n", ndrx_Bfname_int(bfldid), p*/
0245 
0246             if (NULL!=p_writef)
0247             {
0248                 char *tmp;
0249                 long tmp_len;
0250                 int do_write = EXFALSE;
0251                 
0252                 NDRX_ASPRINTF(&tmp, &tmp_len, OUTPUT_FORMAT_WDATA);
0253                 
0254                 if (NULL==tmp)
0255                 {
0256                     ndrx_Bset_error_fmt(BMALLOC, "%s: NDRX_ASPRINTF failed", 
0257                             __func__);
0258                     EXFAIL_OUT(ret);
0259                 }
0260                 
0261                 tmp_len++;
0262                 
0263                 if (EXSUCCEED!=(ret=p_writef(&tmp, tmp_len, dataptr1, &do_write, 
0264                         outf, bfldid)))
0265                 {
0266                     ndrx_Bset_error_fmt(BEINVAL, "%s: p_writef user function "
0267                             "failed with %d for [%s]", 
0268                             __func__, ret, tmp);
0269                     NDRX_FREE(tmp);
0270                     EXFAIL_OUT(ret);
0271                 }
0272                 
0273                 if (do_write)
0274                 {
0275                     fprintf(outf, "%s", tmp);
0276                 }
0277                         
0278                 NDRX_FREE(tmp);
0279             }
0280             else
0281             {
0282                 fprintf(outf, OUTPUT_FORMAT_WDATA);
0283             }
0284             
0285         }
0286         else
0287         {
0288             if (NULL!=p_writef)
0289             {
0290                 char *tmp;
0291                 long tmp_len;
0292                 int do_write = EXFALSE;
0293                 
0294                 NDRX_ASPRINTF(&tmp, &tmp_len, OUTPUT_FORMAT_NDATA);
0295                 
0296                 if (NULL==tmp)
0297                 {
0298                     ndrx_Bset_error_fmt(BMALLOC, "%s: NDRX_ASPRINTF failed 2", 
0299                             __func__);
0300                     EXFAIL_OUT(ret);
0301                 }
0302                 
0303                 tmp_len++;
0304                 
0305                 if (EXSUCCEED!=(ret=p_writef(&tmp, tmp_len, dataptr1, &do_write, outf,
0306                         bfldid)))
0307                 {
0308                     ndrx_Bset_error_fmt(BEINVAL, "%s: p_writef user function "
0309                             "failed with %d for [%s] 2", 
0310                             __func__, ret, tmp);
0311                     NDRX_FREE(tmp);
0312                     EXFAIL_OUT(ret);
0313                 }
0314                 
0315                 if (do_write)
0316                 {
0317                     fprintf(outf, "%s", tmp);
0318                 }
0319                 
0320                 NDRX_FREE(tmp);
0321             }
0322             else
0323             {
0324                 fprintf(outf, OUTPUT_FORMAT_NDATA);
0325             }
0326    
0327         }
0328         
0329         if (NULL!=outf && ferror(outf))
0330         {
0331             ndrx_Bset_error_fmt(BEUNIX, "Failed to write to file with error: [%s]",
0332                         strerror(errno));
0333             EXFAIL_OUT(ret);
0334         }
0335         
0336         /* Step into printing the inner ubf */
0337         if (BFLD_UBF==fldtype)
0338         {
0339             if (EXSUCCEED!=ndrx_Bfprint ((UBFH *)p, outf, p_writef, dataptr1, level+1))
0340             {
0341                 UBF_LOG(log_error, "ndrx_Bfprint failed at level %d", level+1);
0342                 EXFAIL_OUT(ret);
0343             }
0344         }
0345         /* the view is not empty one... */
0346         else if (BFLD_VIEW==fldtype && len > 1)
0347         {
0348             /* at this step we shall print the VIEW at given indentation level */
0349             if (EXSUCCEED!=ndrx_Bvfprint (vdata->data, vdata->vname, outf,
0350                     p_writef, dataptr1, level+1))
0351             {
0352                 UBF_LOG(log_error, "ndrx_Bvfprint failed at level %d", level+1);
0353                 EXFAIL_OUT(ret);
0354             }
0355         }
0356     }
0357     
0358 out:
0359     /* Free up allocated resources */
0360     if (NULL!=tmp_buf)
0361     {
0362         NDRX_FREE(tmp_buf);
0363     }
0364 
0365     if (NULL!=cnv_buf)
0366     {
0367         NDRX_FREE(cnv_buf);
0368     }
0369 
0370     /* release the stuff... */
0371     if (0==level)
0372     {
0373         fflush(outf);
0374     }
0375 
0376     return ret;
0377 }
0378 
0379 /**
0380  * Internal version of Bextread. This accepts either file stream or callback
0381  * function. One or other must be present. The output may be produced by
0382  * \ref Bfprint or similar funcs.
0383  * @param p_ub ptr to UBF buffer
0384  * @param inf input file stream
0385  * @param p_readf callback to read function. Function shall provide back data
0386  *  to ndrx_Bextread(). The reading must be feed line by line. The input line
0387  *  must be terminated with EOS. The buffer size which accepts the input line
0388  *  is set by `bufsz'. The function receives forwarded \p dataptr1 argument.
0389  *  Once EOF is reached, the callback shall return read of 0 bytes. Otherwise
0390  *  it must return number of bytes read, including EOS.
0391  * @param dataptr1 option user pointer forwarded to \p p_readf.
0392  * @param level recursion level
0393  * @param p_readbuf_buffered (if previous recursion terminated with next line
0394  *  from current buffer
0395  * @param p_is_eof is EOF set by recusrsion
0396  * @return EXSUCCEED/EXFAIL
0397  */
0398 expublic int ndrx_Bextread (UBFH * p_ub, FILE *inf,
0399         long (*p_readf)(char *buffer, long bufsz, void *dataptr1), 
0400         void *dataptr1, int level, char **p_readbuf_buffered)
0401 {
0402     int ret=EXSUCCEED;
0403     int line=0;
0404     char *readbuf=NULL;
0405     size_t readbuf_len;
0406     char fldnm[UBFFLDMAX+1];
0407     char view[NDRX_VIEW_NAME_LEN+1];
0408     char *value=NULL;
0409     size_t value_len;
0410     char flag;
0411     char *p;
0412     char *tok;
0413     BFLDID bfldid;
0414     BFLDID bfldid_from;
0415     int fldtype;
0416     int cpylen;
0417     int len;
0418     char *readbuf_buffered=NULL;
0419     int nr_lead_tabs;
0420     int is_eof=EXFALSE;
0421     NDRX_USYSBUF_MALLOC_WERR_OUT(readbuf, readbuf_len, ret);
0422     NDRX_USYSBUF_MALLOC_WERR_OUT(value, value_len, ret);
0423     
0424     /* Read line by line */
0425     while(!is_eof)
0426     {
0427         /* use buffered line from inner reads */
0428         if (NULL!=readbuf_buffered)
0429         {
0430             NDRX_SYSBUF_FREE(readbuf);
0431             readbuf=readbuf_buffered;
0432             readbuf_buffered=NULL;
0433         }
0434         else if (NULL!=p_readf)
0435         {
0436             /* read the data from callback */
0437             ret = (int)p_readf(readbuf, readbuf_len, dataptr1);
0438             
0439             if (0==ret)
0440             {
0441                 /* eof reached */
0442                 break;
0443             }
0444             if (ret < 0)
0445             {
0446                 ndrx_Bset_error_fmt(BEUNIX, "p_readf() user callback failed");
0447                 
0448                 EXFAIL_OUT(ret);
0449             }
0450             ret = EXSUCCEED;
0451         }
0452         else 
0453         {
0454             if (NULL==fgets(readbuf, readbuf_len, inf))
0455             {
0456                 /* terminate the loop */
0457                 /*
0458                  * Check errors on file.
0459                  */
0460                 if (!feof(inf))
0461                 {
0462                    /* some other error happened!?! */
0463                    ndrx_Bset_error_fmt(BEUNIX, "Failed to read from file "
0464                            "with error: [%s]", strerror(errno));
0465                    EXFAIL_OUT(ret);
0466                 }
0467 
0468                 break;
0469             }
0470         }
0471                 
0472         len = strlen(readbuf);
0473         line++;
0474         bfldid=BBADFLDID;
0475         value[0] = EXEOS;
0476         fldnm[0] = EXEOS;
0477         p = readbuf;
0478 
0479         if ('#'==p[0])
0480         {
0481             continue; /* <<<< nothing to do - continue */
0482         }
0483 
0484         /* Ignore any newline we get, so that we are backwards compatible
0485          * with original logic
0486          */
0487         if (0==strcmp(p, "\n"))
0488         {
0489             continue; /* <<<< nothing to do - continue */
0490         }
0491         
0492         /* check the leading tabs, to see the current nesting level */
0493         nr_lead_tabs=0;
0494         while (*p=='\t')
0495         {
0496             nr_lead_tabs++;
0497             p++;
0498         }
0499         
0500         /* terminate the function if found less tabs than current level */
0501         if (nr_lead_tabs < level)
0502         {
0503             UBF_LOG(log_debug, "Found tab level %d current %d, popping up line %d", 
0504                     nr_lead_tabs, level, line);
0505             if (NULL!=p_readbuf_buffered)
0506             {
0507                 /* pass to upper level */
0508                 *p_readbuf_buffered=readbuf;
0509                 readbuf=NULL;
0510             }
0511             /* terminate the read */
0512             goto out;
0513         }
0514         else if (nr_lead_tabs > level)
0515         {
0516             ndrx_Bset_error_fmt(BSYNTAX, "Tab level %d expected %d or less - "
0517                     "invalid data at line %d", nr_lead_tabs, level, line);
0518             EXFAIL_OUT(ret);
0519         }
0520         /* else: it is current level and process ok */
0521         
0522         flag = 0;
0523 
0524         if ('-'==p[0] || '+'==p[0] || '='==p[0])
0525         {
0526             /* Check syntax with flags... */
0527 
0528             flag=p[0];
0529 
0530             if (' '!=p[1])
0531             {
0532                 ndrx_Bset_error_fmt(BSYNTAX, "Space does not follow the flag on "
0533                                             "line %d!", line);
0534                 
0535                 EXFAIL_OUT(ret);
0536             }
0537             else
0538             {
0539                 /* step forward, flag + eos*/
0540                 p+=2;
0541             }
0542         }
0543         
0544         tok = strchr(p, '\t');
0545         if (NULL==tok)
0546         {
0547             ndrx_Bset_error_fmt(BSYNTAX, "No tab on "
0548                                         "line %d!", line);
0549             EXFAIL_OUT(ret);
0550         }
0551         else if (tok==readbuf)
0552         {
0553             ndrx_Bset_error_fmt(BSYNTAX, "Line should not start with tab on "
0554                                         "line %d!", line);
0555             EXFAIL_OUT(ret);
0556         } 
0557         else
0558         {
0559             int tmpl = strlen(p);
0560             /* seems to be ok, remove trailing newline */
0561             
0562             if (p[tmpl-1]!='\n')
0563             {
0564                 /* new line at the end is optional for callbacks... */
0565                 if (NULL==p_readf)
0566                 {
0567                     ndrx_Bset_error_fmt(BSYNTAX, "Line %d does not "
0568                             "terminate with newline!", line);
0569                     EXFAIL_OUT(ret);
0570                 }
0571             }
0572             else
0573             {
0574                 p[tmpl-1]=EXEOS;
0575             }
0576         }
0577 
0578         /* now read field number + value */
0579         cpylen = (tok-p);
0580         /* Copy off field name */
0581         NDRX_STRNCPY_EOS(fldnm, p, cpylen, sizeof(fldnm));
0582         
0583         /* Copy off value */
0584         NDRX_STRCPY_SAFE_DST(value, tok+1, value_len);
0585         UBF_LOG(log_debug, "Got [%s]:[%s]", fldnm, value);
0586 
0587         /*
0588          * Resolve field name
0589          */
0590         bfldid = ndrx_Bfldid_int(fldnm);
0591         if (BBADFLDID==bfldid)
0592         {
0593             ndrx_Bset_error_fmt(BBADNAME, "Cannot resolve field ID from [%s] on"
0594                                         "line %d!", fldnm, line);
0595             EXFAIL_OUT(ret);
0596         }
0597 
0598         /* Get new field type */
0599         fldtype=bfldid >> EFFECTIVE_BITS;
0600 
0601         /* check type */
0602         if (IS_TYPE_INVALID(fldtype))
0603         {
0604             ndrx_Bset_error_fmt(BBADFLD, "BAD field's type [%d] on"
0605                                             "line %d!", fldtype, line);
0606             EXFAIL_OUT(ret);
0607         }
0608         
0609         /* Check field type */
0610         if (BFLD_PTR==fldtype && !(ndrx_G_apiflags & NDRX_APIFLAGS_UBFPTRPARSE))
0611         {
0612             flag='N';   /* Ignore field... */
0613         }
0614         else if ((BFLD_STRING == fldtype || 
0615                 BFLD_CARRAY == fldtype || BFLD_CHAR == fldtype) && '='!=flag)
0616         {
0617             if (EXFAIL==ndrx_normalize_string(value, &len))
0618             {
0619                 ndrx_Bset_error_fmt(BSYNTAX, "Cannot normalize value on line %d", 
0620                         line);
0621                 EXFAIL_OUT(ret);
0622             }
0623         }
0624         else if (BFLD_UBF == fldtype && '='!=flag)
0625         {
0626             /* init the buffer */
0627             if (EXSUCCEED!=Binit((UBFH*)value, value_len))
0628             {
0629                 UBF_LOG(log_error, "Failed to init %p/%z level: %d", 
0630                         value, value_len, level);
0631                 EXFAIL_OUT(ret);
0632             }
0633             
0634             /* start to parse inner struct.. */
0635             if (EXSUCCEED!=ndrx_Bextread ((UBFH*)value, inf,
0636                 p_readf, dataptr1, level+1, &readbuf_buffered))
0637             {
0638                 UBF_LOG(log_error, "Failed to parse inner UBF level %d", level+1);
0639                 EXFAIL_OUT(ret);
0640             }
0641             
0642             /* if no next line found, then it is EOF */
0643             if (NULL==readbuf_buffered)
0644             {
0645                 is_eof=EXTRUE;
0646             }
0647         }
0648         else if (BFLD_VIEW == fldtype && '='!=flag)
0649         {
0650             /* now parse the view  
0651              * So where do we load?
0652              * And how do we add to FB? Needs some temp space not...
0653              */
0654             ndrx_typedview_t *v = NULL;
0655             
0656             NDRX_STRCPY_SAFE(view, value);
0657             
0658             if (EXSUCCEED!=ndrx_view_init())
0659             {
0660                 UBF_LOG(log_error, "Failed to init view sub-system");
0661                 EXFAIL_OUT(ret);
0662             }
0663             
0664             /* Resolve view descriptor, in case of view is not empty... */
0665             if (EXEOS!=view[0])
0666             {
0667                 if (NULL==(v = ndrx_view_get_view(view)))
0668                 {
0669                     ndrx_Bset_error_fmt(BBADVIEW, "View [%s] not found!", view);
0670                     EXFAIL_OUT(ret);
0671                 }
0672 
0673                 if (value_len<v->ssize)
0674                 {
0675                     ndrx_Bset_error_fmt(BNOSPACE, "Temporary buffer size %zu "
0676                             "is shorter than view size %ld", value_len, v->ssize);
0677                     EXFAIL_OUT(ret);
0678                 }
0679 
0680                 /* use value buffer for building up the view data */
0681                 if (EXSUCCEED!=ndrx_Bvextread (value, view, inf, p_readf, dataptr1, 
0682                         level+1, &readbuf_buffered))
0683                 {
0684                     UBF_LOG(log_error, "Failed to parse view [%s] at level %d", 
0685                             view, level+1);
0686                     EXFAIL_OUT(ret);
0687                 }
0688             }
0689             
0690             /* add stuff to fb... */
0691         }
0692         
0693         /* now about to execute command */
0694         if (0==flag)
0695         {
0696             if (BFLD_UBF == fldtype)
0697             {
0698                 if (EXSUCCEED!=(ret=Badd(p_ub, bfldid, value, 0)))
0699                 {
0700                     EXFAIL_OUT(ret);
0701                 }
0702             }
0703             else if (BFLD_VIEW == fldtype)
0704             {
0705                 BVIEWFLD vadd;
0706                 
0707                 vadd.data=value;
0708                 NDRX_STRCPY_SAFE(vadd.vname, view);
0709                 vadd.vflags=0;
0710                 if (EXSUCCEED!=(ret=Badd(p_ub, bfldid, (char *)&vadd, 0)))
0711                 {
0712                     EXFAIL_OUT(ret);
0713                 }
0714             }
0715             else if (EXSUCCEED!=(ret=CBadd(p_ub, bfldid, value, len, BFLD_CARRAY)))
0716             {
0717                 EXFAIL_OUT(ret);
0718             }
0719         }
0720         else if ('+'==flag)
0721         {
0722             if (BFLD_UBF == fldtype)
0723             {
0724                 if (EXSUCCEED!=(ret=Bchg(p_ub, bfldid, 0, value, 0)))
0725                 {
0726                     EXFAIL_OUT(ret);
0727                 }
0728             }
0729             else if (BFLD_VIEW == fldtype)
0730             {
0731                 BVIEWFLD vadd;
0732                 
0733                 vadd.data=value;
0734                 NDRX_STRCPY_SAFE(vadd.vname, view);
0735                 vadd.vflags=0;
0736                 if (EXSUCCEED!=(ret=Bchg(p_ub, bfldid, 0, (char *)&vadd, 0)))
0737                 {
0738                     EXFAIL_OUT(ret);
0739                 }
0740             }
0741             else if (EXSUCCEED!=(ret=CBchg(p_ub, bfldid, 0, value, len, BFLD_CARRAY)))
0742             {
0743                 EXFAIL_OUT(ret);
0744             }
0745         }
0746         else if ('-'==flag)
0747         {
0748             if (EXSUCCEED!=(ret=Bdel(p_ub, bfldid, 0)))
0749             {
0750                 EXFAIL_OUT(ret);
0751             }
0752         }
0753         else if ('='==flag)
0754         {
0755             /* Resolve field to-field id */
0756             bfldid_from = ndrx_Bfldid_int(value);
0757             if (BBADFLDID==bfldid_from)
0758             {
0759                 ndrx_Bset_error_fmt(BBADNAME, "Cannot resolve field ID from [%s] on"
0760                                             "line %d!", value, line);
0761                 EXFAIL_OUT(ret);
0762             }
0763             else
0764             {
0765                 BFLDLEN len_from=0;
0766                 /* TODO: use Bgetalloc to copy value from */
0767                 char *copy_form = Bgetalloc (p_ub, bfldid_from, 0, &len_from);
0768                 
0769                 /* Find the value and put into buffer. */
0770                 if (NULL!=copy_form)
0771                 {
0772                     
0773                     /* WARNING! This might move the source buffer before setting
0774                      * Say: We set field_id=1 from field_id=2. Thus we will move
0775                      * the 2 to get space for 1.
0776                      * Fixed: moved from Bfind to ndrx_Bgetalloc
0777                      */
0778                     
0779                     /* to work with view/ubf we need Bchg() in place */
0780                     if (Bfldtype(bfldid_from) == fldtype)
0781                     {
0782                         if (EXSUCCEED!=(ret=Bchg(p_ub, bfldid, 0, copy_form, len_from)))
0783                         {
0784                             NDRX_FREE(copy_form);
0785                             EXFAIL_OUT(ret);
0786                         }
0787                     }
0788                     else if (EXSUCCEED!=(ret=CBchg(p_ub, bfldid, 0, copy_form, 
0789                             len_from, Bfldtype(bfldid_from))))
0790                     {
0791                         NDRX_FREE(copy_form);
0792                         EXFAIL_OUT(ret);
0793                     }
0794                     
0795                     NDRX_FREE(copy_form);
0796                 }
0797                 else
0798                 {
0799                     EXFAIL_OUT(ret);
0800                 }
0801             }
0802         } /* '='==flag */
0803         else if ('N'==flag)
0804         {
0805             UBF_LOG(log_error, "Ignoring field %d", bfldid);
0806         }
0807     } /* while */
0808     
0809 out:
0810     
0811     if (NULL!=readbuf_buffered)
0812     {
0813         NDRX_SYSBUF_FREE(readbuf_buffered);
0814     }
0815 
0816     if (NULL!=readbuf)
0817     {
0818         NDRX_SYSBUF_FREE(readbuf);
0819     }
0820 
0821     if (NULL!=value)
0822     {
0823         NDRX_SYSBUF_FREE(value);
0824     }
0825 
0826     UBF_LOG(log_debug, "%s: return %d", __func__, ret);
0827     
0828     return ret;
0829 }
0830 
0831 /* vim: set ts=4 sw=4 et smartindent: */