modules_k/db_text/dbt_file.c

00001 /*
00002  * $Id$
00003  *
00004  * DBText library
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  * 
00024  * History:
00025  * --------
00026  * 2003-02-03 created by Daniel
00027  * 
00028  */
00029 
00030 #include <stdio.h>
00031 #include <string.h>
00032 #include <time.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <dirent.h>
00036 
00037 #include "../../mem/shm_mem.h"
00038 #include "../../mem/mem.h"
00039 #include "../../dprint.h"
00040 
00041 #include "dbt_util.h"
00042 #include "dbt_lib.h"
00043 
00044 
00050 int dbt_check_mtime(const str *tbn, const str *dbn, time_t *mt)
00051 {
00052         char path[512];
00053         struct stat s;
00054         int ret = 0;
00055 
00056         path[0] = 0;
00057         if(dbn && dbn->s && dbn->len>0)
00058         {
00059                 if(dbn->len+tbn->len<511)
00060                 {
00061                         strncpy(path, dbn->s, dbn->len);
00062                         path[dbn->len] = '/';
00063                         strncpy(path+dbn->len+1, tbn->s, tbn->len);
00064                         path[dbn->len+tbn->len+1] = 0;
00065                 }
00066         }
00067         if(path[0] == 0)
00068         {
00069                 strncpy(path, tbn->s, tbn->len);
00070                 path[tbn->len] = 0;
00071         }
00072         if(stat(path, &s) == 0)
00073         {
00074                 if((int)s.st_mtime > (int)*mt)
00075                 {
00076                         ret = 1;
00077                         *mt = s.st_mtime;
00078                         LM_DBG("[%.*s] was updated\n", tbn->len, tbn->s);
00079                 }
00080         } else {
00081                 LM_DBG("stat failed on [%.*s]\n", tbn->len, tbn->s);
00082                 ret = -1;
00083         }
00084         return ret;
00085 }
00086 
00090 dbt_table_p dbt_load_file(const str *tbn, const str *dbn)
00091 {
00092         FILE *fin=NULL;
00093         char path[512], buf[4096];
00094         int c, crow, ccol, bp, sign, max_auto;
00095         dbt_val_t dtval;
00096         dbt_table_p dtp = NULL;
00097         dbt_column_p colp, colp0 = NULL;
00098         dbt_row_p rowp, rowp0 = NULL;
00099                 
00100         enum {DBT_FLINE_ST, DBT_NLINE_ST, DBT_DATA_ST} state;
00101         
00102         LM_DBG("request for table [%.*s]\n", tbn->len, tbn->s);
00103         
00104         if(!tbn || !tbn->s || tbn->len<=0 || tbn->len>=255)
00105                 return NULL;
00106         path[0] = 0;
00107         if(dbn && dbn->s && dbn->len>0)
00108         {
00109                 LM_DBG("db is [%.*s]\n", dbn->len, dbn->s);
00110                 if(dbn->len+tbn->len<511)
00111                 {
00112                         strncpy(path, dbn->s, dbn->len);
00113                         path[dbn->len] = '/';
00114                         strncpy(path+dbn->len+1, tbn->s, tbn->len);
00115                         path[dbn->len+tbn->len+1] = 0;
00116                 }
00117         }
00118         if(path[0] == 0)
00119         {
00120                 strncpy(path, tbn->s, tbn->len);
00121                 path[tbn->len] = 0;
00122         }
00123         
00124         LM_DBG("loading file [%s]\n", path);
00125         fin = fopen(path, "rt");
00126         if(!fin)
00127                 return NULL;    
00128         
00129         dtp = dbt_table_new(tbn, dbn, path);
00130         if(!dtp)
00131                 goto done;
00132         
00133         state = DBT_FLINE_ST;
00134         crow = ccol = -1;
00135         colp = colp0 = NULL;
00136         rowp = rowp0 = NULL;
00137         c = fgetc(fin);
00138         max_auto = 0;
00139         while(c!=EOF)
00140         {
00141                 switch(state)
00142                 {
00143                         case DBT_FLINE_ST:
00144                                 //LM_DBG("state FLINE!\n");
00145                                 bp = 0;
00146                                 while(c==DBT_DELIM_C)
00147                                         c = fgetc(fin);
00148                                 if(c==DBT_DELIM_R && !colp0)
00149                                         goto clean;
00150                                 if(c==DBT_DELIM_R)
00151                                 {
00152                                         if(dtp->nrcols <= 0)
00153                                                 goto clean;
00154                                         dtp->colv = (dbt_column_p*)
00155                                                         shm_malloc(dtp->nrcols*sizeof(dbt_column_p));
00156                                         if(!dtp->colv)
00157                                                 goto clean;
00158                                         colp0 = dtp->cols;
00159                                         for(ccol=0; ccol<dtp->nrcols && colp0; ccol++)
00160                                         {
00161                                                 dtp->colv[ccol] = colp0;
00162                                                 colp0 = colp0->next;
00163                                         }
00164                                         state = DBT_NLINE_ST;
00165                                         break;
00166                                 }
00167                                 while(c!=DBT_DELIM_C && c!='(' && c!=DBT_DELIM_R)
00168                                 {
00169                                         if(c==EOF)
00170                                                 goto clean;
00171                                         buf[bp++] = c;
00172                                         c = fgetc(fin);
00173                                 }
00174                                 colp = dbt_column_new(buf, bp);
00175                                 if(!colp)
00176                                         goto clean;
00177                                 //LM_DBG("new col [%.*s]\n", bp, buf);
00178                                 while(c==DBT_DELIM_C)
00179                                         c = fgetc(fin);
00180                                 if(c!='(')
00181                                         goto clean;
00182                                 c = fgetc(fin);
00183                                 while(c==DBT_DELIM_C)
00184                                         c = fgetc(fin);
00185                                 
00186                                 switch(c)
00187                                 {
00188                                         case 's':
00189                                         case 'S':
00190                                                 colp->type = DB1_STR;
00191                                                 LM_DBG("column[%d] is STR!\n", ccol+1);
00192                                         break;
00193                                         case 'i':
00194                                         case 'I':
00195                                                 colp->type = DB1_INT;
00196                                                 LM_DBG("column[%d] is INT!\n", ccol+1);
00197                                         break;
00198                                         case 'd':
00199                                         case 'D':
00200                                                 colp->type = DB1_DOUBLE;
00201                                                 LM_DBG("column[%d] is DOUBLE!\n", ccol+1);
00202                                         break;
00203                                         case 'b':
00204                                         case 'B':
00205                                                 colp->type = DB1_BLOB;
00206                                                 LM_DBG("column[%d] is BLOB!\n", ccol+1);
00207                                         break;
00208                                         case 't':
00209                                         case 'T':
00210                                                 colp->type = DB1_DATETIME;
00211                                                 LM_DBG("column[%d] is TIME!\n", ccol+1);
00212                                         break;
00213                                         default:
00214                                                 LM_DBG("wrong column type!\n");
00215                                                 goto clean;
00216                                 }
00217 
00218                                 while(c!='\n' && c!=EOF && c!=')' && c!= ',')
00219                                 {
00220                                         if(colp->type == DB1_STR && (c=='i'|| c=='I'))
00221                                         {
00222                                                 colp->type = DB1_STRING;
00223                                                 LM_DBG("column[%d] is actually STRING!\n", ccol+1);
00224                                         }
00225                                         c = fgetc(fin);
00226                                 }
00227                                 if(c==',')
00228                                 {
00229                                         //LM_DBG("c=%c!\n", c);
00230                                         c = fgetc(fin);
00231                                         while(c==DBT_DELIM_C)
00232                                                 c = fgetc(fin);
00233                                         if(c=='N' || c=='n')
00234                                         {
00235                                                 //LM_DBG("NULL flag set!\n");
00236                                                 colp->flag |= DBT_FLAG_NULL;
00237                                         }
00238                                         else if(colp->type==DB1_INT && dtp->auto_col<0
00239                                                         && (c=='A' || c=='a'))
00240                                         {
00241                                                 //LM_DBG("AUTO flag set!\n");
00242                                                 colp->flag |= DBT_FLAG_AUTO;
00243                                                 dtp->auto_col = ccol+1;
00244                                         }
00245                                         else
00246                                                 goto clean;
00247                                         while(c!=')' && c!=DBT_DELIM_R && c!=EOF)
00248                                                 c = fgetc(fin);
00249                                 }
00250                                 if(c == ')')
00251                                 {
00252                                         //LM_DBG("c=%c!\n", c);
00253                                         if(colp0)
00254                                         {
00255                                                 colp->prev = colp0;
00256                                                 colp0->next = colp;
00257                                         }
00258                                         else
00259                                                 dtp->cols = colp;
00260                                         colp0 = colp;
00261                                         dtp->nrcols++;
00262                                         c = fgetc(fin);
00263                                 }
00264                                 else
00265                                         goto clean;
00266                                 ccol++;
00267                         break;
00268 
00269                         case DBT_NLINE_ST:
00270                                 //LM_DBG("state NLINE!\n");
00271                                 while(c==DBT_DELIM_R)
00272                                         c = fgetc(fin);
00273                                 if(rowp)
00274                                 {
00275                                         if(dbt_table_check_row(dtp, rowp))
00276                                                 goto clean;
00277 
00278                                         if(!rowp0)
00279                                                 dtp->rows = rowp;
00280                                         else
00281                                         {
00282                                                 rowp0->next = rowp;
00283                                                 rowp->prev = rowp0;
00284                                         }
00285                                         rowp0 = rowp;
00286                                         dtp->nrrows++;
00287                                 }
00288                                 if(c==EOF)
00289                                         break;
00290                                 crow++;
00291                                 ccol = 0;
00292                                 rowp = dbt_row_new(dtp->nrcols);
00293                                 if(!rowp)
00294                                         goto clean;
00295                                 state = DBT_DATA_ST;
00296                                 
00297                         break;
00298                         
00299                         case DBT_DATA_ST:
00300                                 //LM_DBG("state DATA!\n");
00301                                 //while(c==DBT_DELIM)
00302                                 //      c = fgetc(fin);
00303                                 if(ccol == dtp->nrcols && (c==DBT_DELIM_R || c==EOF))
00304                                 {
00305                                         state = DBT_NLINE_ST;
00306                                         break;
00307                                 }
00308                                 if(ccol>= dtp->nrcols)
00309                                         goto clean;
00310                                 
00311                                 switch(dtp->colv[ccol]->type)
00312                                 {
00313                                         case DB1_INT:
00314                                         case DB1_DATETIME:
00315                                                 //LM_DBG("INT value!\n");
00316                                                 dtval.val.int_val = 0;
00317                                                 dtval.type = dtp->colv[ccol]->type;
00318 
00319                                                 if(c==DBT_DELIM || 
00320                                                                 (ccol==dtp->nrcols-1
00321                                                                  && (c==DBT_DELIM_R || c==EOF)))
00322                                                         dtval.nul = 1;
00323                                                 else
00324                                                 {
00325                                                         dtval.nul = 0;
00326                                                         sign = 1;
00327                                                         if(c=='-')
00328                                                         {
00329                                                                 sign = -1;
00330                                                                 c = fgetc(fin);
00331                                                         }
00332                                                         if(c<'0' || c>'9')
00333                                                                 goto clean;
00334                                                         while(c>='0' && c<='9')
00335                                                         {
00336                                                                 dtval.val.int_val=dtval.val.int_val*10+c-'0';
00337                                                                 c = fgetc(fin);
00338                                                         }
00339                                                         dtval.val.int_val *= sign;
00340                                                         //LM_DBG("data[%d,%d]=%d\n", crow,
00341                                                         //      ccol, dtval.val.int_val);
00342                                                 }
00343                                                 if(c!=DBT_DELIM && c!=DBT_DELIM_R && c!=EOF)
00344                                                         goto clean;
00345                                                 if(dbt_row_set_val(rowp,&dtval,dtp->colv[ccol]->type,
00346                                                                         ccol))
00347                                                         goto clean;
00348                                                 if(ccol == dtp->auto_col)
00349                                                         max_auto = (max_auto<dtval.val.int_val)?
00350                                                                         dtval.val.int_val:max_auto;
00351                                         break;
00352                                         
00353                                         case DB1_DOUBLE:
00354                                                 //LM_DBG("DOUBLE value!\n");
00355                                                 dtval.val.double_val = 0.0;
00356                                                 dtval.type = DB1_DOUBLE;
00357 
00358                                                 if(c==DBT_DELIM || 
00359                                                                 (ccol==dtp->nrcols-1
00360                                                                  && (c==DBT_DELIM_R || c==EOF)))
00361                                                         dtval.nul = 1;
00362                                                 else
00363                                                 {
00364                                                         dtval.nul = 0;
00365                                                         sign = 1;
00366                                                         if(c=='-')
00367                                                         {
00368                                                                 sign = -1;
00369                                                                 c = fgetc(fin);
00370                                                         }
00371                                                         if(c<'0' || c>'9')
00372                                                                 goto clean;
00373                                                         while(c>='0' && c<='9')
00374                                                         {
00375                                                                 dtval.val.double_val = dtval.val.double_val*10
00376                                                                                 + c - '0';
00377                                                                 c = fgetc(fin);
00378                                                         }
00379                                                         if(c=='.')
00380                                                         {
00381                                                                 c = fgetc(fin);
00382                                                                 bp = 1;
00383                                                                 while(c>='0' && c<='9')
00384                                                                 {
00385                                                                         bp *= 10;
00386                                                                         dtval.val.double_val+=((double)(c-'0'))/bp;
00387                                                                         c = fgetc(fin);
00388                                                                 }
00389                                                         }
00390                                                         dtval.val.double_val *= sign;
00391                                                         //LM_DBG("data[%d,%d]=%10.2f\n",
00392                                                         //      crow, ccol, dtval.val.double_val);
00393                                                 }
00394                                                 if(c!=DBT_DELIM && c!=DBT_DELIM_R && c!=EOF)
00395                                                         goto clean;
00396                                                 if(dbt_row_set_val(rowp,&dtval,DB1_DOUBLE,ccol))
00397                                                         goto clean;
00398                                         break;
00399                                         
00400                                         case DB1_STR:
00401                                         case DB1_STRING:
00402                                         case DB1_BLOB:
00403                                                 //LM_DBG("STR value!\n");
00404                                                 
00405                                                 dtval.val.str_val.s = NULL;
00406                                                 dtval.val.str_val.len = 0;
00407                                                 dtval.type = dtp->colv[ccol]->type;
00408                                                 
00409                                                 bp = 0;
00410                                                 if(c==DBT_DELIM || 
00411                                                                 (ccol == dtp->nrcols-1
00412                                                                  && (c == DBT_DELIM_R || c==EOF)))
00413                                                         dtval.nul = 1;
00414                                                 else
00415                                                 {
00416                                                         dtval.nul = 0;
00417                                                         while(c!=DBT_DELIM && c!=DBT_DELIM_R && c!=EOF)
00418                                                         {
00419                                                                 if(c=='\\')
00420                                                                 {
00421                                                                         c = fgetc(fin);
00422                                                                         switch(c)
00423                                                                         {
00424                                                                                 case 'n':
00425                                                                                         c = '\n';       
00426                                                                                 break;
00427                                                                                 case 'r':
00428                                                                                         c = '\r';
00429                                                                                 break;
00430                                                                                 case 't':
00431                                                                                         c = '\t';
00432                                                                                 break;
00433                                                                                 case '\\':
00434                                                                                         c = '\\';
00435                                                                                 break;
00436                                                                                 case DBT_DELIM:
00437                                                                                         c = DBT_DELIM;
00438                                                                                 break;
00439                                                                                 case '0':
00440                                                                                         c = 0;
00441                                                                                 break;
00442                                                                                 default:
00443                                                                                         goto clean;
00444                                                                         }
00445                                                                 }
00446                                                                 buf[bp++] = c;
00447                                                                 c = fgetc(fin);
00448                                                         }
00449                                                         dtval.val.str_val.s = buf;
00450                                                         dtval.val.str_val.len = bp;
00451                                                         //LM_DBG("data[%d,%d]=%.*s\n",
00453                                                 }
00454                                                 if(c!=DBT_DELIM && c!=DBT_DELIM_R && c!=EOF)
00455                                                         goto clean;
00456                                                 if(dbt_row_set_val(rowp,&dtval,dtp->colv[ccol]->type,
00457                                                                         ccol))
00458                                                         goto clean;
00459                                         break;
00460                                         default:
00461                                                 goto clean;
00462                                 }
00463                                 if(c==DBT_DELIM)
00464                                         c = fgetc(fin);
00465                                 ccol++;
00466                         break; // state DBT_DATA_ST
00467                 }
00468         }
00469 
00470         if(max_auto)
00471                 dtp->auto_val = max_auto;
00472 
00473 done:
00474         if(fin)
00475                 fclose(fin);
00476         return dtp;
00477 clean:
00478         // ????? FILL IT IN - incomplete row/column
00479         // memory leak?!?! with last incomplete row
00480         LM_DBG("error at row=%d col=%d c=%c\n", crow+1, ccol+1, c);
00481         if(dtp)
00482                 dbt_table_free(dtp);
00483         return NULL;
00484 }
00485 
00486 
00490 int dbt_print_table(dbt_table_p _dtp, str *_dbn)
00491 {
00492         dbt_column_p colp = NULL;
00493         dbt_row_p rowp = NULL;
00494         FILE *fout = NULL;
00495         int ccol;
00496         char *p, path[512];
00497         
00498         if(!_dtp || !_dtp->name.s || _dtp->name.len <= 0)
00499                 return -1;
00500 
00501         if(!_dbn || !_dbn->s || _dbn->len <= 0)
00502         {
00503                 fout = stdout;
00504                 fprintf(fout, "\n Content of [%.*s::%.*s]\n",
00505                                 _dtp->dbname.len, _dtp->dbname.s,
00506                                 _dtp->name.len, _dtp->name.s);
00507         }
00508         else
00509         {
00510                 if(_dtp->name.len+_dbn->len > 510)
00511                         return -1;
00512                 strncpy(path, _dbn->s, _dbn->len);
00513                 path[_dbn->len] = '/';
00514                 strncpy(path+_dbn->len+1, _dtp->name.s, _dtp->name.len);
00515                 path[_dbn->len+_dtp->name.len+1] = 0;
00516                 fout = fopen(path, "wt");
00517                 if(!fout)
00518                         return -1;      
00519         }
00520         
00521         colp = _dtp->cols;
00522         while(colp)
00523         {
00524                 switch(colp->type)
00525                 {
00526                         case DB1_INT:
00527                                 fprintf(fout, "%.*s(int", colp->name.len, colp->name.s);
00528                         break;
00529                         case DB1_DOUBLE:
00530                                 fprintf(fout, "%.*s(double", colp->name.len, colp->name.s);
00531                         break;
00532                         case DB1_STR:
00533                                 fprintf(fout, "%.*s(str", colp->name.len, colp->name.s);
00534                         break;
00535                         case DB1_STRING:
00536                                 fprintf(fout, "%.*s(string", colp->name.len, colp->name.s);
00537                         break;
00538                         case DB1_BLOB:
00539                                 fprintf(fout, "%.*s(blob", colp->name.len, colp->name.s);
00540                         break;
00541                         case DB1_DATETIME:
00542                                 fprintf(fout, "%.*s(time", colp->name.len, colp->name.s);
00543                         break;
00544                         default:
00545                                 if(fout!=stdout)
00546                                         fclose(fout);
00547                                 return -1;
00548                 }
00549                 
00550                 if(colp->flag & DBT_FLAG_NULL)
00551                                 fprintf(fout,",null");
00552                 else if(colp->type==DB1_INT && colp->flag & DBT_FLAG_AUTO)
00553                                         fprintf(fout,",auto");
00554                 fprintf(fout,")");
00555                 
00556                 colp = colp->next;
00557                 if(colp)
00558                         fprintf(fout,"%c", DBT_DELIM_C);
00559         }
00560         fprintf(fout, "%c", DBT_DELIM_R);
00561         rowp = _dtp->rows;
00562         while(rowp)
00563         {
00564                 for(ccol=0; ccol<_dtp->nrcols; ccol++)
00565                 {
00566                         switch(_dtp->colv[ccol]->type)
00567                         {
00568                                 case DB1_DATETIME:
00569                                 case DB1_INT:
00570                                         if(!rowp->fields[ccol].nul)
00571                                                 fprintf(fout,"%d",
00572                                                                 rowp->fields[ccol].val.int_val);
00573                                 break;
00574                                 case DB1_DOUBLE:
00575                                         if(!rowp->fields[ccol].nul)
00576                                                 fprintf(fout, "%.2f",
00577                                                                 rowp->fields[ccol].val.double_val);
00578                                 break;
00579                                 case DB1_STR:
00580                                 case DB1_STRING:
00581                                 case DB1_BLOB:
00582                                         if(!rowp->fields[ccol].nul)
00583                                         {
00584                                                 p = rowp->fields[ccol].val.str_val.s;
00585                                                 while(p < rowp->fields[ccol].val.str_val.s
00586                                                                 + rowp->fields[ccol].val.str_val.len)
00587                                                 {
00588                                                         switch(*p)
00589                                                         {
00590                                                                 case '\n':
00591                                                                         fprintf(fout, "\\n");
00592                                                                 break;
00593                                                                 case '\r':
00594                                                                         fprintf(fout, "\\r");
00595                                                                 break;
00596                                                                 case '\t':
00597                                                                         fprintf(fout, "\\t");
00598                                                                 break;
00599                                                                 case '\\':
00600                                                                         fprintf(fout, "\\\\");
00601                                                                 break;
00602                                                                 case DBT_DELIM:
00603                                                                         fprintf(fout, "\\%c", DBT_DELIM);
00604                                                                 break;
00605                                                                 case '\0':
00606                                                                         fprintf(fout, "\\0");
00607                                                                 break;
00608                                                                 default:
00609                                                                         fprintf(fout, "%c", *p);
00610                                                         }
00611                                                         p++;
00612                                                 }
00613                                         }
00614                                 break;
00615                                 default:
00616                                         if(fout!=stdout)
00617                                                 fclose(fout);
00618                                         return -1;
00619                         }
00620                         if(ccol<_dtp->nrcols-1)
00621                                 fprintf(fout, "%c",DBT_DELIM);
00622                 }
00623                 fprintf(fout, "%c", DBT_DELIM_R);
00624                 rowp = rowp->next;
00625         }
00626         
00627         if(fout!=stdout)
00628                 fclose(fout);
00629         
00630         return 0;
00631 }
00632