dbt_file.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. /*
  2. * $Id$
  3. *
  4. * DBText library
  5. *
  6. * Copyright (C) 2001-2003 FhG Fokus
  7. *
  8. * This file is part of Kamailio, a free SIP server.
  9. *
  10. * Kamailio is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version
  14. *
  15. * Kamailio is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * History:
  25. * --------
  26. * 2003-02-03 created by Daniel
  27. *
  28. */
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <time.h>
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <dirent.h>
  35. #include "../../mem/shm_mem.h"
  36. #include "../../mem/mem.h"
  37. #include "../../dprint.h"
  38. #include "dbt_util.h"
  39. #include "dbt_lib.h"
  40. /**
  41. * -1 - error
  42. * 0 - no change
  43. * 1 - changed
  44. */
  45. int dbt_check_mtime(const str *tbn, const str *dbn, time_t *mt)
  46. {
  47. char path[512];
  48. struct stat s;
  49. int ret = 0;
  50. path[0] = 0;
  51. if(dbn && dbn->s && dbn->len>0)
  52. {
  53. if(dbn->len+tbn->len<511)
  54. {
  55. strncpy(path, dbn->s, dbn->len);
  56. path[dbn->len] = '/';
  57. strncpy(path+dbn->len+1, tbn->s, tbn->len);
  58. path[dbn->len+tbn->len+1] = 0;
  59. }
  60. }
  61. if(path[0] == 0)
  62. {
  63. strncpy(path, tbn->s, tbn->len);
  64. path[tbn->len] = 0;
  65. }
  66. if(stat(path, &s) == 0)
  67. {
  68. if((int)s.st_mtime > (int)*mt)
  69. {
  70. ret = 1;
  71. *mt = s.st_mtime;
  72. LM_DBG("[%.*s] was updated\n", tbn->len, tbn->s);
  73. }
  74. } else {
  75. LM_DBG("stat failed on [%.*s]\n", tbn->len, tbn->s);
  76. ret = -1;
  77. }
  78. return ret;
  79. }
  80. /**
  81. *
  82. */
  83. dbt_table_p dbt_load_file(const str *tbn, const str *dbn)
  84. {
  85. FILE *fin=NULL;
  86. char path[512], buf[4096];
  87. int c, crow, ccol, bp, sign, max_auto;
  88. dbt_val_t dtval;
  89. dbt_table_p dtp = NULL;
  90. dbt_column_p colp, colp0 = NULL;
  91. dbt_row_p rowp, rowp0 = NULL;
  92. enum {DBT_FLINE_ST, DBT_NLINE_ST, DBT_DATA_ST} state;
  93. LM_DBG("request for table [%.*s]\n", tbn->len, tbn->s);
  94. if(!tbn || !tbn->s || tbn->len<=0 || tbn->len>=255)
  95. return NULL;
  96. path[0] = 0;
  97. if(dbn && dbn->s && dbn->len>0)
  98. {
  99. LM_DBG("db is [%.*s]\n", dbn->len, dbn->s);
  100. if(dbn->len+tbn->len<511)
  101. {
  102. strncpy(path, dbn->s, dbn->len);
  103. path[dbn->len] = '/';
  104. strncpy(path+dbn->len+1, tbn->s, tbn->len);
  105. path[dbn->len+tbn->len+1] = 0;
  106. }
  107. }
  108. if(path[0] == 0)
  109. {
  110. strncpy(path, tbn->s, tbn->len);
  111. path[tbn->len] = 0;
  112. }
  113. LM_DBG("loading file [%s]\n", path);
  114. fin = fopen(path, "rt");
  115. if(!fin)
  116. return NULL;
  117. dtp = dbt_table_new(tbn, dbn, path);
  118. if(!dtp)
  119. goto done;
  120. state = DBT_FLINE_ST;
  121. crow = ccol = -1;
  122. colp = colp0 = NULL;
  123. rowp = rowp0 = NULL;
  124. c = fgetc(fin);
  125. max_auto = 0;
  126. while(c!=EOF)
  127. {
  128. switch(state)
  129. {
  130. case DBT_FLINE_ST:
  131. //LM_DBG("state FLINE!\n");
  132. bp = 0;
  133. while(c==DBT_DELIM_C)
  134. c = fgetc(fin);
  135. if(c==DBT_DELIM_R && !colp0)
  136. goto clean;
  137. if(c==DBT_DELIM_R)
  138. {
  139. if(dtp->nrcols <= 0)
  140. goto clean;
  141. dtp->colv = (dbt_column_p*)
  142. shm_malloc(dtp->nrcols*sizeof(dbt_column_p));
  143. if(!dtp->colv)
  144. goto clean;
  145. colp0 = dtp->cols;
  146. for(ccol=0; ccol<dtp->nrcols && colp0; ccol++)
  147. {
  148. dtp->colv[ccol] = colp0;
  149. colp0 = colp0->next;
  150. }
  151. state = DBT_NLINE_ST;
  152. break;
  153. }
  154. while(c!=DBT_DELIM_C && c!='(' && c!=DBT_DELIM_R)
  155. {
  156. if(c==EOF)
  157. goto clean;
  158. buf[bp++] = c;
  159. c = fgetc(fin);
  160. }
  161. colp = dbt_column_new(buf, bp);
  162. if(!colp)
  163. goto clean;
  164. //LM_DBG("new col [%.*s]\n", bp, buf);
  165. while(c==DBT_DELIM_C)
  166. c = fgetc(fin);
  167. if(c!='(')
  168. goto clean;
  169. c = fgetc(fin);
  170. while(c==DBT_DELIM_C)
  171. c = fgetc(fin);
  172. switch(c)
  173. {
  174. case 's':
  175. case 'S':
  176. colp->type = DB1_STR;
  177. LM_DBG("column[%d] is STR!\n", ccol+1);
  178. break;
  179. case 'i':
  180. case 'I':
  181. colp->type = DB1_INT;
  182. LM_DBG("column[%d] is INT!\n", ccol+1);
  183. break;
  184. case 'd':
  185. case 'D':
  186. colp->type = DB1_DOUBLE;
  187. LM_DBG("column[%d] is DOUBLE!\n", ccol+1);
  188. break;
  189. case 'b':
  190. case 'B':
  191. colp->type = DB1_BLOB;
  192. LM_DBG("column[%d] is BLOB!\n", ccol+1);
  193. break;
  194. case 't':
  195. case 'T':
  196. colp->type = DB1_DATETIME;
  197. LM_DBG("column[%d] is TIME!\n", ccol+1);
  198. break;
  199. default:
  200. LM_DBG("wrong column type!\n");
  201. goto clean;
  202. }
  203. while(c!='\n' && c!=EOF && c!=')' && c!= ',')
  204. {
  205. if(colp->type == DB1_STR && (c=='i'|| c=='I'))
  206. {
  207. colp->type = DB1_STRING;
  208. LM_DBG("column[%d] is actually STRING!\n", ccol+1);
  209. }
  210. c = fgetc(fin);
  211. }
  212. if(c==',')
  213. {
  214. //LM_DBG("c=%c!\n", c);
  215. c = fgetc(fin);
  216. while(c==DBT_DELIM_C)
  217. c = fgetc(fin);
  218. if(c=='N' || c=='n')
  219. {
  220. //LM_DBG("NULL flag set!\n");
  221. colp->flag |= DBT_FLAG_NULL;
  222. }
  223. else if(colp->type==DB1_INT && dtp->auto_col<0
  224. && (c=='A' || c=='a'))
  225. {
  226. //LM_DBG("AUTO flag set!\n");
  227. colp->flag |= DBT_FLAG_AUTO;
  228. dtp->auto_col = ccol+1;
  229. }
  230. else
  231. goto clean;
  232. while(c!=')' && c!=DBT_DELIM_R && c!=EOF)
  233. c = fgetc(fin);
  234. }
  235. if(c == ')')
  236. {
  237. //LM_DBG("c=%c!\n", c);
  238. if(colp0)
  239. {
  240. colp->prev = colp0;
  241. colp0->next = colp;
  242. }
  243. else
  244. dtp->cols = colp;
  245. colp0 = colp;
  246. dtp->nrcols++;
  247. c = fgetc(fin);
  248. }
  249. else
  250. goto clean;
  251. ccol++;
  252. break;
  253. case DBT_NLINE_ST:
  254. //LM_DBG("state NLINE!\n");
  255. while(c==DBT_DELIM_R)
  256. c = fgetc(fin);
  257. if(rowp)
  258. {
  259. if(dbt_table_check_row(dtp, rowp))
  260. goto clean;
  261. if(!rowp0)
  262. dtp->rows = rowp;
  263. else
  264. {
  265. rowp0->next = rowp;
  266. rowp->prev = rowp0;
  267. }
  268. rowp0 = rowp;
  269. dtp->nrrows++;
  270. }
  271. if(c==EOF)
  272. break;
  273. crow++;
  274. ccol = 0;
  275. rowp = dbt_row_new(dtp->nrcols);
  276. if(!rowp)
  277. goto clean;
  278. state = DBT_DATA_ST;
  279. break;
  280. case DBT_DATA_ST:
  281. //LM_DBG("state DATA!\n");
  282. //while(c==DBT_DELIM)
  283. // c = fgetc(fin);
  284. if(ccol == dtp->nrcols && (c==DBT_DELIM_R || c==EOF))
  285. {
  286. state = DBT_NLINE_ST;
  287. break;
  288. }
  289. if(ccol>= dtp->nrcols)
  290. goto clean;
  291. switch(dtp->colv[ccol]->type)
  292. {
  293. case DB1_INT:
  294. case DB1_DATETIME:
  295. //LM_DBG("INT value!\n");
  296. dtval.val.int_val = 0;
  297. dtval.type = dtp->colv[ccol]->type;
  298. if(c==DBT_DELIM ||
  299. (ccol==dtp->nrcols-1
  300. && (c==DBT_DELIM_R || c==EOF)))
  301. dtval.nul = 1;
  302. else
  303. {
  304. dtval.nul = 0;
  305. sign = 1;
  306. if(c=='-')
  307. {
  308. sign = -1;
  309. c = fgetc(fin);
  310. }
  311. if(c<'0' || c>'9')
  312. goto clean;
  313. while(c>='0' && c<='9')
  314. {
  315. dtval.val.int_val=dtval.val.int_val*10+c-'0';
  316. c = fgetc(fin);
  317. }
  318. dtval.val.int_val *= sign;
  319. //LM_DBG("data[%d,%d]=%d\n", crow,
  320. // ccol, dtval.val.int_val);
  321. }
  322. if(c!=DBT_DELIM && c!=DBT_DELIM_R && c!=EOF)
  323. goto clean;
  324. if(dbt_row_set_val(rowp,&dtval,dtp->colv[ccol]->type,
  325. ccol))
  326. goto clean;
  327. if(ccol == dtp->auto_col)
  328. max_auto = (max_auto<dtval.val.int_val)?
  329. dtval.val.int_val:max_auto;
  330. break;
  331. case DB1_DOUBLE:
  332. //LM_DBG("DOUBLE value!\n");
  333. dtval.val.double_val = 0.0;
  334. dtval.type = DB1_DOUBLE;
  335. if(c==DBT_DELIM ||
  336. (ccol==dtp->nrcols-1
  337. && (c==DBT_DELIM_R || c==EOF)))
  338. dtval.nul = 1;
  339. else
  340. {
  341. dtval.nul = 0;
  342. sign = 1;
  343. if(c=='-')
  344. {
  345. sign = -1;
  346. c = fgetc(fin);
  347. }
  348. if(c<'0' || c>'9')
  349. goto clean;
  350. while(c>='0' && c<='9')
  351. {
  352. dtval.val.double_val = dtval.val.double_val*10
  353. + c - '0';
  354. c = fgetc(fin);
  355. }
  356. if(c=='.')
  357. {
  358. c = fgetc(fin);
  359. bp = 1;
  360. while(c>='0' && c<='9')
  361. {
  362. bp *= 10;
  363. dtval.val.double_val+=((double)(c-'0'))/bp;
  364. c = fgetc(fin);
  365. }
  366. }
  367. dtval.val.double_val *= sign;
  368. //LM_DBG("data[%d,%d]=%10.2f\n",
  369. // crow, ccol, dtval.val.double_val);
  370. }
  371. if(c!=DBT_DELIM && c!=DBT_DELIM_R && c!=EOF)
  372. goto clean;
  373. if(dbt_row_set_val(rowp,&dtval,DB1_DOUBLE,ccol))
  374. goto clean;
  375. break;
  376. case DB1_STR:
  377. case DB1_STRING:
  378. case DB1_BLOB:
  379. //LM_DBG("STR value!\n");
  380. dtval.val.str_val.s = NULL;
  381. dtval.val.str_val.len = 0;
  382. dtval.type = dtp->colv[ccol]->type;
  383. bp = 0;
  384. if(c==DBT_DELIM ||
  385. (ccol == dtp->nrcols-1
  386. && (c == DBT_DELIM_R || c==EOF)))
  387. dtval.nul = 1;
  388. else
  389. {
  390. dtval.nul = 0;
  391. while(c!=DBT_DELIM && c!=DBT_DELIM_R && c!=EOF)
  392. {
  393. if(c=='\\')
  394. {
  395. c = fgetc(fin);
  396. switch(c)
  397. {
  398. case 'n':
  399. c = '\n';
  400. break;
  401. case 'r':
  402. c = '\r';
  403. break;
  404. case 't':
  405. c = '\t';
  406. break;
  407. case '\\':
  408. c = '\\';
  409. break;
  410. case DBT_DELIM:
  411. c = DBT_DELIM;
  412. break;
  413. case '0':
  414. c = 0;
  415. break;
  416. default:
  417. goto clean;
  418. }
  419. }
  420. buf[bp++] = c;
  421. c = fgetc(fin);
  422. }
  423. dtval.val.str_val.s = buf;
  424. dtval.val.str_val.len = bp;
  425. //LM_DBG("data[%d,%d]=%.*s\n",
  426. /// crow, ccol, bp, buf);
  427. }
  428. if(c!=DBT_DELIM && c!=DBT_DELIM_R && c!=EOF)
  429. goto clean;
  430. if(dbt_row_set_val(rowp,&dtval,dtp->colv[ccol]->type,
  431. ccol))
  432. goto clean;
  433. break;
  434. default:
  435. goto clean;
  436. }
  437. if(c==DBT_DELIM)
  438. c = fgetc(fin);
  439. ccol++;
  440. break; // state DBT_DATA_ST
  441. }
  442. }
  443. if(max_auto)
  444. dtp->auto_val = max_auto;
  445. done:
  446. if(fin)
  447. fclose(fin);
  448. return dtp;
  449. clean:
  450. // ????? FILL IT IN - incomplete row/column
  451. // memory leak?!?! with last incomplete row
  452. LM_DBG("error at row=%d col=%d c=%c\n", crow+1, ccol+1, c);
  453. if(dtp)
  454. dbt_table_free(dtp);
  455. return NULL;
  456. }
  457. /**
  458. *
  459. */
  460. int dbt_print_table(dbt_table_p _dtp, str *_dbn)
  461. {
  462. dbt_column_p colp = NULL;
  463. dbt_row_p rowp = NULL;
  464. FILE *fout = NULL;
  465. int ccol;
  466. char *p, path[512];
  467. if(!_dtp || !_dtp->name.s || _dtp->name.len <= 0)
  468. return -1;
  469. if(!_dbn || !_dbn->s || _dbn->len <= 0)
  470. {
  471. fout = stdout;
  472. fprintf(fout, "\n Content of [%.*s::%.*s]\n",
  473. _dtp->dbname.len, _dtp->dbname.s,
  474. _dtp->name.len, _dtp->name.s);
  475. }
  476. else
  477. {
  478. if(_dtp->name.len+_dbn->len > 510)
  479. return -1;
  480. strncpy(path, _dbn->s, _dbn->len);
  481. path[_dbn->len] = '/';
  482. strncpy(path+_dbn->len+1, _dtp->name.s, _dtp->name.len);
  483. path[_dbn->len+_dtp->name.len+1] = 0;
  484. fout = fopen(path, "wt");
  485. if(!fout)
  486. return -1;
  487. }
  488. colp = _dtp->cols;
  489. while(colp)
  490. {
  491. switch(colp->type)
  492. {
  493. case DB1_INT:
  494. fprintf(fout, "%.*s(int", colp->name.len, colp->name.s);
  495. break;
  496. case DB1_DOUBLE:
  497. fprintf(fout, "%.*s(double", colp->name.len, colp->name.s);
  498. break;
  499. case DB1_STR:
  500. fprintf(fout, "%.*s(str", colp->name.len, colp->name.s);
  501. break;
  502. case DB1_STRING:
  503. fprintf(fout, "%.*s(string", colp->name.len, colp->name.s);
  504. break;
  505. case DB1_BLOB:
  506. fprintf(fout, "%.*s(blob", colp->name.len, colp->name.s);
  507. break;
  508. case DB1_DATETIME:
  509. fprintf(fout, "%.*s(time", colp->name.len, colp->name.s);
  510. break;
  511. default:
  512. if(fout!=stdout)
  513. fclose(fout);
  514. return -1;
  515. }
  516. if(colp->flag & DBT_FLAG_NULL)
  517. fprintf(fout,",null");
  518. else if(colp->type==DB1_INT && colp->flag & DBT_FLAG_AUTO)
  519. fprintf(fout,",auto");
  520. fprintf(fout,")");
  521. colp = colp->next;
  522. if(colp)
  523. fprintf(fout,"%c", DBT_DELIM_C);
  524. }
  525. fprintf(fout, "%c", DBT_DELIM_R);
  526. rowp = _dtp->rows;
  527. while(rowp)
  528. {
  529. for(ccol=0; ccol<_dtp->nrcols; ccol++)
  530. {
  531. switch(_dtp->colv[ccol]->type)
  532. {
  533. case DB1_DATETIME:
  534. case DB1_INT:
  535. if(!rowp->fields[ccol].nul)
  536. fprintf(fout,"%d",
  537. rowp->fields[ccol].val.int_val);
  538. break;
  539. case DB1_DOUBLE:
  540. if(!rowp->fields[ccol].nul)
  541. fprintf(fout, "%.2f",
  542. rowp->fields[ccol].val.double_val);
  543. break;
  544. case DB1_STR:
  545. case DB1_STRING:
  546. case DB1_BLOB:
  547. if(!rowp->fields[ccol].nul)
  548. {
  549. p = rowp->fields[ccol].val.str_val.s;
  550. while(p < rowp->fields[ccol].val.str_val.s
  551. + rowp->fields[ccol].val.str_val.len)
  552. {
  553. switch(*p)
  554. {
  555. case '\n':
  556. fprintf(fout, "\\n");
  557. break;
  558. case '\r':
  559. fprintf(fout, "\\r");
  560. break;
  561. case '\t':
  562. fprintf(fout, "\\t");
  563. break;
  564. case '\\':
  565. fprintf(fout, "\\\\");
  566. break;
  567. case DBT_DELIM:
  568. fprintf(fout, "\\%c", DBT_DELIM);
  569. break;
  570. case '\0':
  571. fprintf(fout, "\\0");
  572. break;
  573. default:
  574. fprintf(fout, "%c", *p);
  575. }
  576. p++;
  577. }
  578. }
  579. break;
  580. default:
  581. if(fout!=stdout)
  582. fclose(fout);
  583. return -1;
  584. }
  585. if(ccol<_dtp->nrcols-1)
  586. fprintf(fout, "%c",DBT_DELIM);
  587. }
  588. fprintf(fout, "%c", DBT_DELIM_R);
  589. rowp = rowp->next;
  590. }
  591. if(fout!=stdout)
  592. fclose(fout);
  593. return 0;
  594. }