DbReader.c 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*
  24. * File: DbReader.c $TOG: DbReader.c /main/9 1998/05/14 11:16:57 mgreess $
  25. * Language: C
  26. *
  27. * (c) Copyright 1991, Hewlett-Packard Company, all rights reserved.
  28. *
  29. * (c) Copyright 1993, 1994 Hewlett-Packard Company *
  30. * (c) Copyright 1993, 1994 International Business Machines Corp. *
  31. * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
  32. * (c) Copyright 1993, 1994 Novell, Inc. *
  33. */
  34. #include <stdio.h>
  35. #include <ctype.h>
  36. #include <stdlib.h>
  37. #include <limits.h>
  38. #include <string.h>
  39. #include <X11/X.h>
  40. #include <X11/Xlib.h>
  41. #include <X11/Xresource.h>
  42. #include <Dt/DtP.h>
  43. #include <Dt/UserMsg.h>
  44. #include <Dt/Connect.h>
  45. #include <Dt/DbUtil.h>
  46. #include <Dt/DbReader.h>
  47. #include <Dt/DtsDb.h>
  48. #include <Dt/DtNlUtils.h>
  49. #include <Tt/tt_c.h>
  50. #include "DtSvcLock.h"
  51. #define TRUE 1
  52. #define FALSE 0
  53. /*
  54. * The default size of an input buffer
  55. */
  56. #define MAX_LINE_LENGTH 1024
  57. /* Structure to hold $variable definitions */
  58. typedef struct {
  59. char * varName;
  60. char * value;
  61. } VariableEntry;
  62. static int variableCount;
  63. static VariableEntry * variableSet;
  64. /*
  65. * The following variables are used to keep track of the
  66. * number of fields that have been allocated. These are
  67. * needed to preallocate a reasonably large number of
  68. * fields in advance because DtDbRead supports a
  69. * 'DTUNLIMITEDFIELDS' number of fields.
  70. */
  71. #define NUMBER_FIELDS_DEFAULT 16
  72. #define NUMBER_FIELDS_INCREMENT 8
  73. /*
  74. * The following variables are used in ReadNextEntry.
  75. * They are global because there space is malloc'ed
  76. * in _DtDbRead but potentially realloc'ed in some
  77. * other function (e.g. ResolveVariableReferenc).
  78. */
  79. /******** Static Function Declarations ********/
  80. static int ReadNextEntry(
  81. Boolean * versionCanBeSet,
  82. FILE *fd,
  83. DtDtsDbField ** fieldPtr,
  84. DtDbRecordDesc * recordDescriptions,
  85. int numRecordDescriptions,
  86. int * returnRrecordIndex,
  87. char *file_name,
  88. int *NumberFieldsAllocated,
  89. char **tmpBuffer,
  90. char **tmpLine) ;
  91. static void ResolveVariableReference(
  92. char *varName,
  93. int varNameLen,
  94. char **buf,
  95. int *buf_size,
  96. int start,
  97. int len,
  98. int *buf_len,
  99. int escape,
  100. int brackets) ;
  101. static char *read_line(
  102. char string[],
  103. int n,
  104. FILE *fd) ;
  105. static void clean_line(
  106. char **string) ;
  107. void _DtDbFillVariables (
  108. char **line ) ;
  109. static Boolean get_variable (
  110. char *key,
  111. int key_len,
  112. char **value,
  113. int escape,
  114. int brackets,
  115. char *var) ;
  116. static void ClearVariables( void ) ;
  117. static Boolean DefineVariable(
  118. Boolean * versionCanBeSet,
  119. char *varString,
  120. char * fileName,
  121. int *variableSetSize) ;
  122. static void SplitField(
  123. DtDtsDbField ** fields,
  124. int * slotToUse,
  125. char * ptr,
  126. int *NumberFieldsAllocated) ;
  127. static int MatchKeyword(
  128. char * line,
  129. DtDbRecordDesc * recordDescriptions,
  130. int numRecordDescriptions);
  131. static void FreeDbField(
  132. DtDtsDbField * fields) ;
  133. static void InitializeLocalizedStrings( void ) ;
  134. /******** End Static Function Declarations ********/
  135. #define VERSION_QUERY_STR "$DtDbVersion"
  136. #define VERSION_KEYWORD "DtDbVersion"
  137. #define VERSION_ID "1.0"
  138. /*
  139. * Pointers to localized strings.
  140. */
  141. static char * incompleteDefn;
  142. static char * multiLineDefn;
  143. static char * tooManyFields;
  144. static char * emptyTypesDirs;
  145. static char * noStartSymbol;
  146. static char * invalidStartSymbol;
  147. static char * missingStartSymbol;
  148. static char * cantSetVersion;
  149. static char * invalidVersion;
  150. /********************
  151. *
  152. * Function Name: _DtDbPathIdToString
  153. *
  154. * Description:
  155. *
  156. * This function maps a path Id, supplied by DtDbLoad during the
  157. * loading of a database, into the associated string value.
  158. *
  159. * Synopsis:
  160. *
  161. * path = _DtDbPathIdToString (pathId);
  162. *
  163. * char * path; A pointer to the string containing the path
  164. * associated witht the Id. This memory is
  165. * owned by the caller, and should be freed up
  166. * when no longer needed.
  167. * DtDbPathId pathId; The Id for the path.
  168. *
  169. ***********************/
  170. char *
  171. _DtDbPathIdToString(
  172. DtDbPathId pathId )
  173. {
  174. char * path;
  175. char * newPath;
  176. if ((path = XrmQuarkToString((XrmQuark)pathId)))
  177. {
  178. /* Allocate some storage for the string */
  179. newPath = (char *) XtNewString(path);
  180. return(newPath);
  181. }
  182. /* Bogus Id */
  183. return(NULL);
  184. }
  185. /********************
  186. *
  187. * Function Name: DtDbRead
  188. *
  189. * Description:
  190. *
  191. * This function loads a collection of database records, located within
  192. * database files. The database files are located within
  193. * the specified set of directories, and match the specified file
  194. * suffix. This function does not interpretation of the database
  195. * entries, other than to break each field into a keyword/value pair.
  196. * For each record loaded, it will be passed to a converter function,
  197. * which is responsible for parsing the fields within the record, and
  198. * then adding the entry to the appropriate in-memory database structure.
  199. *
  200. * If the database files to be loaded are located in the standard
  201. * Dt database locations, then you should call _DtGetDatabaseDirPaths()
  202. * to obtain the 'dirs' info.
  203. *
  204. * Synopsis:
  205. *
  206. * _DtDbRead (dirs, suffix, recordDescriptions, numRecordDescriptions);
  207. *
  208. * DtDirPaths *dirs; A structure containing the names of all the
  209. * directories to search for DB files.
  210. * char *suffix; A filename suffix that identifies which files
  211. * in the "dirs" directories are DB files to
  212. * be loaded.
  213. * DtDbRecordDesc ** recordDescriptions
  214. * An array, where each entry describes a
  215. * database record which should be loaded during
  216. * this pass of _DtDbRead(). See the definition
  217. * of this structure, for more details.
  218. *
  219. * int numRecordDescriptions
  220. * The number of entries in the above array.
  221. *
  222. ***********************/
  223. void
  224. _DtDbRead (
  225. DtDirPaths *dirs,
  226. char *suffix,
  227. DtDbRecordDesc * recordDescriptions,
  228. int numRecordDescriptions )
  229. {
  230. /* LOCAL VARIABLES */
  231. DtDirPaths *db_files;/* An array of string pointers which point to the
  232. names of all the files to be read. */
  233. FILE *fd; /* File descriptor for the file being processed. */
  234. DtDtsDbField *entryFields;/* An array of keyword/value string pairs,
  235. representing the record information. */
  236. XrmQuark pathIndex; /* Index associated with db file */
  237. DtDirPaths tmp_dirs; /* Temporary list of directories. */
  238. int nextIndex = 0;
  239. int i, j;
  240. int recordIndex;
  241. Boolean rejectionStatus;
  242. static Boolean first_time = True;
  243. static char local_host[MAXHOSTNAMELEN];
  244. Boolean versionCanBeSet;
  245. char * verString;
  246. int NumberFieldsAllocated = 0;
  247. char *tmpBuffer = NULL; /* Buffer to store a field value that may
  248. grow to an unlimited size */
  249. char *tmpLine = NULL; /* Temporary input line */
  250. /* CODE */
  251. _DtSvcProcessLock();
  252. if (first_time)
  253. {
  254. first_time = False;
  255. InitializeLocalizedStrings ();
  256. DtGetShortHostname (local_host, MAXHOSTNAMELEN);
  257. }
  258. _DtSvcProcessUnlock();
  259. /* Verify the incoming parameters */
  260. if (dirs == NULL)
  261. return;
  262. tmpLine = XtMalloc (MAX_LINE_LENGTH);
  263. tmpBuffer = XtMalloc (MAX_LINE_LENGTH);
  264. tmp_dirs.paths = (char **) XtMalloc (2 * sizeof (char *));
  265. tmp_dirs.dirs = (char **) XtMalloc (2 * sizeof (char *));
  266. tmp_dirs.dirs[1] = tmp_dirs.paths[1] = NULL;
  267. /*
  268. * The fields for each record will temporarily be stored
  269. * in the variable 'entryFields'. Instead of allocating
  270. * space for this on an as needed basis and then freeing
  271. * the space after a record is input, search the record
  272. * descriptions for the largest number of fields and
  273. * set entryFields to this number of fields. Before this
  274. * function returns, entryField will be free'd.
  275. */
  276. NumberFieldsAllocated = NUMBER_FIELDS_DEFAULT;
  277. for (i = 0; i < numRecordDescriptions; i++)
  278. {
  279. if (recordDescriptions[i].maxFields > NumberFieldsAllocated)
  280. NumberFieldsAllocated = recordDescriptions[i].maxFields;
  281. }
  282. entryFields = (DtDtsDbField *) XtMalloc ((NumberFieldsAllocated + 1) *
  283. sizeof (DtDtsDbField));
  284. /* Load all of the database files in each of the specified directories. */
  285. for (i=0; dirs->dirs[i] != NULL; i++)
  286. {
  287. char *host = NULL,
  288. *dir = NULL,
  289. *pch = NULL,
  290. *tmp = NULL,
  291. *host_prefix = NULL;
  292. /* Locate all matching db file in the current directory */
  293. tmp_dirs.dirs[0] = (char *) dirs->dirs[i];
  294. tmp_dirs.paths[0] = (char *) dirs->paths[i];
  295. db_files = _DtFindMatchingFiles(&tmp_dirs, suffix, True);
  296. nextIndex=0;
  297. /* Determine the "host_prefix" for this directory. */
  298. tmp = (char *) XtNewString (dirs->dirs[i]);
  299. host = tmp;
  300. if ((pch = DtStrchr (tmp, ':')) != NULL)
  301. {
  302. char * netfile;
  303. Tt_status status;
  304. int charLen;
  305. char * lastChar;
  306. char * hpx;
  307. dir = pch + 1;
  308. *pch = '\0';
  309. if (strcmp (local_host, host))
  310. {
  311. netfile = tt_host_file_netfile(host, "/");
  312. if ((status = tt_ptr_error(netfile)) == TT_OK)
  313. {
  314. hpx = tt_netfile_file(netfile);
  315. tt_free(netfile);
  316. status = tt_ptr_error(hpx);
  317. }
  318. if (status != TT_OK)
  319. host_prefix = NULL;
  320. else if (hpx)
  321. {
  322. DtLastChar(hpx, &lastChar, &charLen);
  323. if ((charLen != 1) || (*lastChar != '/'))
  324. {
  325. host_prefix = XtMalloc(strlen(hpx) + 2);
  326. strcpy(host_prefix, hpx);
  327. strcat(host_prefix, "/");
  328. }
  329. else
  330. host_prefix = XtNewString(hpx);
  331. tt_free(hpx);
  332. }
  333. }
  334. else {
  335. /*
  336. * The database host is the same as the invoking host.
  337. */
  338. host_prefix = NULL;
  339. }
  340. }
  341. XtFree ((char *) tmp);
  342. /* Open each of the db files, and extract any matching records */
  343. while (db_files->paths[nextIndex] != NULL)
  344. {
  345. /* If we can't open the next db file, just skip it. */
  346. if ((fd = fopen (db_files->paths[nextIndex], "r")) == NULL)
  347. {
  348. nextIndex++;
  349. continue;;
  350. }
  351. /* Variables do not transfer across database files */
  352. ClearVariables();
  353. versionCanBeSet = True;
  354. pathIndex = XrmStringToQuark(db_files->dirs[nextIndex]);
  355. /* Read and process each entry in the file. */
  356. while (ReadNextEntry (&versionCanBeSet, fd, &entryFields,
  357. recordDescriptions, numRecordDescriptions,
  358. &recordIndex, db_files->dirs[nextIndex],
  359. &NumberFieldsAllocated, &tmpBuffer, &tmpLine))
  360. {
  361. /*
  362. * Invoke all of the callbacks registered for this record type,
  363. * allowing each one to parse the entry, and add it to the
  364. * appropriate in-memory database.
  365. */
  366. for (j = 0, rejectionStatus = False;
  367. recordDescriptions[recordIndex].converters[j]; j++)
  368. {
  369. rejectionStatus |=
  370. (*recordDescriptions[recordIndex].converters[j]) (
  371. entryFields, pathIndex, host_prefix,
  372. rejectionStatus);
  373. }
  374. /* Free up the record information */
  375. FreeDbField(entryFields);
  376. }
  377. (void)fclose (fd);
  378. nextIndex++;
  379. }
  380. _DtFreeDatabaseDirPaths (db_files);
  381. if (host_prefix != NULL)
  382. XtFree (host_prefix);
  383. }
  384. XtFree ((char *) entryFields);
  385. XtFree (tmpLine);
  386. XtFree (tmpBuffer);
  387. XtFree ((char *) tmp_dirs.paths);
  388. XtFree ((char *) tmp_dirs.dirs);
  389. }
  390. /*********************
  391. *
  392. * Function Name: get_variable
  393. *
  394. * Description:
  395. *
  396. * Given a string, this function determines if the string is one of
  397. * local variables or an environment variable and if it is one of
  398. * these, it returns the actual vaulue of the variable.
  399. *
  400. * The local database variables (set VAR=something) take precedence.
  401. *
  402. * Synopsis:
  403. *
  404. * ret_value = get_variable ( key, key_len, value )
  405. *
  406. * Boolean ret_value; True if the variable is found, False
  407. * otherwise.
  408. *
  409. * char *key; The variable name to search for.
  410. *
  411. * int key_len; The length of the key string.
  412. *
  413. * char **value; The value of the variable;
  414. *
  415. * char *var; Caller allocates space for character array
  416. *
  417. * MODIFIED: value
  418. *
  419. ***********************/
  420. static
  421. Boolean
  422. get_variable (
  423. char *key,
  424. int key_len,
  425. char **value,
  426. int escape,
  427. int bracketSeen,
  428. char *var)
  429. {
  430. char **ppchar;
  431. int i;
  432. extern char **environ;
  433. char *tmp;
  434. _DtSvcProcessLock();
  435. for (i = 0; i < variableCount; i++)
  436. if ((strncmp(key, variableSet[i].varName, (size_t)key_len) != 0) ||
  437. ((int)strlen(variableSet[i].varName) != key_len))
  438. continue;
  439. else
  440. {
  441. *value = variableSet[i].value;
  442. _DtSvcProcessUnlock();
  443. return (True);
  444. }
  445. _DtSvcProcessUnlock();
  446. if(!use_in_memory_db)
  447. {
  448. /*
  449. * The variable name was not found in the variable list, so look
  450. * for it in the environment data.
  451. */
  452. for (i=0, ppchar = environ; *ppchar; *ppchar++, i++)
  453. {
  454. if ((tmp = (char *) DtStrrchr (*ppchar, '=')) != NULL)
  455. {
  456. int evar_len = tmp - *ppchar;
  457. if ( (key_len == evar_len)
  458. && (strncmp (key, *ppchar, key_len) == 0))
  459. {
  460. *value = tmp + 1;
  461. return (True);
  462. }
  463. }
  464. }
  465. *value = NULL;
  466. return(False);
  467. }
  468. else
  469. {
  470. /* just put it back as "${value}" */
  471. if(escape)
  472. {
  473. strcat(var, "\\");
  474. }
  475. if( bracketSeen )
  476. {
  477. strcat(var, "${");
  478. }
  479. else
  480. {
  481. strcat(var, "$");
  482. }
  483. strncat(var, key, key_len);
  484. if( bracketSeen )
  485. {
  486. strcat(var, "}");
  487. }
  488. *value = var;
  489. return (True);
  490. }
  491. }
  492. /*********************
  493. *
  494. * Function Name: read_line
  495. *
  496. * Description:
  497. *
  498. * This function reads in one line from a database file
  499. * and returns the string. This is a modified version
  500. * of K&R's "fgets" (Second Edition). Note that the EOLN
  501. * mark is replaced with a '\0'.
  502. *
  503. * Synopsis:
  504. *
  505. * ret_value = read_line (string, n, fd);
  506. *
  507. * char *ret_vaulue; NULL if EOF, string otherwise
  508. *
  509. * char string[]; The array to put the line into.
  510. *
  511. * int n; Max number of chars to read.
  512. *
  513. * FILE * fd; The file descriptor to read from.
  514. *
  515. ***********************/
  516. static
  517. char*
  518. read_line (
  519. char string[], /* MODIFIED */
  520. int n,
  521. FILE *fd )
  522. {
  523. if ((fgets (string, n, fd)) == NULL)
  524. return (NULL);
  525. else {
  526. string[strlen (string) - 1] = '\000';
  527. return (string);
  528. }
  529. }
  530. /*********************
  531. *
  532. * Function Name: clean_line
  533. *
  534. * Description:
  535. *
  536. * This function removes the slashes from a string unless the slash
  537. * is preceded by a slash. It also remove whitespace from the end
  538. * of the string.
  539. *
  540. * Synopsis:
  541. *
  542. * (void) = clean_line (string)
  543. *
  544. * char *string; The array to put the line into.
  545. *
  546. * MODIFIED: string
  547. *
  548. ***********************/
  549. static
  550. void
  551. clean_line (
  552. char **string )
  553. {
  554. int i, j=0, len;
  555. char *ch=*string;
  556. char *ret_string;
  557. char *head;
  558. char *tail;
  559. int _found;
  560. ret_string = (char *) *string;
  561. /*
  562. * Don't search \ by "byte by byte"
  563. * \ may be in the 2nd of IBM-932 char.
  564. */
  565. {
  566. int _i;
  567. int _clen;
  568. _found = 0;
  569. for( _i = 0; _i < strlen( ret_string ); _i += _clen ) {
  570. _clen = mblen( &(ret_string[_i]), MB_CUR_MAX );
  571. /*
  572. * If found invalid char, go ahead.
  573. */
  574. if ( _clen == -1 ) {
  575. _clen = 1;
  576. continue;
  577. }
  578. if ( _clen == 0 )
  579. break;
  580. if ( ( _clen == 1 ) && ( ret_string[_i] == '\\' ) ) {
  581. _found = 1;
  582. break;
  583. }
  584. }
  585. }
  586. if ( _found )
  587. {
  588. while (*ch != '\0')
  589. {
  590. #ifdef NLS16
  591. if (!is_multibyte)
  592. #endif
  593. len = 1;
  594. #ifdef NLS16
  595. else
  596. len = mblen (ch, MB_CUR_MAX);
  597. #endif
  598. /*
  599. * We have to take care of the case when mblen() returns -1
  600. */
  601. if ( (len == 1) || ( len == -1 ) )
  602. {
  603. if (use_in_memory_db || *ch != '\\')
  604. {
  605. ret_string[j++] = *ch;
  606. ch++;
  607. }
  608. else
  609. {
  610. /* Get next char. */
  611. ch++;
  612. #ifdef NLS16
  613. if (!is_multibyte)
  614. #endif
  615. len = 1;
  616. #ifdef NLS16
  617. else
  618. len = mblen (ch, MB_CUR_MAX);
  619. #endif
  620. /*
  621. * We have to take care of the case when mblen() returns -1
  622. */
  623. if ( (len == 1) || ( len == -1 ) )
  624. {
  625. ret_string[j++] = *ch;
  626. /* Skip this char., unless its the terminater */
  627. if (*ch != '\0')
  628. ch++;
  629. }
  630. else
  631. {
  632. for (i=0; i < len; i++, ch++)
  633. ret_string[j++] = *ch;
  634. }
  635. }
  636. }
  637. else
  638. {
  639. for (i=0; i < len; i++, ch++)
  640. ret_string[j++] = *ch;
  641. }
  642. }
  643. ret_string[j] = '\0';
  644. }
  645. /*
  646. * Now remove whitespace from the end of the line.
  647. *
  648. */
  649. tail = head = ret_string;
  650. #ifdef NLS16
  651. /*
  652. * If dealing with single byte characters only first
  653. * check the last character and if it is not a space
  654. * (normally the case) then return.
  655. */
  656. if (_DtNl_is_multibyte == False)
  657. #endif /* NLS16 */
  658. {
  659. i = strlen (ret_string) - 1;
  660. while (i >= 0 && isspace((unsigned char)ret_string[i]))
  661. ret_string[i--] = '\000';
  662. return;
  663. }
  664. /*
  665. * Need to parse the mulit-byte character line.
  666. */
  667. while (*head != '\0')
  668. {
  669. #ifdef NLS16
  670. if (is_multibyte && ((len = mblen (head, MB_CUR_MAX)) > 1))
  671. {
  672. for (i=0; i < len; i++, head++);
  673. tail = head;
  674. }
  675. else
  676. #endif /* NLS16 */
  677. {
  678. /* This is a bugfix for AIX. Need to return true in case of one-byte
  679. * Katakana code.
  680. */
  681. if (((isgraph (*head)) || (iscntrl (*head))) && (!isspace ((unsigned
  682. char)*head)))
  683. tail = head;
  684. head++;
  685. }
  686. }
  687. if (*tail != '\0')
  688. {
  689. tail++;
  690. *tail = '\0';
  691. }
  692. }
  693. /*********************
  694. *
  695. * Function Name: _DtDbFillVariables
  696. *
  697. * Description:
  698. *
  699. * This function scans a string for variable definitions
  700. * and if found, gets the variable substitued for the
  701. * actual value.
  702. *
  703. * Synopsis:
  704. *
  705. * (void) = _DtDbFillVariables (line)
  706. *
  707. * char **line; The string to scan and replace.
  708. *
  709. * MODIFIED: line
  710. *
  711. ***********************/
  712. void
  713. _DtDbFillVariables (
  714. char **line )
  715. {
  716. int i;
  717. int len;
  718. int lineLen;
  719. int lineSize;
  720. char bracketSeen;
  721. int brackets = FALSE;
  722. char *start;
  723. char *variableStart;
  724. char *variableEnd;
  725. char *replacementStart;
  726. char *replacementEnd;
  727. int currentOffset;
  728. Boolean escape = False;
  729. start = *line;
  730. lineLen = strlen (*line)+1;
  731. lineSize = MAX_LINE_LENGTH;
  732. while (*start != '\0')
  733. {
  734. escape = False;
  735. /* Determine the size of this character */
  736. #ifdef NLS16
  737. if (!is_multibyte)
  738. #endif
  739. len = 1;
  740. #ifdef NLS16
  741. else
  742. len = mblen(start, MB_CUR_MAX);
  743. #endif
  744. if (len > 1)
  745. {
  746. /* Move passed the multi-byte char. */
  747. for (i = 0; (i < len) && (*start != '\0'); start++);
  748. continue;
  749. }
  750. if (*start == '\\')
  751. {
  752. /* Discard the escape character, and use the next one */
  753. start++;
  754. escape=True;
  755. /* Get the size of the new character */
  756. #ifdef NLS16
  757. if (!is_multibyte)
  758. len = 1;
  759. else
  760. len = mblen(start, MB_CUR_MAX);
  761. #else
  762. len = 1;
  763. #endif
  764. if (len > 1)
  765. {
  766. /* Move passed the multi-byte char. */
  767. for (i = 0; (i < len) && (*start != '\0'); start++);
  768. continue;
  769. }
  770. }
  771. if (*start == '$' && !escape)
  772. {
  773. /* Variable name reference */
  774. /* Skip the optional left bracket character */
  775. replacementEnd = replacementStart = start;
  776. replacementEnd++;
  777. if (
  778. #ifdef NLS16
  779. (!is_multibyte || (mblen(replacementEnd, MB_CUR_MAX)==1)) &&
  780. #endif
  781. (*replacementEnd == '{'))
  782. {
  783. replacementEnd++;
  784. bracketSeen = TRUE;
  785. }
  786. else
  787. bracketSeen = FALSE;
  788. /*
  789. * Extract the variable name.
  790. * Composed of alphanumeric and _
  791. */
  792. variableStart = replacementEnd;
  793. #ifdef NLS16
  794. if (!is_multibyte)
  795. #endif
  796. {
  797. while (isalnum(*replacementEnd) || (*replacementEnd == '_'))
  798. replacementEnd++;
  799. }
  800. #ifdef NLS16
  801. else
  802. {
  803. while (1)
  804. {
  805. len = mblen(replacementEnd, MB_CUR_MAX);
  806. if ((len == 0) ||
  807. ((len == 1) && !isalnum(*replacementEnd) &&
  808. (*replacementEnd != '_')))
  809. {
  810. break;
  811. }
  812. replacementEnd += len;
  813. }
  814. }
  815. #endif
  816. variableEnd = replacementEnd;
  817. /*
  818. * Strip optional right bracket, if left bracket was
  819. * seen earlier.
  820. */
  821. if (bracketSeen &&
  822. #ifdef NLS16
  823. (!is_multibyte || (mblen(replacementEnd, MB_CUR_MAX)==1)) &&
  824. #endif
  825. (*replacementEnd == '}'))
  826. {
  827. bracketSeen = FALSE;
  828. brackets = TRUE;
  829. replacementEnd ++;
  830. }
  831. if(!bracketSeen)
  832. {
  833. /* Replace with the variable definition */
  834. currentOffset = start - *line;
  835. ResolveVariableReference(variableStart,
  836. variableEnd - variableStart,
  837. line,
  838. &lineSize,
  839. currentOffset,
  840. replacementEnd - replacementStart,
  841. &lineLen,
  842. escape,
  843. brackets);
  844. /* Resync, in case entry_line was realloc'ed */
  845. start = *line + currentOffset;
  846. brackets = FALSE;
  847. }
  848. if(*start != 0)
  849. start++;
  850. }
  851. else if (*start != '\0')
  852. start++;
  853. }
  854. if(!use_in_memory_db)
  855. {
  856. clean_line(line);
  857. }
  858. }
  859. /*********************
  860. *
  861. * Function Name: ReadNextEntry
  862. *
  863. * Description:
  864. *
  865. * This function reads one definition out of the specified file.
  866. * It returns the definition as an array of keyword/value strings.
  867. * This function is responsible for handling syntactic things like string
  868. * variables and comments.
  869. *
  870. ***********************/
  871. #define AT_START 0 /* 0 = at start, '{' symbol not found */
  872. #define NO_START_SYMBOL 1 /* 1 = not at start, '{' symbol not found */
  873. #define START_SYMBOL 2 /* 2 = not at start, '{' symbol found */
  874. static int
  875. ReadNextEntry(
  876. Boolean * versionCanBeSet,
  877. FILE *fd,
  878. DtDtsDbField ** fieldPtr,
  879. DtDbRecordDesc * recordDescriptions,
  880. int numRecordDescriptions,
  881. int * returnRecordIndex,
  882. char *file_name,
  883. int *NumberFieldsAllocated,
  884. char **tmpBuffer,
  885. char **tmpLine)
  886. {
  887. int i;
  888. int len;
  889. int indx = 0;
  890. Boolean multi_line = False; /* Previous line. */
  891. Boolean line_cont = False; /* Current line. */
  892. Boolean remove_defn = False; /* The definition has an error, free it. */
  893. char *start;
  894. char *last;
  895. char *save;
  896. char *error_buffer = NULL;
  897. short startDef;
  898. char * errorName;
  899. char * version;
  900. int variableSetSize = 0;
  901. while (1)
  902. {
  903. (*tmpLine)[0] = '\000';
  904. remove_defn = False;
  905. multi_line = False;
  906. start = NULL;
  907. indx = 0;
  908. if (read_line (*tmpLine, MAX_LINE_LENGTH, fd) == NULL)
  909. {
  910. /* EOF */
  911. break;
  912. }
  913. /* Strip off leading white space */
  914. start = *tmpLine;
  915. while (
  916. #ifdef NLS16
  917. (!is_multibyte || (mblen(start, MB_CUR_MAX) == 1)) &&
  918. #endif
  919. isspace((unsigned char)*start))
  920. {
  921. start++;
  922. }
  923. /* Skip empty lines or comment lines */
  924. if ((*start == '\0') ||
  925. (
  926. #ifdef NLS16
  927. (!is_multibyte || (mblen(start, MB_CUR_MAX) == 1)) &&
  928. #endif
  929. (*start == '#')))
  930. continue;
  931. /* Check for a variable definition */
  932. if ((strncmp(start, "set ", 4) == 0) &&
  933. (strlen(start) >= 4))
  934. {
  935. if (!DefineVariable(versionCanBeSet, start + 4, file_name, &variableSetSize))
  936. {
  937. /*
  938. * An attempt was made to redefine the Db version; this
  939. * is only allowed as the first keyword in a file. We
  940. * will ignore this file. An error msg was already reported.
  941. */
  942. return(False);
  943. }
  944. /*
  945. * Once we've read something other than a comment, then the version
  946. * can no longer be changed. We also need to verify that the
  947. * specified version string is valid.
  948. */
  949. if (*versionCanBeSet)
  950. {
  951. *versionCanBeSet = False;
  952. version = XtNewString(VERSION_QUERY_STR);
  953. if (strchr (version, '$'))
  954. _DtDbFillVariables(&version);
  955. if ((strlen(version) > 0) && (strcmp(version, VERSION_ID)))
  956. {
  957. /* Bad version number; give error, and ignore this file */
  958. error_buffer = XtMalloc(MAXPATHLEN);
  959. sprintf(error_buffer, invalidVersion, file_name);
  960. _DtSimpleError(DtProgName, DtError, NULL, "%s", error_buffer);
  961. XtFree(version);
  962. XtFree(error_buffer);
  963. return(False);
  964. }
  965. XtFree(version);
  966. }
  967. continue;
  968. }
  969. /* Do here also, in case we did not encounter any "set" commands */
  970. *versionCanBeSet = False;
  971. if ((*returnRecordIndex = MatchKeyword(start, recordDescriptions,
  972. numRecordDescriptions)) < 0)
  973. {
  974. /* Skip this definition */
  975. continue;
  976. }
  977. /*
  978. * At this point, the beginning of a definition has been recognized.
  979. * Must now get the data for the fields.
  980. */
  981. clean_line (tmpLine);
  982. if (strchr (*tmpLine, '$'))
  983. _DtDbFillVariables (tmpLine);
  984. /*
  985. * Before spliting tmpLine into the record name and value,
  986. * remove leading whitespace. Variable 'start' may not
  987. * be valid because tmpLine could have been realloc'ed
  988. * by _DtDbFillVariables.
  989. */
  990. start = *tmpLine;
  991. while (
  992. #ifdef NLS16
  993. (!is_multibyte || (mblen(start, MB_CUR_MAX) == 1)) &&
  994. #endif
  995. isspace((unsigned char)*start))
  996. {
  997. start++;
  998. }
  999. SplitField(fieldPtr, &indx, start, NumberFieldsAllocated);
  1000. line_cont = False; /* True if the current line has a continuation
  1001. * character, False otherwise. */
  1002. multi_line = False; /* True if the previous line was continued.
  1003. * This means the current line must be
  1004. * appended to the previous line. */
  1005. startDef = AT_START;
  1006. /* AT_START = at start, '{' symbol not found */
  1007. /* NO_START_SYMBOL = not at start, '{' symbol not found */
  1008. /* START_SYMBOL = not at start, '{' symbol found */
  1009. (*tmpBuffer)[0] = '\000';
  1010. while (1)
  1011. {
  1012. (*tmpLine)[0] = '\000';
  1013. if (read_line (*tmpLine, MAX_LINE_LENGTH, fd) == NULL) /* EOF */
  1014. {
  1015. if (multi_line || (indx >=1))
  1016. {
  1017. error_buffer = XtMalloc(MAXPATHLEN);
  1018. errorName = (*fieldPtr)[0].fieldValue ?
  1019. (*fieldPtr)[0].fieldValue :
  1020. XrmQuarkToString((*fieldPtr)[0].fieldName);
  1021. (void) sprintf (error_buffer, incompleteDefn, errorName,
  1022. file_name);
  1023. _DtSimpleError (DtProgName, DtError, NULL, "%s", error_buffer);
  1024. XtFree(error_buffer);
  1025. remove_defn = True;
  1026. }
  1027. break;
  1028. }
  1029. /* Fill varibles now. */
  1030. if (strchr (*tmpLine, '$'))
  1031. _DtDbFillVariables (tmpLine);
  1032. /* Strip off leading white space */
  1033. start = *tmpLine;
  1034. while (
  1035. #ifdef NLS16
  1036. (!is_multibyte || (mblen(start, MB_CUR_MAX) == 1)) &&
  1037. #endif
  1038. isspace((unsigned char)*start))
  1039. {
  1040. start++;
  1041. }
  1042. /* Skip empty lines or comment lines */
  1043. if ((*start == '\0') ||
  1044. (
  1045. #ifdef NLS16
  1046. (!is_multibyte || (mblen(start, MB_CUR_MAX) == 1)) &&
  1047. #endif
  1048. (*start == '#')))
  1049. continue;
  1050. /* Check for a variable definition */
  1051. if ((strncmp(start, "set ", 4) == 0) &&
  1052. (strlen(start) >= 4))
  1053. {
  1054. if (!DefineVariable(versionCanBeSet, start + 4, file_name, &variableSetSize))
  1055. {
  1056. /*
  1057. * An attempt was made to redefine the Db version; this
  1058. * is only allowed as the first keyword in a file. We
  1059. * will ignore this file. An error msg was already reported.
  1060. */
  1061. remove_defn = True;
  1062. break;
  1063. }
  1064. continue;
  1065. }
  1066. /* Check for the start of a definition ("{") */
  1067. if ( strncmp(start, "{", 1) == 0 )
  1068. {
  1069. /* if '{' found in the middle of definition, ignore defn */
  1070. if ( startDef != AT_START )
  1071. {
  1072. error_buffer = XtMalloc(MAXPATHLEN);
  1073. errorName = (*fieldPtr)[0].fieldValue ?
  1074. (*fieldPtr)[0].fieldValue :
  1075. XrmQuarkToString ((*fieldPtr)[0].fieldName);
  1076. (void) sprintf (error_buffer, invalidStartSymbol, errorName,
  1077. file_name);
  1078. _DtSimpleError (DtProgName, DtError, NULL, "%s", error_buffer);
  1079. XtFree(error_buffer);
  1080. remove_defn = True;
  1081. break;
  1082. }
  1083. startDef = START_SYMBOL; /* not at start, '{' symbol found */
  1084. continue;
  1085. }
  1086. /* we are no longer at definition start, note if start symbol found */
  1087. if ( startDef == AT_START )
  1088. {
  1089. if (error_buffer) XtMalloc(MAXPATHLEN);
  1090. errorName = (*fieldPtr)[0].fieldValue ?
  1091. (*fieldPtr)[0].fieldValue :
  1092. XrmQuarkToString ((*fieldPtr)[0].fieldName);
  1093. (void) sprintf (error_buffer, missingStartSymbol, errorName,
  1094. file_name);
  1095. _DtSimpleError (DtProgName, DtError, NULL, "%s", error_buffer);
  1096. XtFree(error_buffer);
  1097. remove_defn = True;
  1098. break;
  1099. }
  1100. /* Check for the end of a definition ("}") */
  1101. if ( strncmp(start, "}", 1) == 0 )
  1102. {
  1103. if (multi_line)
  1104. {
  1105. error_buffer = XtMalloc(MAXPATHLEN);
  1106. errorName = (*fieldPtr)[0].fieldValue ?
  1107. (*fieldPtr)[0].fieldValue :
  1108. XrmQuarkToString ((*fieldPtr)[0].fieldName);
  1109. (void) sprintf (error_buffer, multiLineDefn, errorName,
  1110. file_name);
  1111. _DtSimpleError (DtProgName, DtError, NULL, "%s", error_buffer);
  1112. XtFree(error_buffer);
  1113. remove_defn = True;
  1114. }
  1115. /* if '}' end found with no starting '{', ignore defn */
  1116. if ( strncmp(start, "}", 1) == 0 && startDef != START_SYMBOL )
  1117. {
  1118. error_buffer = XtMalloc(MAXPATHLEN);
  1119. errorName = (*fieldPtr)[0].fieldValue ?
  1120. (*fieldPtr)[0].fieldValue :
  1121. XrmQuarkToString ((*fieldPtr)[0].fieldName);
  1122. (void) sprintf (error_buffer, noStartSymbol, errorName,
  1123. file_name);
  1124. _DtSimpleError (DtProgName, DtError, NULL, "%s", error_buffer);
  1125. XtFree(error_buffer);
  1126. remove_defn = True;
  1127. }
  1128. break;
  1129. }
  1130. /*
  1131. * At this point, "line" contains data for a field. If "indx"
  1132. * is already equal to "num_fields - 1" (the last entry is a
  1133. * NULL), then something has gone wrong with this definition -
  1134. * like a field is missing the continuation mark.
  1135. */
  1136. if ((recordDescriptions[*returnRecordIndex].maxFields !=
  1137. DTUNLIMITEDFIELDS) &&
  1138. (indx > recordDescriptions[*returnRecordIndex].maxFields))
  1139. {
  1140. error_buffer = XtMalloc(MAXPATHLEN);
  1141. errorName = (*fieldPtr)[0].fieldValue ?
  1142. (*fieldPtr)[0].fieldValue :
  1143. XrmQuarkToString ((*fieldPtr)[0].fieldName);
  1144. (void)sprintf (error_buffer, tooManyFields, errorName, file_name);
  1145. _DtSimpleError (DtProgName, DtError, NULL, "%s", error_buffer);
  1146. XtFree(error_buffer);
  1147. remove_defn = True;
  1148. break;
  1149. }
  1150. line_cont = False;
  1151. save = start;
  1152. /* Need to see if this line is part of a multi_line field. */
  1153. if ((last = DtStrrchr (start, '\\')) != NULL)
  1154. {
  1155. /*
  1156. * Need to see if 'last' is the last non-whitespace char.
  1157. * Strip off leading white space.
  1158. */
  1159. start = last + 1; /* Move passed the slash. */
  1160. while (
  1161. #ifdef NLS16
  1162. (!is_multibyte || (mblen(start, MB_CUR_MAX) == 1)) &&
  1163. #endif
  1164. isspace((unsigned char)*start))
  1165. {
  1166. start++;
  1167. }
  1168. if (*start == '\0')
  1169. {
  1170. /*
  1171. * Only whitespace followed the slash, so remove it
  1172. * unless the slash was escaped.
  1173. */
  1174. if (
  1175. #ifdef NLS16
  1176. !_is_previous_single(save, last) ||
  1177. #endif
  1178. *(last-1) != '\\')
  1179. {
  1180. *last = '\0'; /* Replace the slash with EOLine */
  1181. line_cont = True;
  1182. }
  1183. }
  1184. }
  1185. start = save;
  1186. if (multi_line)
  1187. {
  1188. /*
  1189. * This is a multi-line field - the previous line was continued
  1190. * so append the current line to the previous line "tmpBuffer".
  1191. */
  1192. int tmp_len = strlen (*tmpBuffer) + strlen (start) + 2;
  1193. if (tmp_len >= MAX_LINE_LENGTH)
  1194. *tmpBuffer = (char *) XtRealloc ((char *) *tmpBuffer, tmp_len);
  1195. (void) strcat (*tmpBuffer, start);
  1196. if (!line_cont)
  1197. {
  1198. /*
  1199. * This line is not continued so the field is complete -
  1200. * save the data.
  1201. */
  1202. clean_line (tmpBuffer);
  1203. SplitField(fieldPtr, &indx, *tmpBuffer, NumberFieldsAllocated);
  1204. multi_line = False;
  1205. }
  1206. }
  1207. else
  1208. {
  1209. /*
  1210. * Previous line was not continued.
  1211. */
  1212. if (line_cont)
  1213. {
  1214. /*
  1215. * This line has a continuation mark so save it in "tmpBuffer".
  1216. */
  1217. int tmp_len = strlen (start) + 2;
  1218. if (tmp_len >= MAX_LINE_LENGTH)
  1219. *tmpBuffer = (char *) XtRealloc ((char *) *tmpBuffer, tmp_len);
  1220. (void) strcpy (*tmpBuffer, start);
  1221. multi_line = True;
  1222. }
  1223. else
  1224. {
  1225. /*
  1226. * This field is a single-line field. Save it.
  1227. */
  1228. clean_line (&start);
  1229. SplitField(fieldPtr, &indx, start, NumberFieldsAllocated);
  1230. }
  1231. }
  1232. }
  1233. if (remove_defn)
  1234. {
  1235. for (i = 0; i < indx; i++)
  1236. {
  1237. XtFree ((char *) (*fieldPtr)[i].fieldValue);
  1238. }
  1239. }
  1240. else
  1241. {
  1242. /* Add terminating NULL to fieldPtr array */
  1243. SplitField(fieldPtr, &indx, NULL, NumberFieldsAllocated);
  1244. return (TRUE);
  1245. }
  1246. }
  1247. return(FALSE);
  1248. }
  1249. /*********************
  1250. *
  1251. * Function Name: ResolveVariableReference
  1252. *
  1253. * Description:
  1254. *
  1255. * This function takes a variable name, and searches the list of
  1256. * defined variables for a match. If a match is found, then the
  1257. * associated value is inserted into the buffer; otherwise, nothing
  1258. * is inserted into the buffer. The buffer will be grown, if needed.
  1259. *
  1260. * The buffer being worked with here is the buffer containing the
  1261. * raw input line. When a variable replacement occurs, the
  1262. * variable reference (${name}) will be removed, and replaced with
  1263. * the value for the variable reference. This may require us to
  1264. * grow the input buffer. We also may have to shift up or down any
  1265. * data in the buffer which is after this variable reference.
  1266. *
  1267. * If the variable name is not found, the environment variables are
  1268. * searched and the same replacement mechanism will occurr.
  1269. *
  1270. * Synopsis:
  1271. *
  1272. * ResolveVariableReference (varName, varNameLen, buf, buf_size,
  1273. * start, len, buf_len);
  1274. *
  1275. * char * varName; Name of variable to search for.
  1276. * int varNameLen; Length of the variable name
  1277. * char **buf; Pointer to a buffer, into which the value
  1278. * will be placced.
  1279. * int * buf_size; Pointer to size of buffer.
  1280. * int start; Where in buffer to place value
  1281. * int len; Size of area to replace
  1282. * int * buf_len; Pointer to # of chars in the buf.
  1283. *
  1284. ***********************/
  1285. static void
  1286. ResolveVariableReference(
  1287. char *varName,
  1288. int varNameLen,
  1289. char **buf,
  1290. int *buf_size,
  1291. int start,
  1292. int len,
  1293. int *buf_len,
  1294. int escape,
  1295. int brackets )
  1296. {
  1297. int j;
  1298. int valueLen;
  1299. int delta;
  1300. char *value;
  1301. char *var;
  1302. var = (char *) XtMalloc(varNameLen+5);
  1303. *var = '\0';
  1304. if ((get_variable (varName, varNameLen, &value, escape, brackets, var)))
  1305. {
  1306. valueLen = (int)strlen(value);
  1307. /*
  1308. * The way in which we do our work will be dependent upon whether
  1309. * the replacement value is longer, shorter or equal in size to the
  1310. * variable reference.
  1311. */
  1312. if (valueLen == len)
  1313. {
  1314. /* Same len; simply overwrite with the new value */
  1315. (void)strncpy(*buf + start, value, (size_t)valueLen);
  1316. }
  1317. else if (valueLen < len)
  1318. {
  1319. /*
  1320. * The replacement value is shorter than the reference currently
  1321. * in the input line; write in the replacement value, then shift
  1322. * down the remaining contents of the buffer, overwriting the
  1323. * leftover portion of the variable reference.
  1324. */
  1325. (void)strncpy(*buf + start, value, (size_t)valueLen);
  1326. (void)strcpy(*buf + start + valueLen, *buf + start + len);
  1327. *buf_len -= (len - valueLen);
  1328. }
  1329. else
  1330. {
  1331. /*
  1332. * The replacement value is longer than the variable reference;
  1333. * we may need to grow the input line. In any case, before we
  1334. * can copy in the replacement value, we need to shift the
  1335. * remainder of the input line up, so that we will no overwrite
  1336. * it.
  1337. */
  1338. delta = valueLen - len;
  1339. if (*buf_len + delta >= *buf_size)
  1340. {
  1341. /* Grow the buffer */
  1342. *buf_size += delta + 100;
  1343. *buf = (char *)XtRealloc((void *)*buf, (size_t)*buf_size+1);
  1344. }
  1345. /* Shift the remainder of the input line */
  1346. for (j = *buf_len - 1; j >= start; j--)
  1347. (*buf)[j + delta] = (*buf)[j];
  1348. (void)strncpy(*buf + start, value, (size_t)valueLen);
  1349. *buf_len += delta;
  1350. }
  1351. XtFree((char *) var);
  1352. return;
  1353. }
  1354. /* If no match is found, then replace the reference with nothing */
  1355. (void)strcpy(*buf + start, *buf + start + len);
  1356. *buf_len -= len;
  1357. XtFree((char *) var);
  1358. }
  1359. /*********************
  1360. *
  1361. * Function Name: ClearVariables
  1362. *
  1363. * Description:
  1364. *
  1365. * This function clears out the structure containing all of the
  1366. * currently defined variables.
  1367. *
  1368. * Synopsis:
  1369. *
  1370. * ClearVariables ();
  1371. *
  1372. ***********************/
  1373. static void
  1374. ClearVariables( void )
  1375. {
  1376. int i;
  1377. _DtSvcProcessLock();
  1378. for (i = 0; i < variableCount; i++)
  1379. {
  1380. free((void *)variableSet[i].varName);
  1381. free((void *)variableSet[i].value);
  1382. }
  1383. variableCount = 0;
  1384. _DtSvcProcessUnlock();
  1385. }
  1386. /*********************
  1387. *
  1388. * Function Name: DefineVariable
  1389. *
  1390. * Description:
  1391. *
  1392. * This function takes a string of format "name = value", and
  1393. * parses out the name and value fields, and adds them to the
  1394. * list of defined variables. If 'name' already has a definiation,
  1395. * then it will be replaces. Any bogus entries are ignored.
  1396. *
  1397. * If an attempt is made to change the database version variable
  1398. * when it is not allowed, 'False' will be returned; in all other
  1399. * cases 'True' is returned.
  1400. *
  1401. * Synopsis:
  1402. *
  1403. * DefineVariable (versionCanBeSet, varString, fileName);
  1404. *
  1405. * char * varString; Variable definition string
  1406. *
  1407. ***********************/
  1408. static Boolean
  1409. DefineVariable(
  1410. Boolean * versionCanBeSet,
  1411. char *varString,
  1412. char * fileName,
  1413. int *variableSetSize)
  1414. {
  1415. char * nameStart;
  1416. char * valStart;
  1417. int i;
  1418. int len;
  1419. char *errorBuffer;
  1420. /* Find the start of the variable name */
  1421. nameStart = varString;
  1422. while (
  1423. #ifdef NLS16
  1424. (!is_multibyte || (mblen(nameStart, MB_CUR_MAX) == 1)) &&
  1425. #endif
  1426. isspace((unsigned char)*nameStart))
  1427. {
  1428. nameStart++;
  1429. }
  1430. /* Ignore lines of format: "set " */
  1431. if (*nameStart == '\0')
  1432. return(True);
  1433. /*
  1434. * Find the end of the variable name.
  1435. * Variable names are composed of alphanumeric characters, and '_'.
  1436. */
  1437. valStart = nameStart;
  1438. while (1)
  1439. {
  1440. #ifdef NLS16
  1441. if (!is_multibyte)
  1442. #endif
  1443. len = 1;
  1444. #ifdef NLS16
  1445. else
  1446. len = mblen(valStart, MB_CUR_MAX);
  1447. #endif
  1448. if ((len == 0) ||
  1449. ((len == 1) &&
  1450. ((*valStart == '=') || (!isalnum(*valStart) &&(*valStart != '_')))))
  1451. {
  1452. break;
  1453. }
  1454. valStart += len;
  1455. }
  1456. /*
  1457. * Skip the '=' and any preceding whitespace. We would have only
  1458. * broken from the above loop because of a single byte character,
  1459. * so we don't need to check the character length here.
  1460. */
  1461. if (*valStart == '=')
  1462. {
  1463. *valStart = '\0';
  1464. valStart++;
  1465. }
  1466. else
  1467. {
  1468. *valStart = '\0';
  1469. valStart++;
  1470. /* Skip leading spaces */
  1471. while (
  1472. #ifdef NLS16
  1473. (!is_multibyte || (mblen(valStart, MB_CUR_MAX) == 1)) &&
  1474. #endif
  1475. isspace((unsigned char)*valStart))
  1476. {
  1477. valStart++;
  1478. }
  1479. /* Bogus entry if next character is not a '=' */
  1480. #ifdef NLS16
  1481. if (!is_multibyte)
  1482. #endif
  1483. len = 1;
  1484. #ifdef NLS16
  1485. else
  1486. len = mblen(valStart, MB_CUR_MAX);
  1487. #endif
  1488. if (((len == 1) && (*valStart != '=')) || (len != 1))
  1489. return(True);
  1490. /* Skip the '=' */
  1491. valStart++;
  1492. }
  1493. /*
  1494. * Don't allow the version to be changed, if the 'versionCanBeSet'
  1495. * flag disallows it.
  1496. */
  1497. if (strcmp(VERSION_KEYWORD, nameStart) == 0)
  1498. {
  1499. if (!*versionCanBeSet)
  1500. {
  1501. /* Log an error, and ignore the definition */
  1502. errorBuffer = XtMalloc(MAXPATHLEN);
  1503. sprintf(errorBuffer, cantSetVersion, fileName);
  1504. _DtSimpleError(DtProgName, DtError, NULL, "%s", errorBuffer);
  1505. XtFree(errorBuffer);
  1506. return(False);
  1507. }
  1508. }
  1509. /* Find the definition string; skip leading spaces */
  1510. while (
  1511. #ifdef NLS16
  1512. (!is_multibyte || (mblen(valStart, MB_CUR_MAX) == 1)) &&
  1513. #endif
  1514. isspace((unsigned char)*valStart))
  1515. {
  1516. valStart++;
  1517. }
  1518. /* If a definition already exists for this variable, replace it */
  1519. _DtSvcProcessLock();
  1520. for (i = 0; i < variableCount; i++)
  1521. {
  1522. if (strcmp(nameStart, variableSet[i].varName))
  1523. continue;
  1524. free((void *)variableSet[i].value);
  1525. variableSet[i].value = malloc((size_t)(strlen(valStart) + 1));
  1526. (void)strcpy(variableSet[i].value, valStart);
  1527. _DtSvcProcessUnlock();
  1528. return(True);
  1529. }
  1530. /* New entry; allocate space, if needed */
  1531. if (variableCount >= *variableSetSize)
  1532. {
  1533. *variableSetSize += 10;
  1534. if (variableSet == NULL)
  1535. {
  1536. variableSet = (VariableEntry *)
  1537. malloc(sizeof(VariableEntry) * (*variableSetSize));
  1538. }
  1539. else
  1540. {
  1541. variableSet = (VariableEntry *) realloc((void *)variableSet,
  1542. (size_t)(sizeof(VariableEntry) * (*variableSetSize)));
  1543. }
  1544. }
  1545. variableSet[variableCount].varName =
  1546. (char *)malloc((size_t)strlen(nameStart) + 1);
  1547. (void)strcpy(variableSet[variableCount].varName, nameStart);
  1548. variableSet[variableCount].value =
  1549. (char *)malloc((size_t)strlen(valStart) + 1);
  1550. (void)strcpy(variableSet[variableCount].value, valStart);
  1551. variableCount++;
  1552. _DtSvcProcessUnlock();
  1553. return(True);
  1554. }
  1555. /*
  1556. * Given a field string, made up of a keyword and a value, split them into
  1557. * the two pieces, and store into the indicated structure array. The space
  1558. * in the array will be allocated here, as will copies of the strings.
  1559. */
  1560. static void
  1561. SplitField(
  1562. DtDtsDbField ** fields,
  1563. int * slotToUse,
  1564. char * ptr,
  1565. int *NumberFieldsAllocated)
  1566. {
  1567. char * nextChar;
  1568. char savedChar;
  1569. if (*slotToUse >= *NumberFieldsAllocated)
  1570. {
  1571. *fields = (DtDtsDbField *)XtRealloc((char *)*fields,
  1572. sizeof(DtDtsDbField) *
  1573. (*NumberFieldsAllocated +
  1574. NUMBER_FIELDS_INCREMENT));
  1575. *NumberFieldsAllocated += NUMBER_FIELDS_INCREMENT;
  1576. }
  1577. (*fields)[*slotToUse].fieldName = 0;
  1578. (*fields)[*slotToUse].fieldValue = NULL;
  1579. /* A NULL ptr is how we force a NULL entry to terminate the array */
  1580. nextChar = ptr;
  1581. if (ptr != NULL)
  1582. {
  1583. /* Find the end of the fieldName ('\0' or whitespace) */
  1584. while (*nextChar)
  1585. {
  1586. if (
  1587. #ifdef NLS16
  1588. (!is_multibyte || (mblen(nextChar, MB_CUR_MAX) == 1)) &&
  1589. #endif
  1590. isspace((unsigned char)*nextChar))
  1591. {
  1592. break;
  1593. }
  1594. nextChar++;
  1595. }
  1596. /* Save a copy of the field name */
  1597. savedChar = *nextChar;
  1598. *nextChar = '\0';
  1599. (*fields)[*slotToUse].fieldName = XrmStringToQuark (ptr);
  1600. *nextChar = savedChar;
  1601. /*
  1602. * The remainder of the string is the field value, with leading
  1603. * whitespace stripped out.
  1604. */
  1605. while (*nextChar)
  1606. {
  1607. if (
  1608. #ifdef NLS16
  1609. (!is_multibyte || (mblen(nextChar, MB_CUR_MAX) == 1)) &&
  1610. #endif
  1611. isspace((unsigned char)*nextChar))
  1612. {
  1613. nextChar++;
  1614. }
  1615. else
  1616. break;
  1617. }
  1618. if (*nextChar)
  1619. {
  1620. (*fields)[*slotToUse].fieldValue = XtMalloc(strlen(nextChar) + 1);
  1621. strcpy((*fields)[*slotToUse].fieldValue, nextChar);
  1622. }
  1623. }
  1624. (*slotToUse)++;
  1625. }
  1626. /*
  1627. * This function will take a line read from a database file (with leading
  1628. * white space stripped off), and will attempt to match the keyword portion
  1629. * of it (i.e. the first block of characters terminated by a white space
  1630. * or a NULL) against the set of valid keywords specified in the array of
  1631. * recordDescriptions. The index of the matching record is returned, or
  1632. * -1, if no match is found.
  1633. */
  1634. static int
  1635. MatchKeyword(
  1636. char * line,
  1637. DtDbRecordDesc * recordDescriptions,
  1638. int numRecordDescriptions )
  1639. {
  1640. char * keyword;
  1641. char * nextChar;
  1642. int i;
  1643. for (i = 0; i < numRecordDescriptions; i++)
  1644. {
  1645. keyword = recordDescriptions[i].recordKeyword;
  1646. if (keyword && (strncmp(line, keyword, strlen(keyword)) == 0))
  1647. {
  1648. /*
  1649. * A preliminary match was found. Now, verify that the keywords
  1650. * match completely, by making sure that the next character in
  1651. * the line is either a white space or a NULL; i.e. "foo" and
  1652. * "foobar" would pass the preliminary test above, but would fail
  1653. * the second half of the test.
  1654. */
  1655. nextChar = line + strlen(keyword);
  1656. if ((*nextChar == '\0') || (
  1657. #ifdef NLS16
  1658. (!is_multibyte || (mblen(nextChar, MB_CUR_MAX) == 1)) &&
  1659. #endif
  1660. isspace((unsigned char)*nextChar)))
  1661. {
  1662. /* A match! */
  1663. return (i);
  1664. }
  1665. }
  1666. }
  1667. return (-1);
  1668. }
  1669. /*
  1670. * This function frees up all of the entries for a db record, including the
  1671. * array holding the field information. The array is terminated by an
  1672. * entry with both fieldName and fieldValue set to NULL.
  1673. */
  1674. static void
  1675. FreeDbField(
  1676. DtDtsDbField * fields )
  1677. {
  1678. int i = 0;
  1679. while (fields[i].fieldName || fields[i].fieldValue)
  1680. {
  1681. XtFree(fields[i].fieldValue);
  1682. i++;
  1683. }
  1684. }
  1685. /*********************
  1686. *
  1687. * Function Name: InitializeLocalizedStrings
  1688. *
  1689. * Description: Initializes the localized strings.
  1690. *
  1691. * Modified:
  1692. *
  1693. * char * incompleteDefn; - Set to the default value.
  1694. *
  1695. * char * multiLineDefn; - Set to the default value.
  1696. *
  1697. * char * tooManyFields; - Set to the default value.
  1698. *
  1699. * char * emptyTypesDirs - Set to the default value.
  1700. *
  1701. * char * noStartSymbol; - Set to the default value.
  1702. *
  1703. * char * invalidStartSymbol; - Set to the default value.
  1704. *
  1705. * char * cantSetVersion; - Set to the default value.
  1706. *
  1707. * char * invalidVersion; - Set to the default value.
  1708. *
  1709. ***********************/
  1710. static
  1711. void
  1712. InitializeLocalizedStrings ( void )
  1713. {
  1714. incompleteDefn = strdup (((char *) Dt11GETMESSAGE (4, 8, "The definition \"%s\" in the file\n \"%s\"\n is incomplete. The definition may be missing\n the \"}\" field.\n")));
  1715. multiLineDefn = strdup (((char *) Dt11GETMESSAGE (4, 3, "A multi-line field in the definition \"%s\"\n in the file\n \"%s\"\n is incomplete. A \"\\\" character may be missing\n in the multi-line field.\n")));
  1716. tooManyFields = strdup (((char *) Dt11GETMESSAGE (4, 4, "The definition \"%s\" in the file\n \"%s\"\n has too many fields.\n")));
  1717. emptyTypesDirs = strdup (((char *) Dt11GETMESSAGE (4, 5, "An attempt to read the action and filetypes databases failed.\n This may be caused by the resource \"Dt.TypesDirs\" being incorrectly set.\n")));
  1718. noStartSymbol = strdup (((char *) Dt11GETMESSAGE (4, 6, "The definition \"%s\" in the file\n \"%s\"\n has an end symbol '}' with no start symbol '{'.\n")));
  1719. invalidStartSymbol = strdup (((char *) Dt11GETMESSAGE (4, 7, "The definition \"%s\" in the file\n \"%s\"\n has an unexpected start symbol '{'.\n")));
  1720. missingStartSymbol = strdup (((char *) Dt11GETMESSAGE (4, 9, "The definition \"%s\" in the file\n \"%s\"\n is missing a start symbol '{'.\n")));
  1721. cantSetVersion = strdup (((char *) Dt11GETMESSAGE (4, 10, "The DtDbVersion variable can only be set\nat the beginning of the file. The remainder of the file\n'%s' is being ignored.\n")));
  1722. invalidVersion = strdup (((char *) Dt11GETMESSAGE (4, 11, "The file '%s'\ncontains an invalid DtDbVersion identifier.\n")));
  1723. }