XlationSvc.c 88 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597
  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. /* $TOG: XlationSvc.c /main/13 1999/10/14 15:59:35 mgreess $ */
  24. /****************************************************************************
  25. $FILEBEG$: XlationSvc.c
  26. $PROJECT$: Cde 1.0
  27. $COMPONENT$: DtXlate service
  28. $1LINER$: Implements a translation service using tables and regex search
  29. $COPYRIGHT$:
  30. (c) Copyright 1993, 1994 Hewlett-Packard Company
  31. (c) Copyright 1993, 1994 International Business Machines Corp.
  32. (c) Copyright 1993, 1994 Sun Microsystems, Inc.
  33. (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc.
  34. $END$
  35. ****************************************************************************
  36. ************************************<+>*************************************/
  37. #include <ctype.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <unistd.h>
  42. #if defined(sun)
  43. #include <sys/utsname.h>
  44. #endif
  45. #include <limits.h> /* INT_MAX */
  46. #include <pwd.h> /* for getpw... */
  47. #include <sys/utsname.h> /* for uname */
  48. #include <sys/param.h> /* MAXPATHLEN */
  49. /* for RADIXCHAR and nl_langinfo */
  50. #if defined(__linux__)
  51. # define RADIXCHAR MON_DECIMAL_POINT
  52. #endif
  53. #include <langinfo.h>
  54. #if defined(sun)
  55. #include <regexpr.h> /* for compile,advance */
  56. #else
  57. #include <regex.h> /* for regcomp,regexec */
  58. #endif
  59. /* for Xrm */
  60. #include <X11/Intrinsic.h>
  61. #include <X11/Xresource.h>
  62. /*=================================================================
  63. $SHAREDBEG$: This header appears in all appropriate DtXlate topics
  64. =======================================================$SKIP$======*/
  65. /*$INCLUDE$*/
  66. #include "XlationSvc.h"
  67. #include "LocaleXlate.h"
  68. /*$END$*/
  69. /**** For extensive Introductory info, go to the end of this file ****/
  70. /*========================================================*/
  71. /*====================== Constants =======================*/
  72. /*========================================================*/
  73. /*=============== private =================*/
  74. /*#define DBG_MATCHING ** if defined, debugging matching stages are compiled */
  75. #define DEBUG_XLATE_NAME "dtXlate.debugDtXlate"
  76. #define DEBUG_XLATE_CLASS "DtXlate.DebugDtXlate"
  77. #define EOS '\0'
  78. /* A "random" number used to ensure that the Db has been initalized */
  79. #define INIT_OCCURRED 2329479
  80. #define PATH_SEPARATOR ':'
  81. #define DIR_SLASH '/'
  82. #define LESSTHAN_STR "<"
  83. #define EQUALS_STR "="
  84. #define CONTAINS_STR "~"
  85. #define MORETHAN_STR ">"
  86. #define INHIBIT_STR "0"
  87. #define MATCHALL_CHAR '?'
  88. #define ESCAPE_CHAR '\\'
  89. #define COMMENT_CHAR '!'
  90. #define QUOTE_CHAR '\"'
  91. #define OPER_SEPARATOR ','
  92. #define STDVALUE_SEPARATOR '.'
  93. #define MATCHALL_VER 0
  94. #define PLATFORM_QUARK 0 /* index offsets into quarklist */
  95. #define VERSION_QUARK 1
  96. #define OPERS_QUARK 2
  97. #define DIRECTION_QUARK 3
  98. #define FIRSTSTD_QUARK 4
  99. #define MAXSPECQUARKS 43 /* std + platform + version + operation */
  100. #define MAXSTDQUARKS 40
  101. #define MAXRHSSIZE 100 /* max supported RHS size */
  102. #define MAXLHSSIZE 200 /* max supported LHS size */
  103. #define MAXINTSTRSIZE 15 /* handle any long int -> string */
  104. typedef enum {
  105. __DtXLATE_TYPE_NONE = 0,
  106. __DtXLATE_TYPE_INHIBIT = 1,
  107. __DtXLATE_TYPE_REGEX = 2,
  108. __DtXLATE_TYPE_PURE = 3,
  109. __DtXLATE_TYPE_CONTAINS = 4
  110. } __DtXlateType;
  111. #if defined(sun)
  112. /* Sun doesn't support regcomp() and regexec() yet, so
  113. define this here and fill it will the results of advance() */
  114. typedef struct regmatch_t {
  115. int rm_so; /* start offset */
  116. int rm_eo; /* end offset */
  117. } regmatch_t;
  118. #endif
  119. /*========================================================*/
  120. /*====================== Typedefs ========================*/
  121. /*========================================================*/
  122. #if DOC
  123. /*========================================================*/
  124. $PTYPEBEG$: __DtXlateDbRec
  125. $1LINER$: A private object used to represent translation dbs
  126. $SUMMARY$:
  127. __DtXlateDbRec is the type of the contents of a translation database
  128. object. The database object must be opened before use and closed
  129. after use. The definition of the object is opaque to users.
  130. $ARGS$:
  131. xrmDb: Xrm database used to hold specs
  132. initGuard: used to test whether Db initialized
  133. /*================================================$SKIP$==*/
  134. #endif
  135. /*$DEF$*/
  136. typedef struct __DtXlateDbRec
  137. {
  138. XrmDatabase xrmDb;
  139. int initGuard;
  140. Boolean debugMode;
  141. } __DtXlateDbRec;
  142. /*$END$*/
  143. #if DOC
  144. /*========================================================*/
  145. $PTYPEBEG$: __DtXlateSrchData
  146. $1LINER$: A private object used to collect search-related data
  147. $SUMMARY$:
  148. __DtXlateSrchData stores all the data pertaining to a search
  149. and the search results. The search routines utilize this
  150. to maintain status info over multiple calls by the
  151. enumeration routines and to return info to the routine
  152. that initiated the search.
  153. $ARGS$:
  154. filterQuarks: quark list for the platform, version, and op filter
  155. stdValueQuarks: quark list for the std value
  156. opValue: ptr to operation-specific value string
  157. SpecRef: indices 1 to MAXSPECQUARKS point to matching Xrm strings
  158. SubEx: indices 1 to MAXSPECQUARKS index sub exprs in opValue
  159. /*================================================$SKIP$==*/
  160. #endif
  161. /*$DEF$*/
  162. typedef struct __DtXlateSrchData
  163. {
  164. /* db info */
  165. _DtXlateDb db;
  166. /* query info */
  167. const char * platformStr;
  168. XrmQuark platformQuark;
  169. int version;
  170. char verStr[MAXINTSTRSIZE]; /* handle any long int */
  171. const char * operStr;
  172. int operStrLen;
  173. XrmQuark operQuark;
  174. XrmQuark lessThanQuark;
  175. XrmQuark equalsToQuark;
  176. XrmQuark containsQuark;
  177. XrmQuark moreThanQuark;
  178. XrmQuark inhibitQuark;
  179. /* query or search info */
  180. XrmQuark stdValueQuarks[MAXSTDQUARKS];
  181. const char * opValue;
  182. /* search info */
  183. __DtXlateType curTransType;
  184. __DtXlateType bestTransType;
  185. int curScore;
  186. int bestScore;
  187. /* MAXSPECQUARKS is depended upon elsewhere to be the size of these */
  188. const char * curSpecRefs[MAXSPECQUARKS];
  189. const char * bestSpecRefs[MAXSPECQUARKS];
  190. regmatch_t curSubEx[MAXSPECQUARKS]; /* pattern match data */
  191. regmatch_t bestSubEx[MAXSPECQUARKS]; /* pattern match data */
  192. } __DtXlateSrchData;
  193. /*$END$*/
  194. /*========================================================*/
  195. /*================== Private routines ====================*/
  196. /*========================================================*/
  197. #if DOC
  198. /*========================================================*/
  199. $PFUNBEG$: ExpandPath()
  200. $1LINER$: adds current working directory to front of path if its relative
  201. $SUMMARY$:
  202. If path is absolute, returns a malloced copy.
  203. If path is relative, inserts the CWD in front of the relative path
  204. and returns a mallocedd memory.
  205. The caller must free the memory when no longer needed.
  206. $ARGS$:
  207. filespec: the pathname
  208. $RETURNS$:
  209. ptr to mallocedd memory or NULL
  210. /*================================================$SKIP$==*/
  211. #endif
  212. char * ExpandPath (
  213. const char * filespec)
  214. { /* $CODE$ */
  215. char tmpPath[MAXPATHLEN + 2];
  216. char * pathName;
  217. char * eos = NULL;
  218. const char * slash = NULL;
  219. /* test args */
  220. if (NULL == filespec) return NULL;
  221. /*** is the file absolute ***/
  222. /* if filespec begins with / then it is absolute */
  223. if ( ( MB_CUR_MAX == 1
  224. || mblen(filespec, MB_CUR_MAX) == 1)/* 1st char is 1 byte */
  225. && *filespec == DIR_SLASH) /* and its a / */
  226. {
  227. return strdup(filespec); /* RETURN */
  228. }
  229. /*** otherwise, make it relative to the current directory ***/
  230. /* get user's current working directory */
  231. if (getcwd(tmpPath, MAXPATHLEN) == 0) return NULL; /* RETURN: error */
  232. /*** add a slash to end of path component, if needed ***/
  233. /* get end of the string */
  234. eos = tmpPath + strlen(tmpPath);
  235. /* get last slash */
  236. _DtMBStrrchr(tmpPath,DIR_SLASH,-1,&slash);
  237. if (slash != (eos-1)) /* is slash last char of path? */
  238. {
  239. *eos++ = DIR_SLASH;
  240. *eos = EOS;
  241. }
  242. /* make a malloc'd copy of the path with room to grow */
  243. pathName = malloc(sizeof(char) *
  244. (strlen(filespec) + (eos-tmpPath) + 5) ); /* 5: arbitrary */
  245. if (NULL == pathName) return NULL; /* RETURN: error */
  246. /* build the absolute path */
  247. strcpy(pathName,tmpPath);
  248. strcat(pathName,filespec);
  249. return pathName; /* RETURN: found */
  250. } /* $END$ */
  251. #if DOC
  252. /*========================================================*/
  253. $PFUNBEG$: DeleteDbMem()
  254. $1LINER$: Zeros out the db mem & frees it
  255. $SUMMARY$:
  256. Zeros out the db mem & frees it
  257. The xrmDb should have already been destroyed before calling
  258. this function.
  259. $ARGS$:
  260. io_db: db to delete
  261. $RETURNS$:
  262. /*================================================$SKIP$==*/
  263. #endif
  264. static
  265. void DeleteDbMem(
  266. _DtXlateDb * io_db)
  267. { /*$CODE$*/
  268. /* zero out object mem and free it */
  269. (*io_db)->xrmDb = NULL;
  270. (*io_db)->initGuard = 0;
  271. free(*io_db);
  272. *io_db= NULL;
  273. } /*$END$*/
  274. #if DOC
  275. /*========================================================*/
  276. $IFUNBEG$: _DtMBStrchr()
  277. $1LINER$: Searches for a character in a multibyte string
  278. $SUMMARY$:
  279. Returns in 'ret_ptr' the address of the first occurence of 'value'
  280. in string s1. Value may also be the end of string marker '\0'.
  281. $ARGS$:
  282. $RETURNS$:
  283. -1 If found an invalid character.
  284. 0 If found value in string s2
  285. 1 If found the null byte character without finding 'value'.
  286. 'ret_ptr' will also be null in this case.
  287. /*================================================$SKIP$==*/
  288. #endif
  289. int _DtMBStrchr (
  290. const char * s1,
  291. int value,
  292. int max_len,
  293. const char * * ret_ptr )
  294. { /*$CODE$*/
  295. int len;
  296. const char * p1;
  297. wchar_t wcs;
  298. *ret_ptr = NULL;
  299. if (!s1 || *s1 == '\0')
  300. return 1;
  301. if (max_len == 1)
  302. {
  303. *ret_ptr = strchr (s1, value);
  304. if (*ret_ptr)
  305. return 0;
  306. return 1;
  307. }
  308. p1 = s1;
  309. while (*p1 != '\0')
  310. {
  311. len = mblen (p1, max_len);
  312. if (len == -1)
  313. return -1;
  314. if (len == 1)
  315. {
  316. if (*p1 == value)
  317. {
  318. *ret_ptr = p1;
  319. return 0;
  320. }
  321. p1++;
  322. }
  323. else
  324. {
  325. if (mbstowcs (&wcs, p1, 1) == value)
  326. {
  327. *ret_ptr = p1;
  328. return 0;
  329. }
  330. p1 += len;
  331. }
  332. }
  333. /* check for match on EOS */
  334. if (*p1 == value) *ret_ptr = p1;
  335. return ((*ret_ptr) ? 0 : 1);
  336. } /*$CODE$*/
  337. #if DOC
  338. /*========================================================*/
  339. $IFUNBEG$: _DtMBStrrchr()
  340. $1LINER$: Searches for a character in a multibyte string
  341. $SUMMARY$:
  342. Returns in 'ret_ptr' the address of the last occurence of 'value'
  343. in string s1. Value may also be the end of string marker '\0'.
  344. $ARGS$:
  345. $RETURNS$:
  346. -1 If found an invalid character.
  347. 0 If found value in string s2
  348. 1 If found the null byte character without finding 'value'.
  349. 'ret_ptr' will also be null in this case.
  350. /*================================================$SKIP$==*/
  351. #endif
  352. int _DtMBStrrchr (
  353. const char * s1,
  354. int value,
  355. int max_len,
  356. const char * * ret_ptr )
  357. { /*$CODE$*/
  358. int len;
  359. const char * p1;
  360. wchar_t wcs;
  361. *ret_ptr = NULL;
  362. if (!s1 || *s1 == '\0')
  363. return 1;
  364. if (max_len == 1)
  365. {
  366. *ret_ptr = strrchr (s1, value);
  367. if (*ret_ptr)
  368. return 0;
  369. return 1;
  370. }
  371. p1 = s1;
  372. while (*p1 != '\0')
  373. {
  374. len = mblen (p1, max_len);
  375. if (len == -1)
  376. return -1;
  377. if (len == 1)
  378. {
  379. if (*p1 == value) *ret_ptr = p1;
  380. p1++;
  381. }
  382. else
  383. {
  384. if (mbstowcs (&wcs, p1, 1) == value) *ret_ptr = p1;
  385. p1 += len;
  386. }
  387. }
  388. /* check for match on EOS */
  389. if (*p1 == value) *ret_ptr = p1;
  390. return ((*ret_ptr) ? 0 : 1);
  391. }
  392. #if DOC
  393. /*========================================================*/
  394. $PFUNBEG$: SetDebugModeState()
  395. $1LINER$: Checks db for debug mode and sets flag
  396. $SUMMARY$:
  397. $WARNING$:
  398. $ARGS$:
  399. $RETURNS$:
  400. /*================================================$SKIP$==*/
  401. #endif
  402. static
  403. void SetDebugModeState(
  404. _DtXlateDb dbRec)
  405. { /*$CODE$*/
  406. XrmValue value;
  407. char * str_type;
  408. if (XrmGetResource(dbRec->xrmDb,
  409. DEBUG_XLATE_NAME,DEBUG_XLATE_CLASS,&str_type,&value) == True)
  410. dbRec->debugMode = True;
  411. }
  412. #if DOC
  413. /*========================================================*/
  414. $PFUNBEG$: ReplaceMatchallSubex()
  415. $1LINER$: Replace matchall subexpression refs (e.g. ?1) with values
  416. $SUMMARY$:
  417. If subexpressions are specified and referenced, the
  418. routine assumes that the string pointed to by pStr was
  419. allocated using malloc() and can be resized using realloc().
  420. The value and size of pStr may be different after the call.
  421. $WARNING$:
  422. This routine assumes it is working on a stdvalue expression
  423. (e.g. from the LHS of a spec), that uses only stdvalue strings
  424. or matchall-style subexpression replacement specs, e.g. ?1.
  425. $ARGS$:
  426. $RETURNS$:
  427. /*================================================$SKIP$==*/
  428. #endif
  429. static
  430. void ReplaceMatchallSubex(
  431. char * * pStr,
  432. regmatch_t * subex,
  433. const char * matchedStr)
  434. { /*$CODE$*/
  435. char * nxt = *pStr;
  436. char * old = *pStr;
  437. /* strip escapes out */
  438. for ( *nxt = *old; /* xfer but don't advance */
  439. *old != EOS;
  440. *nxt = *old ) /* xfer but don't advance */
  441. {
  442. if ( *old == MATCHALL_CHAR ) /* if an escaped char follows */
  443. {
  444. /* if MATCHALL_CHAR is not followed by a digit, e.g. \1
  445. or no replacement values exist, ignore it */
  446. if ( NULL == subex
  447. || isdigit(*(old+1)) == 0 )
  448. {
  449. old++; /* go past the escape char */
  450. *nxt++ = *old++; /* keep just the char that was escaped
  451. and assign here to avoid tranlating
  452. that character, then move on to the
  453. next one */
  454. continue; /* CONTINUE */
  455. }
  456. else /* a value reference is being made */
  457. { /* get the refNum and advance the ptr */
  458. int refNum, numLen;
  459. int newOff, oldOff;
  460. sscanf(++old,"%d%n", &refNum, &numLen);
  461. old += numLen; /* move old ptr past the ref number */
  462. /* printf("%d=%s\n", refNum, &matchedStr[subex[refNum].rm_so]); ** DBG */
  463. /* test for valid replacement */
  464. if ( refNum >= 0
  465. && refNum < MAXSPECQUARKS
  466. && subex[refNum].rm_so != -1)
  467. {
  468. int repLen;
  469. int strLen;
  470. char * oldTmp;
  471. char * newTmp;
  472. newOff = nxt - *pStr;
  473. oldOff = old - *pStr;
  474. repLen = subex[refNum].rm_eo - subex[refNum].rm_so;
  475. strLen = strlen(*pStr);
  476. /* expand memory and reset pointers */
  477. *pStr = realloc(*pStr,strLen+repLen+1);
  478. if (NULL == *pStr) return; /* RETURN */
  479. nxt = *pStr + newOff;
  480. old = *pStr + oldOff;
  481. /* move rest back to leave room for the replacement value */
  482. oldTmp = *pStr+strLen; /* pts to old EOS */
  483. newTmp = *pStr+strLen-(oldOff-newOff)+repLen;/*pts to new EOS*/
  484. while (oldTmp >= old) *newTmp-- = *oldTmp--;
  485. /* replace the ref with a value but don't append EOS */
  486. strncpy(nxt,&matchedStr[subex[refNum].rm_so],repLen);
  487. nxt += repLen; /* move new to end of replace string */
  488. old += repLen - (oldOff-newOff);
  489. /* move old to end of expanded old string */
  490. } /* if valid replacement */
  491. } /* if a replacement requested */
  492. continue; /* CONTINUE */
  493. } /* if an escaped character */
  494. /* if survived all the checks, can advance to next char */
  495. nxt++;
  496. old++;
  497. }
  498. } /*$END$*/
  499. #if DOC
  500. /*========================================================*/
  501. $PFUNBEG$: StripMetaAndReplaceEscSubex()
  502. $1LINER$: Strips off meta chars and replaces escaped subex (e.g. \1) values
  503. $SUMMARY$:
  504. Strip is performed in place if replaceValues is NULL.
  505. If replaceValues are specified and referenced, the
  506. routine assumes that the string pointed to by pStr was
  507. allocated using malloc() and can be resized using realloc().
  508. The value and size of pStr may be different after the call.
  509. $WARNING$:
  510. This routine assumes it is working on a value expression
  511. (e.g. from the RHS of a spec), that uses meta chars and
  512. regex(5)-style subexpression replacement specs.
  513. $ARGS$:
  514. $RETURNS$:
  515. /*================================================$SKIP$==*/
  516. #endif
  517. static
  518. void StripMetaAndReplaceEscSubex(
  519. char * * pStr,
  520. const Boolean keepEscChar,
  521. const char * * replaceValues)
  522. { /*$CODE$*/
  523. char * nxt = *pStr;
  524. char * old = *pStr;
  525. Boolean inQuote = False;
  526. /* strip escapes out */
  527. for ( *nxt = *old; /* xfer but don't advance */
  528. *old != EOS;
  529. *nxt = *old ) /* xfer but don't advance */
  530. {
  531. if ( *old == ESCAPE_CHAR ) /* if an escaped char follows */
  532. {
  533. /* if ESCAPE_CHAR is not followed by a digit, e.g. \1
  534. or no replacement values exist, ignore it */
  535. if ( NULL == replaceValues
  536. || keepEscChar
  537. || isdigit(*(old+1)) == 0 )
  538. {
  539. if (!keepEscChar) old++; /* go past the escape char */
  540. else *nxt++ = *old++; /* copy esc char over */
  541. *nxt++ = *old++; /* keep just the char that was escaped
  542. and assign here to avoid tranlating
  543. that character, then move on to the
  544. next one */
  545. continue; /* CONTINUE */
  546. }
  547. else /* a value reference is being made */
  548. { /* get the refNum and advance the ptr */
  549. int refNum, numLen;
  550. int newOff, oldOff;
  551. sscanf(++old,"%d%n", &refNum, &numLen);
  552. old += numLen; /* move old ptr past the ref number */
  553. /* printf("%x=%s\n", replaceValues[refNum], replaceValues[refNum]); ** DBG */
  554. /* test for valid replacement */
  555. if ( refNum >= 0
  556. && refNum < MAXSPECQUARKS
  557. && replaceValues[refNum] != NULL)
  558. {
  559. int repLen;
  560. int strLen;
  561. char * oldTmp;
  562. char * newTmp;
  563. newOff = nxt - *pStr;
  564. oldOff = old - *pStr;
  565. repLen = strlen(replaceValues[refNum]);
  566. strLen = strlen(*pStr);
  567. /* expand memory and reset pointers */
  568. *pStr = realloc(*pStr,strlen(*pStr)+repLen+1);
  569. if (NULL == *pStr) return; /* RETURN */
  570. nxt = *pStr + newOff;
  571. old = *pStr + oldOff;
  572. /* move rest back to leave room for the replacement value */
  573. oldTmp = *pStr+strLen; /* pts to old EOS */
  574. newTmp = *pStr+strLen-(oldOff-newOff)+repLen;/*pts to new EOS*/
  575. while (oldTmp >= old) *newTmp-- = *oldTmp--;
  576. /* replace the ref with a value but don't append EOS */
  577. strncpy(nxt,replaceValues[refNum],repLen);
  578. nxt += repLen; /* move new to end of replace string */
  579. old += repLen - (oldOff-newOff);
  580. /* move old to end of expanded old string */
  581. } /* if valid replacement */
  582. } /* if a replacement requested */
  583. continue; /* CONTINUE */
  584. } /* if an escaped character */
  585. else
  586. { /* a non-escaped char; make further checks */
  587. if ( *old == COMMENT_CHAR )
  588. {
  589. *old = EOS; /* end the string */
  590. continue; /* CONTINUE */
  591. }
  592. else if ( *old == QUOTE_CHAR )
  593. {
  594. if ( !inQuote) inQuote = True; /* start quote */
  595. else inQuote = False; /* end quote */
  596. old++; /* go to next char */
  597. continue; /* CONTINUE */
  598. }
  599. else if ( !inQuote && isspace(*old) )
  600. {
  601. old++; /* skip the space */
  602. continue; /* CONTINUE */
  603. }
  604. } /* else non-escaped char */
  605. /* if survived all the checks, can advance to next char */
  606. nxt++;
  607. old++;
  608. }
  609. } /*$END$*/
  610. /*========================================================*/
  611. /*============== Private Xlate routines ==================*/
  612. /*========================================================*/
  613. #if DOC
  614. /*========================================================*/
  615. $PFUNBEG$: PrintDbEntry()
  616. $1LINER$: Prints a db entry to stdout
  617. $SUMMARY$:
  618. $ARGS$:
  619. quarks: NULLQUARK-terminated list of quarks for the LHS of the entry
  620. value: value of the RHS of the entry
  621. $RETURNS$:
  622. /*================================================$SKIP$==*/
  623. #endif
  624. static
  625. void PrintDbEntry(
  626. XrmQuarkList quarks,
  627. XrmValue * value)
  628. { /*$CODE$*/
  629. char * str;
  630. XrmQuark quark;
  631. /* print the entry */
  632. quark=*quarks;
  633. while ( quark != NULLQUARK )
  634. {
  635. str = XrmQuarkToString(quark);
  636. fprintf(stderr,"%s", str);
  637. quark = *(++quarks);
  638. if (quark != NULLQUARK) fprintf(stderr,".");
  639. }
  640. fprintf(stderr,":%s\n",value->addr);
  641. } /*$END$*/
  642. #if DOC
  643. /*========================================================*/
  644. $PFUNBEG$: strCaseiCmp
  645. $1LINER$: case insensitive string comparison
  646. $SUMMARY$:
  647. Rolled my own because strcasecmp() not available on
  648. all platforms.
  649. $ARGS$:
  650. $RETURNS$:
  651. True: strings match
  652. False: they do not
  653. /*================================================$SKIP$==*/
  654. #endif
  655. static
  656. Boolean strCaseiCmp(
  657. const char * str1,
  658. const char * str2)
  659. { /*$CODE$*/
  660. /* if ( !str1 || !str2 ) return False; *//* unneeded performance hit */
  661. while ( *str1 && *str2 )
  662. if ( tolower(*str1++) != tolower(*str2++) ) return False;
  663. return (*str1 == *str2);
  664. } /*$END$*/
  665. #if DOC
  666. /*========================================================*/
  667. $PFUNBEG$: CheckForMatchall()
  668. $1LINER$: Matches search pattern to spec data
  669. $SUMMARY$:
  670. $ARGS$:
  671. $RETURNS$:
  672. /*================================================$SKIP$==*/
  673. #endif
  674. static
  675. Boolean CheckForMatchall(
  676. __DtXlateSrchData * srchData,
  677. const char * matchallString,
  678. const char * matchingString)
  679. { /*$CODE$*/
  680. int refNum = -1;
  681. int score = 0;
  682. /* test for a match all */
  683. if (! ( matchallString[0] == MATCHALL_CHAR
  684. && ( matchallString[1] == EOS
  685. || sscanf(matchallString+1,"%d", &refNum) == 1) ) )
  686. return False; /* RETURN: syntax error or non-matchall */
  687. /* matchall occurred; save the matching string if valid ref num */
  688. if ( refNum != -1
  689. && refNum >= 0
  690. && refNum < XtNumber(srchData->curSpecRefs) )
  691. {
  692. /* Don't store the string if it is just a matchall */
  693. /* This allows a replacement ref to be deleted on a match
  694. for which there is no replacement value. */
  695. if ( matchingString[0] == MATCHALL_CHAR
  696. && matchingString[1] == EOS )
  697. {
  698. srchData->curSpecRefs[refNum] = NULL;
  699. /* don't add to score for a matchall with no replacement value */
  700. }
  701. else
  702. {
  703. /* recall: string not owned by curSpecRefs */
  704. srchData->curSpecRefs[refNum] = matchingString;
  705. score = 1;
  706. }
  707. }
  708. else /* not a value reference; just determine if a plain match */
  709. {
  710. if ( matchingString[0] == MATCHALL_CHAR
  711. && matchingString[1] == EOS )
  712. score = 1; /* a plain matchall matches a plain matchall */
  713. }
  714. /* if a perfect matchall match, bump the score */
  715. srchData->curScore += score;
  716. return True; /* RETURN: matchall */
  717. } /*$END$*/
  718. #if DOC
  719. /*========================================================*/
  720. $PFUNBEG$: CheckSearchPlatformMatchesSpec()
  721. $1LINER$: Matches search pattern to spec data
  722. $SUMMARY$:
  723. $ARGS$:
  724. $RETURNS$:
  725. /*================================================$SKIP$==*/
  726. #endif
  727. static
  728. Boolean CheckSearchPlatformMatchesSpec(
  729. __DtXlateSrchData * srchData,
  730. XrmQuark specPlatformQuark)
  731. { /*$CODE$*/
  732. /* CheckForMatchall stores away the matching string if of form ?n */
  733. if (srchData->platformQuark != NULLQUARK)
  734. {
  735. char * specStr = XrmQuarkToString(specPlatformQuark);
  736. /* CheckForMatchall incs score if appropriate */
  737. if (CheckForMatchall(srchData,specStr,srchData->platformStr) == True)
  738. return True; /* RETURN: platform matches */
  739. }
  740. if (srchData->platformQuark == specPlatformQuark)
  741. {
  742. srchData->curScore += 2; /* perfect match better than matchall match */
  743. return True; /* RETURN: platform matches */
  744. }
  745. return False; /* RETURN: platform doesnt match */
  746. } /*$END$*/
  747. #if DOC
  748. /*========================================================*/
  749. $PFUNBEG$: CheckSearchVerMatchesSpec()
  750. $1LINER$: Matches search pattern to spec data
  751. $SUMMARY$:
  752. $ARGS$:
  753. $RETURNS$:
  754. /*================================================$SKIP$==*/
  755. #endif
  756. static
  757. Boolean CheckSearchVerMatchesSpec(
  758. __DtXlateSrchData * srchData,
  759. XrmQuark specVersionQuark)
  760. { /*$CODE$*/
  761. const char * numStr = XrmQuarkToString(specVersionQuark);
  762. int lowerBnd = 0;
  763. int upperBnd = INT_MAX;
  764. int score = 0;
  765. if ( srchData->version == MATCHALL_VER
  766. || CheckForMatchall(srchData,numStr,srchData->verStr) == True )
  767. return True; /* RETURN; matchall specified */
  768. /*** sscanf()-based parsing ***/
  769. /* note that the (score=x) is an assignment, not a compare */
  770. if ( (score=1) && sscanf(numStr,"%d-%d", &lowerBnd, &upperBnd) != 2
  771. && (score=1) && sscanf(numStr,"%d+", &lowerBnd) != 1
  772. && (score=2) && sscanf(numStr,"%d", &lowerBnd) != 1 )
  773. return False; /* RETURN: syntax error */
  774. if ( lowerBnd > srchData->version || upperBnd < srchData->version )
  775. return False; /* RETURN: version doesnt match */
  776. srchData->curScore += score;
  777. return True; /* RETURN: version matches */
  778. } /*$END$*/
  779. #if DOC
  780. /*========================================================*/
  781. $PFUNBEG$: CheckSearchOperMatchesSpec()
  782. $1LINER$: Matches search pattern to spec data
  783. $SUMMARY$:
  784. $ARGS$:
  785. srchData: state of the search
  786. specOperationQuark: quark for the operation specification string
  787. $RETURNS$:
  788. True: if srchData->operation is found in specOperation string
  789. or the specOperation string is a match all
  790. False: if not
  791. /*================================================$SKIP$==*/
  792. #endif
  793. static
  794. Boolean CheckSearchOperMatchesSpec(
  795. __DtXlateSrchData * srchData,
  796. XrmQuark specOperationQuark)
  797. { /*$CODE$*/
  798. const char * opStr = XrmQuarkToString(specOperationQuark);
  799. int hitLen;
  800. const char * hit;
  801. const char * remainingOps;
  802. if ( srchData->operStr == NULL
  803. || CheckForMatchall(srchData,opStr,srchData->operStr) == True
  804. || CheckForMatchall(srchData,srchData->operStr,opStr) == True )
  805. return True; /* RETURN; matchall specified */
  806. /* quark compare search */
  807. if ( specOperationQuark == srchData->operQuark )
  808. goto matched;
  809. /*** strstr-based search ***/
  810. hitLen = srchData->operStrLen;
  811. remainingOps = opStr;
  812. do
  813. {
  814. /* look for operation in remainingOps */
  815. hit = strstr(remainingOps,srchData->operStr);
  816. /* see if the hit is on a complete token */
  817. if ( NULL != hit
  818. && (hit == remainingOps || *(hit-1) == OPER_SEPARATOR)
  819. && (hit[hitLen] == EOS || hit[hitLen] == OPER_SEPARATOR) )
  820. {
  821. matched:
  822. srchData->curScore += 2; /*perfect match better than a matchall match*/
  823. return True; /* RETURN: operation matches */
  824. }
  825. } while(hit != NULL && *(remainingOps = hit+1) != EOS);
  826. return False; /* RETURN: no match on operation */
  827. } /*$END$*/
  828. #if DOC
  829. /*========================================================*/
  830. $PFUNBEG$: CheckSearchDirOpToStdMatchesSpec()
  831. $1LINER$: Matches search pattern to spec data
  832. $SUMMARY$:
  833. $ARGS$:
  834. $RETURNS$:
  835. /*================================================$SKIP$==*/
  836. #endif
  837. static
  838. Boolean CheckSearchDirOpToStdMatchesSpec(
  839. __DtXlateSrchData * srchData,
  840. XrmQuark specDirectionQuark)
  841. { /*$CODE$*/
  842. int score = 0;
  843. __DtXlateType type = __DtXLATE_TYPE_NONE;
  844. if (specDirectionQuark == srchData->inhibitQuark)
  845. return False; /* RETURN: no match */
  846. /* Note that the type and score expressions are assignments */
  847. if (! ( ( (type=__DtXLATE_TYPE_REGEX)
  848. && (specDirectionQuark == srchData->lessThanQuark))
  849. || ( (type=__DtXLATE_TYPE_PURE)
  850. && (score=1)
  851. && (specDirectionQuark == srchData->equalsToQuark))
  852. || ( (type=__DtXLATE_TYPE_CONTAINS)
  853. && (score=1)
  854. && (specDirectionQuark == srchData->containsQuark)) ) )
  855. return False; /* RETURN: no match */
  856. srchData->curScore += score;
  857. srchData->curTransType = type;
  858. return True; /* RETURN: direction matches */
  859. } /*$END$*/
  860. #if DOC
  861. /*========================================================*/
  862. $PFUNBEG$: CheckSearchDirStdToOpMatchesSpec()
  863. $1LINER$: Matches search pattern to spec data
  864. $SUMMARY$:
  865. $ARGS$:
  866. $RETURNS$:
  867. /*================================================$SKIP$==*/
  868. #endif
  869. static
  870. Boolean CheckSearchDirStdToOpMatchesSpec(
  871. __DtXlateSrchData * srchData,
  872. XrmQuark specDirectionQuark)
  873. { /*$CODE$*/
  874. int score = 0;
  875. __DtXlateType type = __DtXLATE_TYPE_NONE;
  876. if (specDirectionQuark == srchData->inhibitQuark)
  877. return False; /* RETURN: no match */
  878. /* Note that the type and score expressions are assignments */
  879. if (! ( ( (type=__DtXLATE_TYPE_REGEX)
  880. && (specDirectionQuark == srchData->moreThanQuark))
  881. || ( (type=__DtXLATE_TYPE_PURE)
  882. && (score=1)
  883. && (specDirectionQuark == srchData->equalsToQuark))
  884. || ( (type=__DtXLATE_TYPE_CONTAINS)
  885. && (score=1)
  886. && (specDirectionQuark == srchData->containsQuark)) ) )
  887. return False; /* RETURN: no match */
  888. srchData->curScore += score;
  889. srchData->curTransType = type;
  890. return True; /* RETURN: direction matches */
  891. } /*$END$*/
  892. #if DOC
  893. /*========================================================*/
  894. $PFUNBEG$: CheckSearchStdValueMatchesSpec()
  895. $1LINER$: Matches search pattern to spec data
  896. $SUMMARY$:
  897. $ARGS$:
  898. $RETURNS$:
  899. /*================================================$SKIP$==*/
  900. #endif
  901. static
  902. Boolean CheckSearchStdValueMatchesSpec(
  903. __DtXlateSrchData * srchData,
  904. XrmQuark * specStdValueQuarks)
  905. { /*$CODE$*/
  906. int score = 0;
  907. int unmatched = 0;
  908. XrmQuark * patQuarks;
  909. /* walk through all available quarks */
  910. for ( patQuarks = srchData->stdValueQuarks;
  911. *specStdValueQuarks != NULLQUARK && *patQuarks != NULLQUARK;
  912. specStdValueQuarks++, patQuarks++ )
  913. {
  914. char * specStr = XrmQuarkToString(*specStdValueQuarks);
  915. char * patStr = XrmQuarkToString(*patQuarks);
  916. if ( CheckForMatchall(srchData,specStr,patStr) == True
  917. || CheckForMatchall(srchData,patStr,specStr) == True )
  918. continue; /* no score for a matchall */
  919. /* is not exact match, match fails */
  920. /* be case insensitive when comparing standard values */
  921. if ( *patQuarks != *specStdValueQuarks
  922. && strCaseiCmp(specStr,patStr) == False )
  923. return False; /* RETURN: no match */
  924. /* one more match--increase score, go to next */
  925. score++;
  926. }
  927. /* find out how many stdValue fields were left unmatched */
  928. for ( unmatched = 0;
  929. *specStdValueQuarks != NULLQUARK;
  930. specStdValueQuarks++ )
  931. { unmatched++; }
  932. /* Score is combo of the number matched - the number unmatched
  933. and not counting the number matchalls that coincided with
  934. the search pattern. This technique allows the spec for
  935. val1 to be at "better" match than the one for val2, and
  936. val2 to be a better match than val3, and val3 to be a better
  937. match than val4.
  938. .a.std : val1 querypattern = a.std
  939. .?.std : val2 querypattern = a.std
  940. .?1.std : \\1val3 querypattern = a.std
  941. .a.std : val4 querypattern = ?.std
  942. .?.std : val5 querypattern = ?.std
  943. .?1.std : \\1val6 querypattern = ?.std
  944. .a.std.? : val4 querypattern = a.std
  945. .?.std.? : val5 querypattern = a.std
  946. .?.std.?1 : \\1val5 querypattern = a.std
  947. .?1.std.? : \\1val5 querypattern = a.std
  948. .?1.std.?2 : \\1\\2val5 querypattern = a.std
  949. .a.std.? : val4 querypattern = a.std.b
  950. .?.std.? : val5 querypattern = a.std.b
  951. .?.std.?1 : \\1val5 querypattern = a.std.b
  952. .?1.std.? : \\1val5 querypattern = a.std.b
  953. .?1.std.?2 : \\1\\2val5 querypattern = a.std.b
  954. */
  955. srchData->curScore += score + MAXSTDQUARKS - unmatched;
  956. return True; /* RETURN: direction matches */
  957. } /*$END$*/
  958. #if DOC
  959. /*========================================================*/
  960. $PFUNBEG$: CheckSearchOpValueMatchesSpec()
  961. $1LINER$: Matches search pattern to spec data
  962. $SUMMARY$:
  963. $ARGS$:
  964. $RETURNS$:
  965. /*================================================$SKIP$==*/
  966. #endif
  967. static
  968. Boolean CheckSearchOpValueMatchesSpec(
  969. __DtXlateSrchData * srchData,
  970. const char * specOpValue)
  971. { /*$CODE$*/
  972. char opValBuf[MAXRHSSIZE]; /* max supported RHS size */
  973. char * pOpValBuf = opValBuf; /* need this for StripMeta... call */
  974. size_t opValLen;
  975. Boolean matches = False;
  976. /* copy value to mutable memory */
  977. strncpy(opValBuf,specOpValue,sizeof(opValBuf));
  978. opValBuf[sizeof(opValBuf)-1] = EOS;
  979. opValLen = strlen(opValBuf);
  980. /* depending on the translation type of the spec, do a
  981. regexex match of the spec value pattern to the search
  982. value or do a pure match */
  983. if (srchData->curTransType == __DtXLATE_TYPE_REGEX)
  984. {
  985. #if defined(sun)
  986. char * ex = NULL;
  987. /* True: leave escape char in place */
  988. StripMetaAndReplaceEscSubex(&pOpValBuf,True,NULL);
  989. /* we need to use regexex to pattern match */
  990. /* and we need to save of the reference value matches */
  991. if ( (ex = compile(opValBuf,NULL,NULL)) != NULL
  992. && advance(srchData->opValue,ex) != 0)
  993. {
  994. int matchSize;
  995. int subExCnt = nbra; /* Sun global for advance() */
  996. matches = True; /* if got this far */
  997. /* need due to bug in advance()--operation doesn't meet documentation */
  998. if (NULL == loc1) loc1=(char *)srchData->opValue;
  999. /* inc score by the size of the match after
  1000. scaling for the maximum possible match size */
  1001. matchSize = loc2 - loc1; /*loc[12] are Sun globals for advance()*/
  1002. if (matchSize < 0 || matchSize >= sizeof(opValBuf)) matchSize = 0;
  1003. /* NOTE: this scoring code should be identical in the
  1004. Sun-specific and non-Sun code blocks */
  1005. if (matchSize == strlen(srchData->opValue))
  1006. {
  1007. /* if the matchSize is the length of srchData->opValue,
  1008. then we have a complete match. In this case, use the
  1009. specificity of the pattern to pick the best match */
  1010. /* NOTE: opValLen is a crude measure of specificity.
  1011. A better measure would be to count the number of
  1012. literals/ranges that matched exactly. When doing this,
  1013. a perfect match without regex syntax should rank higher
  1014. than a perfect match with regex syntax. This is one
  1015. area where the current algorithm breaks. For example:
  1016. opValue=23, pat1=23, pat2=[0-9]3.
  1017. Both patterns match and pat1 is a better match,
  1018. but not with the current length-based algorithm. */
  1019. /* NOTE: this formula does not advance the score
  1020. to sizeof(opValBuf) for a perfect match. Other match
  1021. formulas use sizeof(opValBuf) as the max value
  1022. to indicate a perfect match. */
  1023. srchData->curScore += matchSize + opValLen;
  1024. }
  1025. else
  1026. {
  1027. /* if its not a complete match, inc score by match size */
  1028. srchData->curScore += matchSize;
  1029. }
  1030. /* put sub expression matching stuff in srchData->curSubEx */
  1031. for( ; nbra > 0; nbra-- )
  1032. {
  1033. srchData->curSubEx[nbra].rm_so = braslist[nbra-1] - loc1;
  1034. srchData->curSubEx[nbra].rm_eo = braelist[nbra-1] - loc1;
  1035. }
  1036. }
  1037. if (ex) free(ex);
  1038. #else
  1039. regex_t re;
  1040. /* True: leave escape char in place */
  1041. StripMetaAndReplaceEscSubex(&pOpValBuf,True,NULL);
  1042. /* we need to use regexex to pattern match */
  1043. /* and we need to save of the reference value matches */
  1044. if ( regcomp(&re,opValBuf,0) == 0
  1045. && regexec(&re,srchData->opValue,
  1046. XtNumber(srchData->curSubEx),srchData->curSubEx,0) == 0)
  1047. {
  1048. int matchSize;
  1049. matches = True; /* if got this far */
  1050. /* inc score by the size of the match after
  1051. scaling for the maximum possible match size */
  1052. matchSize = srchData->curSubEx[0].rm_eo -
  1053. srchData->curSubEx[0].rm_so;
  1054. /* NOTE: this scoring code should be identical in the
  1055. Sun-specific and non-Sun code blocks */
  1056. if (matchSize == strlen(srchData->opValue))
  1057. {
  1058. /* if the matchSize is the length of srchData->opValue,
  1059. then we have a complete match. In this case, use the
  1060. specificity of the pattern to pick the best match */
  1061. /* NOTE: opValLen is a crude measure of specificity.
  1062. A better measure would be to count the number of
  1063. literals/ranges that matched exactly. When doing this,
  1064. a perfect match without regex syntax should rank higher
  1065. than a perfect match with regex syntax. This is one
  1066. area where the current algorithm breaks. For example:
  1067. opValue=23, pat1=23, pat2=[0-9]3.
  1068. Both patterns match and pat1 is a better match,
  1069. but not with the current length-based algorithm. */
  1070. /* NOTE: this formula does not advance the score
  1071. to sizeof(opValBuf) for a perfect match. Other match
  1072. formulas use sizeof(opValBuf) as the max value
  1073. to indicate a perfect match. */
  1074. srchData->curScore += matchSize + opValLen;
  1075. }
  1076. else
  1077. {
  1078. /* if its not a complete match, inc score by match size */
  1079. srchData->curScore += matchSize;
  1080. }
  1081. /* sub expression matching stuff already in srchData->curSubEx */
  1082. }
  1083. regfree(&re);
  1084. #endif
  1085. }
  1086. else /* (srchData->curTransType == __DtXLATE_TYPE_PURE || __DtXLATE_TYPE_CONTAINS */
  1087. {
  1088. char * opValueInBuf;
  1089. /* False: strip escape char as well */
  1090. StripMetaAndReplaceEscSubex(&pOpValBuf,False,NULL);
  1091. matches = (strcmp(srchData->opValue,opValBuf) == 0);
  1092. /* if matches, inc score to show a perfect match (max poss value) */
  1093. if (matches) srchData->curScore += sizeof(opValBuf);
  1094. /* don't test for contains if a perfect match or a pure match spec */
  1095. if (matches || srchData->curTransType == __DtXLATE_TYPE_PURE)
  1096. return matches; /* RETURN */
  1097. /* (srchData->curTransType == __DtXLATE_TYPE_CONTAINS) */
  1098. /* is opValue contained in opValBuf? */
  1099. /* is opValBuf contained in opValue? */
  1100. opValueInBuf = NULL;
  1101. matches = (opValBuf[0] != EOS && srchData->opValue[0] != EOS)
  1102. && ((opValueInBuf=strstr(opValBuf,srchData->opValue)) != NULL
  1103. || strstr(srchData->opValue,opValBuf) != NULL);
  1104. /* if matches, inc score to show a contains match */
  1105. if (matches)
  1106. {
  1107. if (opValueInBuf) srchData->curScore += strlen(srchData->opValue);
  1108. else srchData->curScore += strlen(opValBuf);
  1109. }
  1110. }
  1111. return matches;
  1112. } /*$END$*/
  1113. #if DOC
  1114. /*========================================================*/
  1115. $PFUNBEG$: FindStdToOpMatchCB()
  1116. $1LINER$: Matches std value of entry to search pattern; gets op value
  1117. $SUMMARY$:
  1118. $ARGS$:
  1119. $RETURNS$:
  1120. /*================================================$SKIP$==*/
  1121. #endif
  1122. static
  1123. Bool FindStdToOpMatchCB(
  1124. XrmDatabase * database,
  1125. XrmBindingList bindings,
  1126. XrmQuarkList quarks,
  1127. XrmRepresentation * type,
  1128. XrmValue * value,
  1129. XPointer client_data)
  1130. { /*$CODE$*/
  1131. __DtXlateSrchData * srchData = (__DtXlateSrchData *) client_data;
  1132. /* always begin scoring from 0 and replacement values at NULL */
  1133. srchData->curScore = 0;
  1134. memset(srchData->curSpecRefs,0, sizeof(srchData->curSpecRefs));
  1135. #ifdef DBG_MATCHING
  1136. fprintf(stderr,"FindStdToOpMatch: "); PrintDbEntry(quarks,value);
  1137. #endif
  1138. /* check for a match */
  1139. if ( CheckSearchPlatformMatchesSpec(srchData,
  1140. quarks[PLATFORM_QUARK]) == False)
  1141. return False; /* continue enumeration */
  1142. #ifdef DBG_MATCHING
  1143. fprintf(stderr,"platform matches\n");
  1144. #endif
  1145. if ( CheckSearchVerMatchesSpec(srchData,
  1146. quarks[VERSION_QUARK]) == False)
  1147. return False; /* continue enumeration */
  1148. #ifdef DBG_MATCHING
  1149. fprintf(stderr,"ver matches\n");
  1150. #endif
  1151. if ( CheckSearchOperMatchesSpec(srchData,
  1152. quarks[OPERS_QUARK]) == False)
  1153. return False; /* continue enumeration */
  1154. #ifdef DBG_MATCHING
  1155. fprintf(stderr,"oper matches\n");
  1156. #endif
  1157. if ( CheckSearchDirStdToOpMatchesSpec(srchData,
  1158. quarks[DIRECTION_QUARK]) == False)
  1159. return False; /* continue enumeration */
  1160. #ifdef DBG_MATCHING
  1161. fprintf(stderr,"kind matches\n");
  1162. #endif
  1163. /* now check for std value match and, if it is
  1164. the best match so far, record the value */
  1165. if ( CheckSearchStdValueMatchesSpec(srchData,
  1166. &quarks[FIRSTSTD_QUARK]) == False )
  1167. {
  1168. if (srchData->db->debugMode)
  1169. {
  1170. fprintf(stderr,"mismatch ");
  1171. PrintDbEntry(quarks,value);
  1172. }
  1173. return False; /* continue enumeration */
  1174. }
  1175. #ifdef DBG_MATCHING
  1176. fprintf(stderr,"std value matches\n");
  1177. #endif
  1178. if (srchData->db->debugMode)
  1179. {
  1180. fprintf(stderr,"match (%d) ",srchData->curScore);
  1181. PrintDbEntry(quarks,value);
  1182. }
  1183. /* we have a match! (we made it through all match checks) */
  1184. /* is it better than or same as any earlier match? */
  1185. if ( srchData->curScore >= srchData->bestScore )
  1186. {
  1187. /* recall that all strings are owned by Xrm==>no need to free them */
  1188. srchData->bestScore = srchData->curScore;
  1189. srchData->bestTransType = srchData->curTransType;
  1190. memcpy(srchData->bestSpecRefs,srchData->curSpecRefs,
  1191. sizeof(srchData->bestSpecRefs)); /* no array assignment in C */
  1192. srchData->opValue = value->addr;
  1193. }
  1194. return False; /* continue enumeration */
  1195. } /*$END$*/
  1196. #if DOC
  1197. /*========================================================*/
  1198. $PFUNBEG$: FindOpToStdMatchCB()
  1199. $1LINER$: Matches op value of entry to search pattern; gets std value
  1200. $SUMMARY$:
  1201. $ARGS$:
  1202. $RETURNS$:
  1203. /*================================================$SKIP$==*/
  1204. #endif
  1205. static
  1206. Bool FindOpToStdMatchCB(
  1207. XrmDatabase * database,
  1208. XrmBindingList bindings,
  1209. XrmQuarkList quarks,
  1210. XrmRepresentation * type,
  1211. XrmValue * value,
  1212. XPointer client_data)
  1213. { /*$CODE$*/
  1214. __DtXlateSrchData * srchData = (__DtXlateSrchData *) client_data;
  1215. /* always begin scoring from 0 and subexpression indices at -1 */
  1216. srchData->curScore = 0;
  1217. memset(srchData->curSubEx,-1, sizeof(srchData->curSubEx));
  1218. #ifdef DBG_MATCHING
  1219. fprintf(stderr,"FindOpToStdMatch: "); PrintDbEntry(quarks,value);
  1220. #endif
  1221. /* check for a match */
  1222. if ( CheckSearchPlatformMatchesSpec(srchData,
  1223. quarks[PLATFORM_QUARK]) == False)
  1224. return False; /* continue enumeration */
  1225. #ifdef DBG_MATCHING
  1226. fprintf(stderr,"platform matches\n");
  1227. #endif
  1228. if ( CheckSearchVerMatchesSpec(srchData,
  1229. quarks[VERSION_QUARK]) == False)
  1230. return False; /* continue enumeration */
  1231. #ifdef DBG_MATCHING
  1232. fprintf(stderr,"ver matches\n");
  1233. #endif
  1234. if ( CheckSearchOperMatchesSpec(srchData,
  1235. quarks[OPERS_QUARK]) == False)
  1236. return False; /* continue enumeration */
  1237. #ifdef DBG_MATCHING
  1238. fprintf(stderr,"oper matches\n");
  1239. #endif
  1240. if ( CheckSearchDirOpToStdMatchesSpec(srchData,
  1241. quarks[DIRECTION_QUARK]) == False)
  1242. return False; /* continue enumeration */
  1243. #ifdef DBG_MATCHING
  1244. fprintf(stderr,"kind matches\n");
  1245. #endif
  1246. /* now check for op value match and, if it is
  1247. the best match so far, record the std value */
  1248. if ( CheckSearchOpValueMatchesSpec(srchData,
  1249. value->addr) == False )
  1250. {
  1251. if (srchData->db->debugMode)
  1252. {
  1253. fprintf(stderr,"mismatch ");
  1254. PrintDbEntry(quarks,value);
  1255. }
  1256. return False; /* continue enumeration */
  1257. }
  1258. #ifdef DBG_MATCHING
  1259. fprintf(stderr,"op value matches\n");
  1260. #endif
  1261. if (srchData->db->debugMode)
  1262. {
  1263. fprintf(stderr,"match (%d) ",srchData->curScore);
  1264. PrintDbEntry(quarks,value);
  1265. }
  1266. /* we have a match! (we made it through all match checks) */
  1267. /* is it better than or same as any earlier match? */
  1268. if ( srchData->curScore >= srchData->bestScore )
  1269. {
  1270. XrmQuarkList stdQ;
  1271. XrmQuarkList curQ;
  1272. /* recall that all strings are owned by Xrm==>no need to free them */
  1273. srchData->bestScore = srchData->curScore;
  1274. srchData->bestTransType = srchData->curTransType;
  1275. memcpy(srchData->bestSubEx,srchData->curSubEx,
  1276. sizeof(srchData->bestSubEx)); /* no array assignment in C */
  1277. /* store off the std value of the best match */
  1278. stdQ = srchData->stdValueQuarks;
  1279. curQ = &quarks[FIRSTSTD_QUARK];
  1280. while ( (*stdQ = *curQ) != NULLQUARK ) stdQ++, curQ++;
  1281. }
  1282. return False; /* continue enumeration */
  1283. } /*$END$*/
  1284. #if DOC
  1285. /*========================================================*/
  1286. $PFUNBEG$: DoCommonSrchDataPrep
  1287. $1LINER$: Prep srchData to search for a pattern
  1288. $SUMMARY$:
  1289. $ARGS$:
  1290. $RETURNS$:
  1291. /*================================================$SKIP$==*/
  1292. #endif
  1293. static
  1294. void DoCommonSrchDataPrep(
  1295. __DtXlateSrchData * srchData,
  1296. _DtXlateDb db,
  1297. const char * platform,
  1298. const int version,
  1299. const char * operation)
  1300. { /*$CODE$*/
  1301. int verNum = version; /* for lint */
  1302. /* zero the search data */
  1303. memset(srchData,0,sizeof(__DtXlateSrchData));
  1304. /* set the db */
  1305. srchData->db = db;
  1306. /* build filter list for enumerating the db */
  1307. if (verNum < MATCHALL_VER) verNum = MATCHALL_VER;
  1308. srchData->platformStr = platform;
  1309. srchData->platformQuark = (platform?XrmStringToQuark(platform):NULLQUARK);
  1310. srchData->version = verNum;
  1311. sprintf(srchData->verStr,"%d",verNum);
  1312. srchData->operStr = operation;
  1313. srchData->operStrLen = strlen(operation);
  1314. srchData->operQuark = (operation ? XrmStringToQuark(operation) : NULLQUARK);
  1315. srchData->lessThanQuark = XrmStringToQuark(LESSTHAN_STR);
  1316. srchData->equalsToQuark = XrmStringToQuark(EQUALS_STR);
  1317. srchData->containsQuark = XrmStringToQuark(CONTAINS_STR);
  1318. srchData->moreThanQuark = XrmStringToQuark(MORETHAN_STR);
  1319. srchData->inhibitQuark = XrmStringToQuark(INHIBIT_STR);
  1320. } /*$END$*/
  1321. /*========================================================*/
  1322. /*=============== Public Xlate routines ==================*/
  1323. /*========================================================*/
  1324. #if DOC
  1325. /*========================================================*/
  1326. $FUNBEG$: _DtXlateOpenDb()
  1327. $1LINER$: Open a translation database
  1328. $SUMMARY$:
  1329. Opens a translation resource database and returns a
  1330. reference to it in ret_db.
  1331. Initializes the _DtXlateDb object to ready for use.
  1332. If an error occurs, _DtXlateDb is set to NULL.
  1333. $ARGS$:
  1334. $RETURNS$:
  1335. 0: no error occurred
  1336. -1: if ret_db is NULL
  1337. if XrmGetFileDatabase() failed on databaseName
  1338. if malloc fails to alloc a db structure
  1339. /*================================================$SKIP$==*/
  1340. #endif
  1341. int _DtXlateOpenDb(
  1342. const char * databaseName,
  1343. _DtXlateDb * ret_db)
  1344. { /*$CODE$*/
  1345. XrmDatabase xrmDb;
  1346. __DtXlateDbRec * dbRec = NULL;
  1347. char * path = NULL;
  1348. if(NULL == ret_db) return -1; /* RETURN */
  1349. *ret_db = NULL;
  1350. /* Do NOT check for whether *ret_db is already
  1351. a valid db; this is none of our affair. */
  1352. /* get an absolute path for the file */
  1353. path = ExpandPath(databaseName);
  1354. if (NULL == path) return -1; /* RETURN */
  1355. xrmDb = XrmGetFileDatabase(path);
  1356. if (NULL == xrmDb) { free(path); return -1; } /* RETURN */
  1357. /* alloc a db ref */
  1358. dbRec = (__DtXlateDbRec *) calloc(1,sizeof(__DtXlateDbRec));
  1359. if(NULL == dbRec)
  1360. {
  1361. XrmDestroyDatabase(xrmDb);
  1362. free(path);
  1363. return -1; /* RETURN */
  1364. }
  1365. /* and populate it */
  1366. dbRec->xrmDb = xrmDb;
  1367. dbRec->initGuard = INIT_OCCURRED;
  1368. /* check for debug mode */
  1369. SetDebugModeState(dbRec);
  1370. if (dbRec->debugMode)
  1371. fprintf(stderr,"_DtXlateOpenDb: opened: %s; new db: %p\n",path, (void *)dbRec);
  1372. *ret_db = dbRec;
  1373. free(path);
  1374. return 0; /* RETURN */
  1375. } /*$END$*/
  1376. #if DOC
  1377. /*========================================================*/
  1378. $FUNBEG$: _DtXlateOpenAndMergeDbs()
  1379. $1LINER$: Opens a translation database and merges with earlier dbs
  1380. $SUMMARY$:
  1381. Opens a translation resource database and returns a
  1382. reference to it in ret_db.
  1383. Initializes the _DtXlateDb object to ready for use.
  1384. $ARGS$:
  1385. $RETURNS$:
  1386. 0: no error occurred
  1387. -1: if io_db is NULL
  1388. if XrmGetFileDatabase() failed on databaseName
  1389. /*================================================$SKIP$==*/
  1390. #endif
  1391. int _DtXlateOpenAndMergeDbs(
  1392. const char * databaseName,
  1393. _DtXlateDb * io_db)
  1394. { /*$CODE$*/
  1395. XrmDatabase xrmDb;
  1396. char * path;
  1397. int ret;
  1398. if(NULL == io_db) return -1; /* RETURN */
  1399. /* if a db has not yet been opened */
  1400. if( NULL == *io_db
  1401. || (*io_db)->initGuard != INIT_OCCURRED
  1402. || (*io_db)->xrmDb == NULL)
  1403. {
  1404. ret = _DtXlateOpenDb(databaseName,io_db); /* RETURN */
  1405. if ( (*io_db) && (*io_db)->debugMode)
  1406. fprintf(stderr,"_DtXlateOpenAndMergeDb: "
  1407. "used _DtXlateOpenDb to open first file\n");
  1408. return ret; /* RETURN */
  1409. }
  1410. if ( (*io_db) && (*io_db)->debugMode)
  1411. fprintf(stderr,"_DtXlateOpenAndMergeDb: "
  1412. "target file: %s; existing db: %p\n",databaseName, (void *) *io_db);
  1413. /* a db has been opened, let's merge with it */
  1414. /* get an absolute path for the file */
  1415. path = ExpandPath(databaseName);
  1416. if (NULL == path) goto Failed; /* RETURN */
  1417. xrmDb = XrmGetFileDatabase(path);
  1418. if (NULL == xrmDb) goto Failed; /* RETURN */
  1419. /* merge and destroy xrmDb for me */
  1420. XrmMergeDatabases(xrmDb,&(*io_db)->xrmDb);
  1421. /* check for debug mode */
  1422. SetDebugModeState(*io_db);
  1423. if ((*io_db)->debugMode)
  1424. fprintf(stderr,"_DtXlateOpenAndMergeDb: "
  1425. "opened: %s; merged db: %p\n",path, (void *) *io_db);
  1426. free(path);
  1427. return 0; /* RETURN */
  1428. Failed:
  1429. if ( (*io_db) && (*io_db)->debugMode)
  1430. fprintf(stderr,"_DtXlateOpenAndMergeDb: open failed; file: %s\n",
  1431. (path ? path : (databaseName ? databaseName : "NULL") ) );
  1432. if (path) free(path);
  1433. return -1; /* RETURN */
  1434. } /*$END$*/
  1435. #if DOC
  1436. /*========================================================*/
  1437. $FUNBEG$: _DtXlateMergeDbs()
  1438. $1LINER$: Merges two open dbs into one and closes the merged-in db.
  1439. $SUMMARY$:
  1440. Merges two databases into one and closes the merged db.
  1441. The io_dbToMerge database must be a valid translation database.
  1442. The io_dbToMerge database is merged into the io_mergeIntoDb.
  1443. The io_mergeIntoDb may either be invalid or valid. If invalid,
  1444. the io_dbToMerge database is simply moved over to io_mergeIntoDb.
  1445. If io_mergeIntoDb is valid, the entries in the io_dbToMerge
  1446. database are merged into it and take precedence over entries in the
  1447. io_mergeIntoDb, and the io_dbToMerge database is closed.
  1448. $ARGS$:
  1449. io_dbToMerge: database to merge into io_mergeIntoDb
  1450. io_mergeIntoDb: database to hold merged result
  1451. $RETURNS$:
  1452. 0: no error occurred
  1453. -1: if io_dbToMerge or io_mergeIntoDb is NULL
  1454. if *io_dbToMerge is NULL or uninitialized
  1455. /*================================================$SKIP$==*/
  1456. #endif
  1457. int _DtXlateMergeDbs(
  1458. _DtXlateDb * io_dbToMerge,
  1459. _DtXlateDb * io_mergeIntoDb)
  1460. { /*$CODE$*/
  1461. /* check args */
  1462. if( NULL == io_mergeIntoDb
  1463. || NULL == io_dbToMerge
  1464. || NULL == *io_dbToMerge
  1465. || (*io_dbToMerge)->initGuard != INIT_OCCURRED
  1466. || (*io_dbToMerge)->xrmDb == NULL)
  1467. return -1; /* RETURN */
  1468. /* check for debug mode */
  1469. if ( ((*io_mergeIntoDb) && (*io_mergeIntoDb)->debugMode)
  1470. || (*io_dbToMerge)->debugMode)
  1471. fprintf(stderr,"_DtXlateMergeDbs: "
  1472. "mergeIntoDb: %p; dbToMerge: %p\n", (void *) *io_mergeIntoDb, (void *) *io_dbToMerge);
  1473. /* if db_mergeIntoDb has not yet been opened */
  1474. if( NULL == *io_mergeIntoDb
  1475. || (*io_mergeIntoDb)->initGuard != INIT_OCCURRED
  1476. || (*io_mergeIntoDb)->xrmDb == NULL)
  1477. {
  1478. /* just move dbToMerge into mergeIntoDb */
  1479. *io_mergeIntoDb = *io_dbToMerge;
  1480. DeleteDbMem(io_dbToMerge);
  1481. return 0; /* RETURN */
  1482. }
  1483. /* merge and destroy io_dbToMerge->xrmDb for me */
  1484. XrmMergeDatabases((*io_dbToMerge)->xrmDb,&(*io_mergeIntoDb)->xrmDb);
  1485. DeleteDbMem(io_dbToMerge);
  1486. /* check for debug mode */
  1487. SetDebugModeState(*io_mergeIntoDb);
  1488. if ((*io_mergeIntoDb)->debugMode)
  1489. fprintf(stderr,"merged db: %p\n", (void *) *io_mergeIntoDb);
  1490. return 0;
  1491. } /*$END$*/
  1492. #if DOC
  1493. /*========================================================*/
  1494. $FUNBEG$: _DtXlateOpenAllDbs()
  1495. $1LINER$: Open and merge all locale translation databases that can be found
  1496. $SUMMARY$:
  1497. DtXlateOpenAllDbs() locates all translation databases
  1498. present in the search paths directories.
  1499. $ARGS$:
  1500. searchPaths: ':' separated list of directories
  1501. databaseName: name of the database file in those directories
  1502. ret_db: the reference to the open database is stored here
  1503. $RETURNS$:
  1504. 0: at least one database was opened
  1505. -1: no database was opened
  1506. /*================================================$SKIP$==*/
  1507. #endif
  1508. int _DtXlateOpenAllDbs(
  1509. const char * searchPaths,
  1510. const char * databaseName,
  1511. _DtXlateDb * ret_db)
  1512. { /*$CODE$*/
  1513. const char * workStart = searchPaths;
  1514. const char * separator = NULL;
  1515. char dbFile[MAXPATHLEN+1];
  1516. int ret = ~0; /* all bits set */
  1517. /* cycle through the paths, opening each one */
  1518. do
  1519. {
  1520. int workLen = 0;
  1521. const char * slash = NULL;
  1522. dbFile[0] = EOS;
  1523. /* isolate the next part of the path */
  1524. _DtMBStrchr (workStart, PATH_SEPARATOR, -1, &separator);
  1525. if (NULL == separator) _DtMBStrchr (workStart, EOS, -1, &separator);
  1526. if (NULL == separator) break; /* BREAK */
  1527. workLen = separator - workStart; /* don't include +1 for EOS */
  1528. /* copy over the path component */
  1529. strncpy(dbFile,workStart,workLen);
  1530. workStart = separator + 1;
  1531. /* add a slash to end of path component, if needed */
  1532. *(dbFile+workLen) = EOS; /* add an EOS for _DtMBStrrchr to find */
  1533. _DtMBStrrchr(dbFile,DIR_SLASH,-1,&slash);
  1534. if (slash != dbFile+workLen-1) /* is slash last char of path? */
  1535. {
  1536. *(dbFile+workLen) = DIR_SLASH;
  1537. workLen++;
  1538. }
  1539. /* append the filename and EOS */
  1540. strcpy(dbFile+workLen,databaseName);
  1541. /*printf("Working on: %s\n", dbFile); **DBG*/
  1542. /* open and merge the database with previously opened dbs */
  1543. /* by ANDing, we determine whether at least one call returned 0 */
  1544. ret &= _DtXlateOpenAndMergeDbs(dbFile,ret_db);
  1545. } while ( *separator != EOS );
  1546. if (*ret_db && (*ret_db)->debugMode)
  1547. fprintf(stderr,"_DtXlateOpenAllDbs: completed\n"
  1548. " srchpaths: %s; db file: %s\n",searchPaths,databaseName);
  1549. return (ret == 0 ? 0 : -1); /* ret != 0 ==> no db was opened */
  1550. } /*$END$*/
  1551. #if DOC
  1552. /*========================================================*/
  1553. $FUNBEG$: _DtXlateCloseDb()
  1554. $1LINER$: Close an open translation database
  1555. $SUMMARY$:
  1556. _DtXlafteCloseDb() releases all memory associated with
  1557. the translation database. Further use of the database
  1558. object is an error.
  1559. $ARGS$:
  1560. $RETURNS$:
  1561. 0: database was valid and has been closed
  1562. -1: invalid database pointer
  1563. /*================================================$SKIP$==*/
  1564. #endif
  1565. int _DtXlateCloseDb(
  1566. _DtXlateDb * io_db)
  1567. { /*$CODE$*/
  1568. __DtXlateDbRec * dbRec;
  1569. if( NULL == io_db
  1570. || NULL == (dbRec = *io_db) /* dbRec assigned */
  1571. || dbRec->initGuard != INIT_OCCURRED)
  1572. return -1; /* RETURN */
  1573. XrmDestroyDatabase(dbRec->xrmDb);
  1574. if (dbRec->debugMode) fprintf(stderr,"_DtXlateCloseDb: %p\n", (void *) dbRec);
  1575. /* zero out object mem and free it */
  1576. DeleteDbMem(io_db);
  1577. return 0;
  1578. } /*$END$*/
  1579. #if DOC
  1580. /*========================================================*/
  1581. $FUNBEG$: _DbXlateStdToOpValue()
  1582. $1LINER$: Translates a standardized spec to an operation-specific value
  1583. $SUMMARY$:
  1584. Looks up the best translation of the standard value for an
  1585. operation and places a pointer to the translation string
  1586. at the location pointed to by ret_opValue.
  1587. The translated string was allocated using malloc() and
  1588. must be freed when no longer needed.
  1589. If ret_opValue is NULL, the function merely verifies that
  1590. a valid translation exists.
  1591. $ARGS$:
  1592. db: a translation database
  1593. platform: the platform string (see _DtXlateGetXlateEnv())
  1594. version: the version number (see _DtXlateGetXlateEnv())
  1595. operation: the operation of interest, e.g. "setlocale"
  1596. stdValue: the standard value pattern
  1597. ret_opValue: location where ptr to translated string is stored
  1598. ret_reserved: reserved for future use
  1599. $RETURNS$:
  1600. 0: translation found
  1601. -1: invalid database (NULL ptr, not opened)
  1602. no operation was specified
  1603. query failed to find a match
  1604. /*================================================$SKIP$==*/
  1605. #endif
  1606. int _DtXlateStdToOpValue(
  1607. _DtXlateDb db,
  1608. const char * platform,
  1609. const int version,
  1610. const char * operation,
  1611. const char * stdValue,
  1612. char * * ret_opValue,
  1613. void * ret_reserved)
  1614. { /*$CODE$*/
  1615. __DtXlateSrchData srchData;
  1616. XrmQuark empty = NULLQUARK;
  1617. if ( NULL == db
  1618. || db->initGuard != INIT_OCCURRED
  1619. || NULL == operation
  1620. || operation[0] == EOS)
  1621. return -1; /* RETURN error */
  1622. /* prep srch data for search */
  1623. DoCommonSrchDataPrep(&srchData,db,platform,version,operation);
  1624. /* handle a rare case */
  1625. if (NULL == stdValue)
  1626. {
  1627. if (db->debugMode) fprintf(stderr,"_DtXlateStdToOpValue: NULL std value\n");
  1628. if (ret_opValue) *ret_opValue = NULL;
  1629. return -1; /* RETURN error */
  1630. }
  1631. /* build std value list for use during comparison */
  1632. srchData.stdValueQuarks[0] = NULLQUARK;
  1633. if (NULL != stdValue && stdValue[0] != EOS)
  1634. XrmStringToQuarkList(stdValue,srchData.stdValueQuarks);
  1635. if (db->debugMode)
  1636. fprintf(stderr,"_DtXlateStdToOpValue: %s.%d.%s.%s: <op>\n",
  1637. platform,version,operation,stdValue);
  1638. /* scan through this Db looking for matches and put in search */
  1639. XrmEnumerateDatabase(db->xrmDb,&empty,&empty,
  1640. XrmEnumAllLevels, FindStdToOpMatchCB, (XPointer) &srchData);
  1641. if ( srchData.opValue != NULL
  1642. && srchData.bestTransType != __DtXLATE_TYPE_INHIBIT )
  1643. {
  1644. char * opValue;
  1645. if (ret_opValue == NULL)
  1646. {
  1647. if (db->debugMode) fprintf(stderr,"translation exists\n");
  1648. return 0; /* RETURN: translation exists */
  1649. }
  1650. /* alloc the string to return */
  1651. opValue = strdup(srchData.opValue);
  1652. if (db->debugMode) fprintf(stderr,"raw opval:%s\n",opValue);
  1653. /* do quote and escape removal and ref replacement in the opValue */
  1654. if ( srchData.bestTransType == __DtXLATE_TYPE_REGEX )
  1655. StripMetaAndReplaceEscSubex(&opValue,False,srchData.bestSpecRefs);
  1656. else
  1657. StripMetaAndReplaceEscSubex(&opValue,False,NULL);
  1658. if (db->debugMode) fprintf(stderr,"op value:%s\n",opValue);
  1659. *ret_opValue = opValue;
  1660. return 0; /* RETURN: search successful */
  1661. }
  1662. return -1; /* RETURN: search failed */
  1663. } /*$END$*/
  1664. #if DOC
  1665. /*========================================================*/
  1666. $FUNBEG$: _DbXlateOpToStdValue()
  1667. $1LINER$: Translates an operation-specific value to a standardized one
  1668. $SUMMARY$:
  1669. Looks up the best translation of the operation value for an
  1670. operation and places a pointer to the standard string
  1671. at the location pointed to by ret_stdValue.
  1672. The standard string was allocated using malloc() and
  1673. must be freed when no longer needed.
  1674. If ret_stdValue is NULL, the function merely verifies that
  1675. a valid translation exists.
  1676. $ARGS$:
  1677. db: a translation database
  1678. platform: the platform string (see _DtXlateGetXlateEnv())
  1679. version: the version number (see _DtXlateGetXlateEnv())
  1680. operation: the operation of interest, e.g. "setlocale"
  1681. opValue: the operation-specific value pattern
  1682. ret_stdValue: location where ptr to standard string is stored
  1683. ret_reserved: reserved for future use
  1684. $RETURNS$:
  1685. 0: translation found
  1686. -1: invalid database (NULL ptr, not opened)
  1687. no operation was specified
  1688. query failed to find a match
  1689. /*================================================$SKIP$==*/
  1690. #endif
  1691. int _DtXlateOpToStdValue(
  1692. _DtXlateDb db,
  1693. const char * platform,
  1694. const int version,
  1695. const char * operation,
  1696. const char * opValue,
  1697. char * * ret_stdValue,
  1698. void * ret_reserved)
  1699. { /*$CODE$*/
  1700. __DtXlateSrchData srchData;
  1701. XrmQuark empty = NULLQUARK;
  1702. char lhs[MAXLHSSIZE];
  1703. if ( NULL == db
  1704. || db->initGuard != INIT_OCCURRED
  1705. || NULL == operation
  1706. || operation[0] == EOS)
  1707. return -1; /* RETURN error */
  1708. /* prep srch data for search */
  1709. DoCommonSrchDataPrep(&srchData,db,platform,version,operation);
  1710. /* after check on value, store op value for use during comparison */
  1711. /* not meaningful to check for a NULL value */
  1712. if (NULL == opValue)
  1713. {
  1714. if (db->debugMode) fprintf(stderr,"_DtXlateOpToStdValue: NULL op value\n");
  1715. if (ret_stdValue) *ret_stdValue = NULL;
  1716. return -1; /* RETURN error */
  1717. }
  1718. srchData.opValue = opValue;
  1719. if (db->debugMode)
  1720. fprintf(stderr,"_DtXlateOpToStdValue: %s.%d.%s.<std>: %s\n",
  1721. platform,version,operation,opValue);
  1722. /* scan through this Db looking for matches and put in search */
  1723. XrmEnumerateDatabase(db->xrmDb,&empty,&empty,
  1724. XrmEnumAllLevels, FindOpToStdMatchCB, (XPointer) &srchData);
  1725. if ( srchData.stdValueQuarks[0] != NULLQUARK
  1726. && srchData.bestTransType != __DtXLATE_TYPE_INHIBIT )
  1727. {
  1728. XrmQuarkList stdQ;
  1729. char * stdValue = lhs;
  1730. int stdValueLen = 0;
  1731. if (ret_stdValue == NULL)
  1732. {
  1733. if (db->debugMode) fprintf(stderr,"translation exists\n");
  1734. return 0; /* RETURN: translation exists */
  1735. }
  1736. /* make a STDVALUE_SEPARATOR separated string out of the std data */
  1737. for ( stdQ = srchData.stdValueQuarks;
  1738. *stdQ != NULLQUARK;
  1739. stdQ++ )
  1740. {
  1741. const char * str = XrmQuarkToString(*stdQ);
  1742. int strLen;
  1743. if (NULL == str || str[0] == EOS) continue;
  1744. strLen = strlen(str);
  1745. if (stdValue != lhs)
  1746. {*stdValue++ = STDVALUE_SEPARATOR; stdValueLen++; }
  1747. if ((stdValueLen + strLen) > sizeof(lhs) )
  1748. strLen = sizeof(lhs)-stdValueLen;
  1749. strncpy(stdValue,str,strLen);
  1750. stdValueLen += strLen;
  1751. stdValue += strLen;
  1752. }
  1753. *stdValue = EOS;
  1754. if (db->debugMode) fprintf(stderr,"raw stdval:%s\n",lhs);
  1755. /* do quote and escape removal and ref replacement in the stdValue */
  1756. stdValue = strdup(lhs); /* reset stdValue ptr */
  1757. if ( srchData.bestTransType == __DtXLATE_TYPE_REGEX )
  1758. ReplaceMatchallSubex(&stdValue,srchData.bestSubEx,srchData.opValue);
  1759. if (db->debugMode) fprintf(stderr,"std value:%s\n",stdValue);
  1760. *ret_stdValue = stdValue;
  1761. return 0; /* RETURN: search successful */
  1762. }
  1763. return -1; /* RETURN: search failed */
  1764. } /*$END$*/
  1765. #if DOC
  1766. /*========================================================*/
  1767. $FUNBEG$: _DtXlateGetXlateEnv()
  1768. $1LINER$: Get the DtXlate compilation and execution environments.
  1769. $SUMMARY$:
  1770. _DtXlateGetXlateEnv() recovers the identity of the application
  1771. current platform, the version value of the application
  1772. execution environment, and the version value of the operating
  1773. system version for which DtXlateGetXlateEnv() was
  1774. compiled. These values can be used in formulating queries,
  1775. especially for the _DtXlateStdToOpValue() query.
  1776. The technique used by this routine is as follows. Using
  1777. uname(2), the routine retrieves the sysname, release, and version
  1778. strings. The sysname is used as the platform name. The
  1779. release and version strings are concatenated in that order
  1780. and as treated below as the <op-rel-ver>. An OpToStd translation
  1781. looks for a match to
  1782. <sysname>.?.version.<.<std-version>: <op-rel-ver>
  1783. or
  1784. <sysname>.?.version.=.<std-version>: <op-rel-ver>
  1785. If no match is found, the next fallback position is to
  1786. get the specification with the same sysname and the highest
  1787. std-version integer value. If no specifications exist for
  1788. that sysname, then sysname is set to the empty string and
  1789. std-version is -1.
  1790. ret_AppExecEnvPlatform should point to a character array at least
  1791. _DtPLATFORM_MAX_LEN characters long. The sysname is copied to it.
  1792. ret_AppExecEnvVersion is given the integer value of the
  1793. std-version recovered from the translation.
  1794. ret_XlateCompiledForOSVersion is given the integer value
  1795. determined by using the OSMajorVersion and OSMinorVersion
  1796. constants defined by the build environment of _DtXlate as follows:
  1797. #define _STR(V) #V
  1798. #define STR(V) _STR(V)
  1799. sprintf(buf,"%s%s%s", STR(OSMAJORVERSION),
  1800. nl_langinfo(RADIXCHAR), STR(OSMAJORVERSION));
  1801. verNum = (int) (100.0 * atof(buf));
  1802. For example:
  1803. OSMAJORVERSION & OSMINORVERSION are compile-time constants
  1804. that must be defined as part of the build environment.
  1805. It is assumed that these constants are of the form:
  1806. e.g. Sun 5.3
  1807. #define OSMAJORVERSION 5
  1808. #define OSMINORVERSION 3
  1809. 530 = (int) 100.0 * atof("5.3");
  1810. e.g. HP-UX 8.09
  1811. #define OSMAJORVERSION 8
  1812. #define OSMINORVERSION 09
  1813. 809 = (int) 100.0 * atof("8.09");
  1814. Note that it may be necessary for the application to determine
  1815. the version number of an operation in some platform-specific
  1816. and operation-specific manner, for example using a library
  1817. version value. In many cases, however, the O.S. version value
  1818. for which _DtXlate was compiled will be sufficient
  1819. when identifying version numbers for standard development
  1820. environment libraries, such as libc.
  1821. $EXAMPLE$:
  1822. char *
  1823. xlateStd2Op(_DtXlateDb db,Boolean runtimeOp, char * operation,char * stdVal)
  1824. {
  1825. char platform[_DtPLATFORM_MAX_LEN];
  1826. int version;
  1827. char * opVal = NULL;
  1828. int ret;
  1829. if (runtimeOp)
  1830. ret=_DtXlateGetXlateEnv(db,platform,&version,NULL);
  1831. else
  1832. ret=_DtXlateGetXlateEnv(db,platform,NULL,&version);
  1833. if (ret == 0)
  1834. _DtXlateStdToOpValue(db,platform,version,operation,stdVal,&opVal,NULL);
  1835. return opVal; /* will be NULL if error occurred */
  1836. }
  1837. $ARGS$:
  1838. ret_AppExecEnvPlatform: pts to a string at least _DtPLATFORM_MAX_LEN long
  1839. that will hold the string uname(2) returns for sysname
  1840. ret_AppExecEnvVersion: pts to an integer that will receive the platform
  1841. standardized version number, as determined by
  1842. a translation on uname(2) release+version.
  1843. ret_XlateCompiledForOSVersion: pts to an integer that will receive the
  1844. operating system version for which _DtXlate was
  1845. compiled using OSMajorVersion * 100 + OSMinorVersion
  1846. Any of the arguments may be NULL.
  1847. $RETURNS$:
  1848. 0: if no error occurred
  1849. -1: if no translation was possible to get the AppExecEnvVersion
  1850. /*================================================$SKIP$==*/
  1851. #endif
  1852. int _DtXlateGetXlateEnv(
  1853. _DtXlateDb db,
  1854. char * ret_AppExecEnvPlatform,
  1855. int * ret_AppExecEnvVersion,
  1856. int * ret_XlateCompiledForOSVersion)
  1857. { /*$CODE$*/
  1858. struct utsname names;
  1859. int ret = 0;
  1860. char * platform = "NULL";
  1861. int execver = -1;
  1862. int compver = -1;
  1863. /* get host specifics */
  1864. uname(&names);
  1865. /* first get execution host name */
  1866. if (ret_AppExecEnvPlatform)
  1867. {
  1868. strncpy(ret_AppExecEnvPlatform,names.sysname,_DtPLATFORM_MAX_LEN-1);
  1869. ret_AppExecEnvPlatform[_DtPLATFORM_MAX_LEN-1] = EOS;
  1870. platform=ret_AppExecEnvPlatform;
  1871. }
  1872. /* then look up version number of execution host */
  1873. if (ret_AppExecEnvVersion)
  1874. {
  1875. char version[sizeof(names.release)+sizeof(names.version)-1];
  1876. char * stdVer = NULL;
  1877. int verNum = MATCHALL_VER;
  1878. /* cat release version and do a translation on it to a std value */
  1879. /* then convert the std value to a integer */
  1880. strncpy(version,names.release,sizeof(names.release)-1);
  1881. version[sizeof(names.release)-1] = EOS;
  1882. strncat(version,names.version,sizeof(names.version)-1);
  1883. ret = _DtXlateOpToStdValue(db,names.sysname,0,
  1884. _DtXLATE_OPER_VERSION,version,&stdVer,NULL);
  1885. if (ret == 0)
  1886. {
  1887. if (sscanf(stdVer,"%d",&verNum) != 1) verNum = MATCHALL_VER;;
  1888. free(stdVer);
  1889. }
  1890. *ret_AppExecEnvVersion = verNum;
  1891. execver = verNum;
  1892. }
  1893. /* then look up version number of execution host */
  1894. if (ret_XlateCompiledForOSVersion)
  1895. {
  1896. char buf[MAXINTSTRSIZE];
  1897. #define _STR(V) #V
  1898. #define STR(V) _STR(V)
  1899. /*===========================
  1900. OSMAJORVERSION & OSMINORVERSION are compile-time constants
  1901. that must be defined as part of the build environment.
  1902. It is assumed that these constants are of the form:
  1903. e.g. Sun 5.3
  1904. #define OSMAJORVERSION 5
  1905. #define OSMINORVERSION 3
  1906. 530 = (int) (100.0 * atof("5.3"));
  1907. e.g. HP-UX 8.09
  1908. #define OSMAJORVERSION 8
  1909. #define OSMINORVERSION 09
  1910. 809 = (int) (100.0 * atof("8.09"));
  1911. ===========================*/
  1912. #if !defined(OSMAJORVERSION) && !defined(OSMINORVERSION)
  1913. #warning "OSMAJORVERSION and OSMINORVERSION not defined, assuming 99.0:
  1914. #define OSMAJORVERSION 99
  1915. #define OSMINORVERSION 0
  1916. #endif
  1917. #if defined(__linux__) || defined(CSRG_BASED)
  1918. sprintf(buf,"%s%s%s", STR(OSMAJORVERSION),
  1919. nl_langinfo('.'), STR(OSMINORVERSION));
  1920. #else
  1921. sprintf(buf,"%s%s%s", STR(OSMAJORVERSION),
  1922. nl_langinfo(RADIXCHAR), STR(OSMINORVERSION));
  1923. #endif
  1924. *ret_XlateCompiledForOSVersion = (int) (100.0 * atof(buf));
  1925. compver = *ret_XlateCompiledForOSVersion;
  1926. }
  1927. if (db->debugMode)
  1928. fprintf(stderr,"_DtXlateGetXlateEnv: "
  1929. "Platform: %s; Execution Ver: %d; Compiled Ver: %d\n",
  1930. platform,execver,compver);
  1931. return ret;
  1932. } /*$END$*/
  1933. /*========================================================*/
  1934. /*================ Introductory Info =====================*/
  1935. /*========================================================*/
  1936. #if DOC
  1937. /*========================================================*/
  1938. $INTROBEG$: _DtXlate family
  1939. $1LINER$: API to translate any value to a standard value and back again
  1940. $SUMMARY$:
  1941. _DtXlate is a collection of routines that allow translation
  1942. between platform, version, and operation specific values
  1943. into standard values and back again. Translation is
  1944. based on the contents of database files specified using
  1945. Xrm-style resources. The semantics of the translation
  1946. are a combination of standard semantics for specifying
  1947. platform, version, operation, and translation type, and
  1948. caller-specific semantics for the standard value format
  1949. and operation values.
  1950. The API contains routines to process translation databases
  1951. in a useful manner.
  1952. _DtXlateOpenDb() opens a particular translation database
  1953. _DtXlateOpenAndMergeDb() opens a particular database and
  1954. merges it with an already opened one, overriding any
  1955. repeated specifications.
  1956. _DtXlateOpenAllDbs() opens all occurrences of a translation
  1957. database found in a search path and cumulatively merges
  1958. the contents, allowing for the override of existing
  1959. specifications as well as the addition of new ones.
  1960. _DtXlateCloseDb() closes an open database
  1961. _DtXlateOpToStdValue() translates an platform, version,
  1962. and operation specific value into a standard value.
  1963. _DtXlateStdToOpValue() translates a standard value into
  1964. a platform, version, and operation specific value.
  1965. /*=$END$================================================*/
  1966. #endif
  1967. #if DOC
  1968. /*========================================================*/
  1969. $INTROBEG$: Design and Implementation Considerations
  1970. $1LINER$: Factors influencing design and implementation
  1971. $SUMMARY$:
  1972. The syntax of the translation specification table is designed
  1973. to be compatible with Xrm resource specifications. This
  1974. allows Xrm to be used to load, parse, and merge the databases
  1975. for processing. This also causes the specifications to be
  1976. case-sensitive, as case is preserved by Xrm and is used when
  1977. processing queries.
  1978. However, due to the semantics of translation specifications
  1979. and limitations of Xrm, XrmGetResource() queries generally
  1980. will not be useful. Rather, a pattern matching API is provided
  1981. that implements the query capability used for the translations.
  1982. The initial implementation will use XrmEnumerateDatabase().
  1983. Using Xrm leads to an in-memory approach to translation, meaning
  1984. that all the resources files are parsed and loaded into memory
  1985. as the first step of a translation. A line-at-a-time approach,
  1986. that process one line at a time directly from the file in a
  1987. grep- or awk-like manner, is likely more memory-efficient.
  1988. Note that the line-at-a-time approach does not avoid parsing
  1989. all the specification files, as the API supports inheritence
  1990. and override of specifications. Hence, to ensure the correct
  1991. value, the entire file set must be processed. Note also that
  1992. in a situation where translations will be repeatedly performed,
  1993. the Xrm in-memory approach may be more time-efficient, as the
  1994. files need only be parsed once, and then are utilized repeatedly.
  1995. Because of time constraints, a line-at-a-time approach will not
  1996. be used for the first implementation, as Xrm provides all the
  1997. necessary parsing, filtering, and symbol hashing routines
  1998. for free. Given the likely large size of the tables and their
  1999. infrequent use, a line-at-a-time approach is likely the better
  2000. choice.
  2001. /*=$END$================================================*/
  2002. #endif
  2003. #if DOC
  2004. /*========================================================*/
  2005. $INTROBEG$: translation BNF syntax and semantics
  2006. $1LINER$: _DtXlate translation specification syntax and semantics
  2007. $SUMMARY$:
  2008. BNF Syntax of Translation Specification
  2009. =======================================
  2010. <specfile> ::= (<xlatespec> | <comment> | <cr>)*
  2011. <xlatespec> ::= <platform>.<version>.<operations>.<transtype>
  2012. .<stdvalue>:<opvalue> (<comment>|<cr>)
  2013. <platform> ::= <identifier> | <matchall>
  2014. <version> ::= <number> [+ | (- <number>)] | <matchall>
  2015. <operations> ::= <identifier> [',' <identifier>]* | <matchall>
  2016. <transtype> ::= '<' | '=' | '~' | '>' | '0'
  2017. <stdvalue> ::= <identifier> [.<identifier>]*
  2018. <langterr> ::= <identifier> | <matchall>
  2019. <codeset> ::= <identifier> | <matchall>
  2020. <modifier> ::= <identifier> | <matchall>
  2021. <opvalue> ::= (<vischars>|<metachar>)+ | '"'(<anychar>|<metachar>)+'"'
  2022. <matchall> ::= '?'[<number>]
  2023. <cr> ::= '\n'
  2024. <comment> ::= '!' [^<cr>]* <cr>
  2025. <number> ::= [0-9]+
  2026. <identifier> ::= [-_a-ZA-Z0-9]
  2027. <vischar> ::= any non-whitespace character; meta and regular
  2028. expression chars must be escaped with "\\"
  2029. <anychar> ::= any printable character; meta and regular
  2030. expression chars must be escaped with "\\"
  2031. <metachar> ::= '!' | '"' | <backslash> | <valex> | <regex>
  2032. <valex> ::= <backslash><number>
  2033. <regex> ::= see regexp(5)
  2034. <backslash> ::= the backslash character (\).
  2035. Semantics of the Translation Specification
  2036. ==========================================
  2037. <specfile> : a file containing zero or more translation specifications
  2038. or comments
  2039. <xlatespec> : a translation specification defines a fully qualified
  2040. string value which may be recovered by query pattern matching the
  2041. specification. The qualifiers identify the semantics of the usage
  2042. of the value, allowing queries to be meaningful. The entire xlatespec
  2043. must be on one line of the file.
  2044. <platform> : a CDE-standardized identifier for an operating system
  2045. platform. The platform need not be supported by CDE, but CDE must
  2046. have standardized an identifier for the platform in order for it to
  2047. be used. For example, candidate platform identifiers are "HP-UX",
  2048. "AIX", "SunOS", "Solaris", "SCO", etc. These identifiers are the
  2049. values returned by uname(2):utsname.sysname and uname(1) -s, and
  2050. I propose CDE standardize on using these values.
  2051. The identifier string and matching constant value must be added to
  2052. the source code of the translation routine in order for it to be
  2053. recognized. This allows control over the platform registry
  2054. and enables automatic generation of the platform on the execution
  2055. host through the use of #ifdef <PLATFORM_CONST> in the source code.
  2056. <version> : a platform-specific numeric value or range of numberic
  2057. values that allows the value to be qualified to a particular version
  2058. and release (version + release = version) or range of versions and
  2059. releases of the platform. The version numbers must be integral and
  2060. suitable for numeric comparison. The '+' can be used to specify an
  2061. open upwards bound, as in 900+. The '- <number>' can be used to
  2062. specify an upper bound, as in 900-999. If no range is specified,
  2063. the version number must match exactly to the query pattern and/or
  2064. execution environment.
  2065. Platforms may not directly provide version numbers in a numeric
  2066. format suitable for use when comparing with a translation
  2067. specification. As part of the translation API source code,
  2068. conversion routines must be supplied that translate the platform-
  2069. specific values, such as those provided by uname(2), into a
  2070. translation specification-compliant format suitable for comparison
  2071. to <version>. Understanding the conversion routines operation
  2072. will be necessary to ensure correct translation specifications.
  2073. <operations> : a CDE-standardized identifier for the operation(s) to
  2074. which the value applies. The operation(s) need not be supported by every
  2075. platform, but CDE must have standardized an identifier for the operation
  2076. in order for it to be used. More than one identifier may be included by
  2077. concatenating them using the ',' separator, eg. "iconv1,iconv3".
  2078. <transtype> : The <transtype> field records the direction of
  2079. translation that the specification supports: '<', '=', '~', '>', '0'.
  2080. Use '<' if the <opvalue> contains a regular expression; the
  2081. specification may only be used to match an operation value in
  2082. a _DtLcxXlateOpToStd() translation. Use '>' if the <opvalue>
  2083. contains value replacement expressions using values from
  2084. the <stdvalue> strings; the specification may only be used by a
  2085. _DtLcxXlateStdToOp() translation. Use '=' if the <opvalue>
  2086. is a pure string that may be used for either OpToStd() or
  2087. StdToOp() translations, and the specification op-value must exactly
  2088. match the op-value of the translation request. use '~' if the
  2089. <opvalue> is a pure string that may be used for either OpToStd() or
  2090. StdToOp() translations, and the specifation op-value must be
  2091. a string within the op-value of the translation request.
  2092. Use the '0' translation to represent that this particular
  2093. translation should result in an error, that is should not result
  2094. in a translation.
  2095. Translations are two-way operations: from a host- and
  2096. operation-specific value to standardized value, and back again.
  2097. In many cases, a straight string value for string value translation
  2098. is sufficient.
  2099. But often, more sophisticated pattern matching and value generation
  2100. mechanisms are useful to keep the table size small and as general
  2101. as possible. In these cases, wildcard and regular expression
  2102. operators are useful. Unfortunately, these specifications are not
  2103. bi-direction. That is, the pattern matching string can be used
  2104. to match against a pattern, but not to generate a result string.
  2105. For example, the vi expression s/he*lo/hello/ matches "hello"
  2106. as well as "hey look out below", but the reverse direction of
  2107. "hello"->"he*lo" will not work.
  2108. <stdvalue> : a sequence of one or more '.'-separated CDE-standardizd
  2109. identifiers or matchall characters. This represents the canonical
  2110. string used as a standard representation of a semantic value that
  2111. may vary in different situations.
  2112. <opvalue> : a string that has different uses depending on the
  2113. value of <transtype>. If transtype is '<', the string is used
  2114. as a regular expression to match the opValue in _DtLcxXlateOpToStd()
  2115. requests. If the transtype is '>', the string is used as a
  2116. replacement expression to generate a opValue in _DtLcxXlateStdToOp().
  2117. If transtype is '=' or '~', the string is used as a straight string to
  2118. both match for the OpToStd translation and as a value for
  2119. the StdToOp translation.
  2120. %
  2121. If the opvalue contains whitespace, the opvalue must be enclosed in
  2122. double quote characters. If the opvalue contains any meta characters
  2123. that should not be treated as meta characters, they must be escaped by
  2124. two preceding backslashs.Lack of an opvalue is not an error, but will
  2125. be ignored during matches and return an empty string in a StdToOp
  2126. translation; to specify that a given translation does not exist, the
  2127. '0' translation type should be used or the specification should not
  2128. occur.
  2129. <comment> : a comment begins on an empty line with an unescaped !
  2130. and continues to the end of the line.
  2131. <matchall> : The matchall character is a universal quantifier, meaning
  2132. that it symbolizes all possible values of the field where it is used.
  2133. The matchall character may occur only in the qualifers side of
  2134. a translation specification. Traditionally, the matchall character
  2135. has been '*', but because of the semantics of Xrm, if the '*' is used
  2136. as the matchall, Xrm does not restrict enumeration as needed.
  2137. The matchall character may be followed by a number when the <transtype>
  2138. is '>'. When this occurs, the string that matches the matchall
  2139. character may be referenced in the <opvalue> by using the sequence
  2140. \<number>, as in "\1". The occurrence is replaced with the matched
  2141. string.
  2142. /*=$END$================================================*/
  2143. #endif
  2144. #if DOC
  2145. /*========================================================*/
  2146. $INTROBEG$: translation specification examples
  2147. $1LINER$: examples of _DtXlate translation specifications
  2148. $EXAMPLE$:
  2149. !! These are examples of bi-directional straight translations
  2150. HP-UX.900-999.setlocale.=.en_US.hp-roman8: american
  2151. HP-UX.900-999.setlocale.=.en_US.iso88591: american.iso88591
  2152. HP-UX.900-999.setlocale.=.nl_BE.hp-roman8.fold: dutch@fold
  2153. HP-UX.900-999.setlocale.=.nl_BE.hp-roman8.nofold: dutch@nofold
  2154. !! These are examples of OpToStd translations utilizing regular
  2155. !! expression patterns to match the search value.
  2156. HP-UX.?.version.<.900: "A\\.09\\..*" !! any HPUX 9.x version
  2157. HP-UX.?.version.<.807: "A\\.08\\.07.*"
  2158. HP-UX.?.version.<.800: "A\\.08\\..*"
  2159. AIX.?.version.<.320: "2 3"
  2160. AIX.?.version.<.300: "[0-9] 3"
  2161. SunOS.?.version.<.530: "5\\.3.*"
  2162. SunOS.?.version.<.500: "5\\..*"
  2163. !! These are examples of StdToOp translations utilizing matchall
  2164. !! specifiers in the std value to match the search value.
  2165. HP-UX.900+.iconv1.>.?.iso88596: arabic8
  2166. HP-UX.900+.iconv1.>.?.iso88597: greek8
  2167. HP-UX.900+.iconv1.>.?.hp-kana8: kana8
  2168. HP-UX.900+.iconv1.>.?.hp-roman8: roman8
  2169. !! The following examples use value replacement as part of their
  2170. !! specifications. Using this can lead to much sparser tables, but
  2171. !! it depends on op-specific and std values sharing the same strings.
  2172. HP-UX.900-999.setlocale.<.nl_BE.hp-roman8.?1: [dD][uU][tT][cC][hH]@\\(.*\\)
  2173. !HP-UX.900-999.setlocale.<.nl_BE.hp-roman8.?1: dutch@\\(.*\\)
  2174. HP-UX.1000+.setlocale.>.?1.hp-roman8: \\1.roman8 !! all non-modif cases
  2175. HP-UX.1000+.setlocale.>.?1.hp-roman8.?2: \\1.roman8@\\2 !! all modif cases
  2176. /*=$END$================================================*/
  2177. #endif
  2178. #if DOC
  2179. /*========================================================*/
  2180. $INTROBEG$: _DtXlate example usage
  2181. $1LINER$: Examples of how to _DtXlate
  2182. $EXAMPLE$:
  2183. #include <XlationSvc.h>
  2184. main()
  2185. {
  2186. _DtXlateDb db = NULL;
  2187. int ret;
  2188. char plat[_DtPLATFORM_MAX_LEN];
  2189. int execver;
  2190. int compver;
  2191. char * val = NULL;
  2192. char * str = NULL;
  2193. char empty = 0;
  2194. #define OPER_YOUROP "myop"
  2195. env = getenv("MYPATH");
  2196. if (env == NULL) env = &empty;
  2197. ret = _DtXlateOpenAllDbs(env,"myfile.xlt",&db);
  2198. ret = _DtXlateGetXlateEnv(db,plat,&execver,&compver);
  2199. printf("Platform: %s\nExec Ver: %d\nComp Ver: %d\n",
  2200. plat,execver,compver);
  2201. ret = _DtXlateStdToOpValue(db,plat,compver,OPER_YOUROP,
  2202. str="en_US.hp-roman8",&val,NULL);
  2203. if (ret==0) printf("setlocale(%s) xlation=%s\n", str, val);
  2204. else printf("no xlation\n", val);
  2205. ret = _DtXlateOpToStdValue(db,plat,execver,OPER_YOUROP,
  2206. str="american",&val,NULL);
  2207. if (ret==0) printf("setlocale(%s) xlation=%s\n", str, val);
  2208. else printf("no xlation\n", val);
  2209. ret = _DtXlateCloseDb(&db);
  2210. }
  2211. /*=$END$================================================*/
  2212. #endif