parser.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. #ident "@(#)parser.c 1.5 01/04/11"
  2. /** BEGIN COPYRIGHT BLOCK
  3. * This Program is free software; you can redistribute it and/or modify it under
  4. * the terms of the GNU General Public License as published by the Free Software
  5. * Foundation; version 2 of the License.
  6. *
  7. * This Program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  10. *
  11. * You should have received a copy of the GNU General Public License along with
  12. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  13. * Place, Suite 330, Boston, MA 02111-1307 USA.
  14. *
  15. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  16. * right to link the code of this Program with code not covered under the GNU
  17. * General Public License ("Non-GPL Code") and to distribute linked combinations
  18. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  19. * permitted under this exception must only link to the code of this Program
  20. * through those well defined interfaces identified in the file named EXCEPTION
  21. * found in the source code files (the "Approved Interfaces"). The files of
  22. * Non-GPL Code may instantiate templates or use macros or inline functions from
  23. * the Approved Interfaces without causing the resulting work to be covered by
  24. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  25. * additions to the list of Approved Interfaces. You must obey the GNU General
  26. * Public License in all respects for all of the Program code and other code used
  27. * in conjunction with the Program except the Non-GPL Code covered by this
  28. * exception. If you modify this file, you may extend this exception to your
  29. * version of the file, but you are not obligated to do so. If you do not wish to
  30. * provide this exception without modification, you must delete this exception
  31. * statement from your version and license this file solely under the GPL without
  32. * exception.
  33. *
  34. *
  35. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  36. * Copyright (C) 2006 Red Hat, Inc.
  37. * All rights reserved.
  38. * END COPYRIGHT BLOCK **/
  39. #ifdef HAVE_CONFIG_H
  40. # include <config.h>
  41. #endif
  42. /*
  43. FILE : parser.c
  44. AUTHOR : Jean-Luc SCHWING
  45. VERSION : 1.0
  46. DATE : 19 March 2001
  47. DESCRIPTION :
  48. This file contains the parser functions of ldclt
  49. LOCAL : None.
  50. HISTORY :
  51. ---------+--------------+------------------------------------------------------
  52. dd/mm/yy | Author | Comments
  53. ---------+--------------+------------------------------------------------------
  54. 19/03/01 | JL Schwing | Creation
  55. ---------+--------------+------------------------------------------------------
  56. 21/03/01 | JL Schwing | 1.2 : Implements variables in "-e object=filename"
  57. ---------+--------------+------------------------------------------------------
  58. 23/03/01 | JL Schwing | 1.3 : Implements data file list support in variants.
  59. | Bug fix : close the file !
  60. | Implements "-e rdn=value".
  61. ---------+--------------+------------------------------------------------------
  62. 28/03/01 | JL Schwing | 1.4 : Support -e commoncounter with -e rdn/object
  63. ---------+--------------+------------------------------------------------------
  64. 11/04/01 | JL Schwing | 1.5 : Implement [INCRFROMFILE<NOLOOP>(myfile)]
  65. | Improved error message.
  66. ---------+--------------+------------------------------------------------------
  67. */
  68. #include <stdio.h> /* printf(), etc... */
  69. #include <string.h> /* strcpy(), etc... */
  70. #include <errno.h> /* errno, etc... */
  71. #include <stdlib.h> /* malloc(), etc... */
  72. #include <lber.h> /* ldap C-API BER declarations */
  73. #include <ldap.h> /* ldap C-API declarations */
  74. #ifdef LDAP_H_FROM_QA_WKA
  75. #include <proto-ldap.h> /* ldap C-API prototypes */
  76. #endif
  77. #ifndef _WIN32
  78. #include <unistd.h> /* close(), etc... */
  79. #include <pthread.h> /* pthreads(), etc... */
  80. #endif
  81. #include "port.h" /* Portability definitions */
  82. #include "ldclt.h" /* This tool's include file */
  83. #include "utils.h" /* Utilities functions */
  84. /* ****************************************************************************
  85. FUNCTION : decodeHow
  86. PURPOSE : Decode the how field
  87. INPUT : how = field to decode
  88. OUTPUT : None.
  89. RETURN : -1 if error, how value else.
  90. DESCRIPTION :
  91. *****************************************************************************/
  92. int
  93. decodeHow (
  94. char *how)
  95. {
  96. if (mctx.mode & VERY_VERBOSE)
  97. printf ("decodeHow: how=\"%s\"\n", how);
  98. if (!strcmp (how, "INCRFROMFILE")) return (HOW_INCR_FROM_FILE);
  99. if (!strcmp (how, "INCRFROMFILENOLOOP")) return (HOW_INCR_FROM_FILE_NL);
  100. if (!strcmp (how, "INCRN")) return (HOW_INCR_NB);
  101. if (!strcmp (how, "INCRNNOLOOP")) return (HOW_INCR_NB_NOLOOP);
  102. if (!strcmp (how, "RNDFROMFILE")) return (HOW_RND_FROM_FILE);
  103. if (!strcmp (how, "RNDN")) return (HOW_RND_NUMBER);
  104. if (!strcmp (how, "RNDS")) return (HOW_RND_STRING);
  105. return (-1);
  106. }
  107. /* ****************************************************************************
  108. FUNCTION : parseVariant
  109. PURPOSE : Parse a variant definition.
  110. INPUT : variant = string to parse
  111. fname = file name
  112. line = source line
  113. obj = object we are parsing and building
  114. OUTPUT : field = field parsed
  115. RETURN : -1 if error, 0 else.
  116. DESCRIPTION :
  117. *****************************************************************************/
  118. int
  119. parseVariant (
  120. char *variant,
  121. char *fname,
  122. char *line,
  123. vers_object *obj,
  124. vers_field *field)
  125. {
  126. int start, end; /* For the loops */
  127. char how[MAX_FILTER]; /* To parse the variant : */
  128. char first[MAX_FILTER]; /* how(first) */
  129. char second[MAX_FILTER]; /* how(first,second) */
  130. char third[MAX_FILTER]; /* how(first,second,third) */
  131. int ret; /* ldclt_mutex_init() return value */
  132. if (mctx.mode & VERY_VERBOSE)
  133. printf ("parseVariant: variant=\"%s\"\n", variant);
  134. /*
  135. * Maybe a variable ?
  136. */
  137. if (variant[1] == '\0')
  138. {
  139. if ((variant[0] < VAR_MIN) || (variant[0] > VAR_MAX))
  140. {
  141. fprintf (stderr, "Error: bad variable in %s : \"%s\"\n", fname, line);
  142. fprintf (stderr, "Error: must be in [%c-%c]\n", VAR_MIN, VAR_MAX);
  143. return (-1);
  144. }
  145. field->how = HOW_VARIABLE;
  146. field->var = variant[0] - VAR_MIN;
  147. return (0);
  148. }
  149. /*
  150. * Maybe a variable definition ?
  151. */
  152. if (variant[1] != '=')
  153. field->var = -1;
  154. else
  155. {
  156. if ((variant[0] < VAR_MIN) || (variant[0] > VAR_MAX))
  157. {
  158. fprintf (stderr, "Error: bad variable in %s : \"%s\"\n", fname, line);
  159. fprintf (stderr, "Error: must be in [%c-%c]\n", VAR_MIN, VAR_MAX);
  160. return (-1);
  161. }
  162. field->var = variant[0] - VAR_MIN;
  163. variant++; /* Skip variable name */
  164. variant++; /* Skip '=' */
  165. /*
  166. * We need a variable !
  167. */
  168. if (obj->var[field->var] == NULL)
  169. obj->var[field->var] = (char *) malloc (MAX_FILTER);
  170. }
  171. /*
  172. * Find how definition
  173. */
  174. for (end=0 ; (variant[end]!='\0') && (variant[end]!='(') ; end++);
  175. if (variant[end]=='\0')
  176. {
  177. fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
  178. fprintf (stderr, "Error: missing '('\n");
  179. return (-1);
  180. }
  181. strncpy (how, variant, end);
  182. how[end] = '\0';
  183. /*
  184. * Parse the first parameter
  185. */
  186. end++; /* Skip '(' */
  187. for (start=end ; (variant[end]!='\0') && (variant[end]!=';')
  188. && (variant[end]!=')') ; end++);
  189. if (variant[end]=='\0')
  190. {
  191. fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
  192. fprintf (stderr, "Error: missing ')'\n");
  193. return (-1);
  194. }
  195. strncpy (first, variant+start, end-start);
  196. first[end-start] = '\0';
  197. /*
  198. * Parse the second parameter
  199. */
  200. if (variant[end] == ')')
  201. second[0] = '\0';
  202. else
  203. {
  204. end++; /* Skip ';' */
  205. for (start=end ; (variant[end]!='\0') && (variant[end]!=';')
  206. && (variant[end]!=')') ; end++);
  207. if (variant[end]=='\0')
  208. {
  209. fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
  210. fprintf (stderr, "Error: missing ')'\n");
  211. return (-1);
  212. }
  213. strncpy (second, variant+start, end-start);
  214. second[end-start] = '\0';
  215. }
  216. /*
  217. * Parse the third parameter
  218. */
  219. if (variant[end]==')')
  220. third[0]='\0';
  221. else
  222. {
  223. end++; /* Skip ';' */
  224. for (start=end ; (variant[end]!='\0') && (variant[end]!=')') ; end++);
  225. if (variant[end]=='\0')
  226. {
  227. fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
  228. fprintf (stderr, "Error: missing ')'\n");
  229. return (-1);
  230. }
  231. strncpy (third, variant+start, end-start);
  232. third[end-start] = '\0';
  233. }
  234. /*
  235. * Analyse it
  236. * Note : first parameter always exist (detected when parsing) while
  237. * second and third may not have been provided by the user.
  238. */
  239. switch (field->how = decodeHow (how))
  240. {
  241. case HOW_INCR_FROM_FILE:
  242. case HOW_INCR_FROM_FILE_NL:
  243. case HOW_RND_FROM_FILE:
  244. if ((field->dlf = dataListFile (first)) == NULL)
  245. {
  246. fprintf (stderr, "Error : bad file in %s : \"%s\"\n", fname, line);
  247. return (-1);
  248. }
  249. /*
  250. * Useless for HOW_RND_FROM_FILE
  251. */
  252. field->cnt = 0;
  253. field->low = 0;
  254. field->high = field->dlf->strNb - 1;
  255. /*
  256. * Maybe common counter ?
  257. */
  258. if ((mctx.mode & COMMON_COUNTER) &&
  259. ((field->how == HOW_INCR_FROM_FILE) ||
  260. (field->how == HOW_INCR_FROM_FILE_NL)))
  261. {
  262. if ((ret = ldclt_mutex_init (&(field->cnt_mutex))) != 0)
  263. {
  264. fprintf (stderr, "ldclt: %s\n", strerror (ret));
  265. fprintf (stderr, "Error: cannot initiate cnt_mutex in %s for %s\n",
  266. fname, line);
  267. fflush (stderr);
  268. return (-1);
  269. }
  270. }
  271. break;
  272. case HOW_INCR_NB:
  273. case HOW_INCR_NB_NOLOOP:
  274. case HOW_RND_NUMBER:
  275. if (third[0] == '\0')
  276. {
  277. fprintf (stderr, "Error : missing parameters in %s : \"%s\"\n",
  278. fname, line);
  279. return (-1);
  280. }
  281. field->cnt = atoi (first);
  282. field->low = atoi (first);
  283. field->high = atoi (second);
  284. field->nb = atoi (third);
  285. /*
  286. * Maybe common counter ?
  287. */
  288. if ((mctx.mode & COMMON_COUNTER) &&
  289. ((field->how == HOW_INCR_NB) || (field->how == HOW_INCR_NB_NOLOOP)))
  290. {
  291. if ((ret = ldclt_mutex_init (&(field->cnt_mutex))) != 0)
  292. {
  293. fprintf (stderr, "ldclt: %s\n", strerror (ret));
  294. fprintf (stderr, "Error: cannot initiate cnt_mutex in %s for %s\n",
  295. fname, line);
  296. fflush (stderr);
  297. return (-1);
  298. }
  299. }
  300. break;
  301. case HOW_RND_STRING:
  302. field->nb = atoi (first);
  303. break;
  304. case -1:
  305. fprintf (stderr, "Error: illegal keyword \"%s\" in %s : \"%s\"\n",
  306. how, fname, line);
  307. return (-1);
  308. break;
  309. }
  310. return (0);
  311. }
  312. /* ****************************************************************************
  313. FUNCTION : parseAttribValue
  314. PURPOSE : Parse the right part of attribname: attribvalue.
  315. INPUT : fname = file name
  316. obj = object where variables are.
  317. line = value to parse.
  318. OUTPUT : attrib = attribute where the value should be stored
  319. RETURN : -1 if error, 0 else.
  320. DESCRIPTION :
  321. *****************************************************************************/
  322. int
  323. parseAttribValue (
  324. char *fname,
  325. vers_object *obj,
  326. char *line,
  327. vers_attribute *attrib)
  328. {
  329. char variant[MAX_FILTER]; /* To process the variant */
  330. int start, end; /* For the loops */
  331. vers_field *field; /* To build the fields */
  332. if (mctx.mode & VERY_VERBOSE)
  333. printf ("parseAttribValue: line=\"%s\"\n", line);
  334. /*
  335. * We will now parse this line for the different fields.
  336. */
  337. field = NULL;
  338. end = start = 0;
  339. while (line[end]!='\0')
  340. {
  341. /*
  342. * Allocate a new field
  343. */
  344. if (field == NULL)
  345. {
  346. field = (vers_field *) malloc (sizeof (vers_field));
  347. field->next = NULL;
  348. attrib->field = field;
  349. }
  350. else
  351. {
  352. field->next = (vers_field *) malloc (sizeof (vers_field));
  353. field = field->next;
  354. field->next = NULL;
  355. }
  356. /*
  357. * Is it a variant field ?
  358. */
  359. if (line[end] == '[')
  360. {
  361. /*
  362. * Extract the variant definition
  363. */
  364. end++; /* Skip '[' */
  365. for (start=end ; (line[end]!='\0') && (line[end]!=']') ; end++);
  366. strncpy (variant, line+start, end-start);
  367. variant[end-start] = '\0';
  368. if (line[end]=='\0')
  369. {
  370. fprintf (stderr, "Error: missing ']' in %s : \"%s\"\n", fname, line);
  371. return (-1);
  372. }
  373. if (parseVariant (variant, fname, line, obj, field) < 0)
  374. return (-1);
  375. end++; /* Skip ']' */
  376. /*
  377. * We need to allocate a buffer in this attribute !
  378. */
  379. if (attrib->buf == NULL)
  380. {
  381. attrib->buf = (char *) malloc (MAX_FILTER);
  382. if (mctx.mode & VERY_VERBOSE)
  383. printf ("parseAttribValue: buffer allocated\n");
  384. }
  385. }
  386. else
  387. {
  388. /*
  389. * It is a constant field. Find the end : [ or \0
  390. */
  391. for (start=end ; (line[end]!='\0') && (line[end]!='[') ; end++);
  392. field->how = HOW_CONSTANT;
  393. field->cst = (char *) malloc (1+end-start);
  394. strncpy (field->cst, line+start, end-start);
  395. field->cst[end-start] = '\0';
  396. }
  397. }
  398. /*
  399. * Attribute value is parsed !
  400. */
  401. return (0);
  402. }
  403. /* ****************************************************************************
  404. FUNCTION : parseLine
  405. PURPOSE : Parse the given line to find an attribute definition.
  406. INPUT : line = line to parse
  407. fname = file name
  408. OUTPUT : obj = object where the attribute should be added
  409. RETURN : -1 if error, 0 else.
  410. DESCRIPTION :
  411. *****************************************************************************/
  412. int
  413. parseLine (
  414. char *line,
  415. char *fname,
  416. vers_object *obj)
  417. {
  418. int end; /* For the loops */
  419. if (mctx.mode & VERY_VERBOSE)
  420. printf ("parseLine: line=\"%s\"\n", line);
  421. /*
  422. * Empty line ? Comment ?
  423. * No more place for new attributes ?
  424. */
  425. if ((line[0]=='\0') || (line[0]=='#'))
  426. return (0);
  427. if (obj->attribsNb == MAX_ATTRIBS)
  428. {
  429. fprintf (stderr, "Error: too many attributes in %s, max is %d\n",
  430. fname, MAX_ATTRIBS);
  431. return (-1);
  432. }
  433. /*
  434. * Find the attribute name
  435. * name:
  436. */
  437. for (end=0 ; (line[end]!='\0') && (line[end]!=':') ; end++);
  438. if (line[end]!=':')
  439. {
  440. fprintf (stderr, "Error: can't find attribute name in %s : \"%s\"\n",
  441. fname, line);
  442. return (-1);
  443. }
  444. /*
  445. * Initiate the attribute
  446. */
  447. obj->attribs[obj->attribsNb].buf = NULL;
  448. obj->attribs[obj->attribsNb].src = strdup (line);
  449. obj->attribs[obj->attribsNb].name = (char *) malloc (1+end);
  450. strncpy (obj->attribs[obj->attribsNb].name, line, end);
  451. obj->attribs[obj->attribsNb].name[end] = '\0';
  452. for (end++ ; line[end]==' ' ; end++); /* Skip the leading ' ' */
  453. /*
  454. * We will now parse the value of this attribute
  455. */
  456. if (parseAttribValue(fname,obj, line+end, &(obj->attribs[obj->attribsNb]))<0)
  457. return (-1);
  458. /*
  459. * Do not forget to increment attributes number !
  460. */
  461. obj->attribsNb++;
  462. return (0);
  463. }
  464. /* ****************************************************************************
  465. FUNCTION : readObject
  466. PURPOSE : This function will read an object description from the
  467. file given in argument.
  468. The object should be already initiated !!!
  469. INPUT : None.
  470. OUTPUT : obj = parsed object.
  471. RETURN : -1 if error, 0 else.
  472. DESCRIPTION :
  473. *****************************************************************************/
  474. int
  475. readObject (
  476. vers_object *obj)
  477. {
  478. FILE *ifile; /* The file that contains the object to read */
  479. char line[MAX_FILTER]; /* To read ifile */
  480. int rc = 0;
  481. /*
  482. * Open the file
  483. */
  484. ifile = fopen (obj->fname, "r");
  485. if (ifile == NULL)
  486. {
  487. perror (obj->fname);
  488. fprintf (stderr, "Error: cannot open file \"%s\"\n", obj->fname);
  489. rc = -1;
  490. goto done;
  491. }
  492. /*
  493. * Process each line of the input file.
  494. * Reminder : the object is initiated by the calling function !
  495. */
  496. while (fgets (line, MAX_FILTER, ifile) != NULL)
  497. {
  498. if ((strlen (line) > 0) && (line[strlen(line)-1]=='\n'))
  499. line[strlen(line)-1] = '\0';
  500. if (parseLine (line, obj->fname, obj) < 0) {
  501. rc = -1;
  502. goto done;
  503. }
  504. }
  505. done:
  506. /*
  507. * Do not forget to close the file !
  508. */
  509. if (ifile && fclose (ifile) != 0)
  510. {
  511. perror (obj->fname);
  512. fprintf (stderr, "Error: cannot fclose file \"%s\"\n", obj->fname);
  513. rc = -1;
  514. }
  515. /*
  516. * End of function
  517. */
  518. if (obj->attribsNb == 0)
  519. {
  520. fprintf (stderr, "Error: no object found in \"%s\"\n", obj->fname);
  521. rc = -1;
  522. }
  523. return rc;
  524. }
  525. /* End of file */