12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- /* $TOG: XlationSvc.c /main/13 1999/10/14 15:59:35 mgreess $ */
- /****************************************************************************
- $FILEBEG$: XlationSvc.c
- $PROJECT$: Cde 1.0
- $COMPONENT$: DtXlate service
- $1LINER$: Implements a translation service using tables and regex search
- $COPYRIGHT$:
- (c) Copyright 1993, 1994 Hewlett-Packard Company
- (c) Copyright 1993, 1994 International Business Machines Corp.
- (c) Copyright 1993, 1994 Sun Microsystems, Inc.
- (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc.
- $END$
- ****************************************************************************
- ************************************<+>*************************************/
- #include <ctype.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #if defined(sun)
- #include <sys/utsname.h>
- #endif
- #include <limits.h> /* INT_MAX */
- #include <pwd.h> /* for getpw... */
- #include <sys/utsname.h> /* for uname */
- #include <sys/param.h> /* MAXPATHLEN */
- /* for RADIXCHAR and nl_langinfo */
- #if defined(__linux__)
- # define RADIXCHAR MON_DECIMAL_POINT
- #endif
- #include <langinfo.h>
- #if defined(sun)
- #include <regexpr.h> /* for compile,advance */
- #else
- #include <regex.h> /* for regcomp,regexec */
- #endif
- /* for Xrm */
- #include <X11/Intrinsic.h>
- #include <X11/Xresource.h>
- /*=================================================================
- $SHAREDBEG$: This header appears in all appropriate DtXlate topics
- =======================================================$SKIP$======*/
- /*$INCLUDE$*/
- #include "XlationSvc.h"
- #include "LocaleXlate.h"
- /*$END$*/
- /**** For extensive Introductory info, go to the end of this file ****/
- /*========================================================*/
- /*====================== Constants =======================*/
- /*========================================================*/
- /*=============== private =================*/
- /*#define DBG_MATCHING ** if defined, debugging matching stages are compiled */
- #define DEBUG_XLATE_NAME "dtXlate.debugDtXlate"
- #define DEBUG_XLATE_CLASS "DtXlate.DebugDtXlate"
- #define EOS '\0'
- /* A "random" number used to ensure that the Db has been initalized */
- #define INIT_OCCURRED 2329479
- #define PATH_SEPARATOR ':'
- #define DIR_SLASH '/'
- #define LESSTHAN_STR "<"
- #define EQUALS_STR "="
- #define CONTAINS_STR "~"
- #define MORETHAN_STR ">"
- #define INHIBIT_STR "0"
- #define MATCHALL_CHAR '?'
- #define ESCAPE_CHAR '\\'
- #define COMMENT_CHAR '!'
- #define QUOTE_CHAR '\"'
- #define OPER_SEPARATOR ','
- #define STDVALUE_SEPARATOR '.'
- #define MATCHALL_VER 0
- #define PLATFORM_QUARK 0 /* index offsets into quarklist */
- #define VERSION_QUARK 1
- #define OPERS_QUARK 2
- #define DIRECTION_QUARK 3
- #define FIRSTSTD_QUARK 4
- #define MAXSPECQUARKS 43 /* std + platform + version + operation */
- #define MAXSTDQUARKS 40
- #define MAXRHSSIZE 100 /* max supported RHS size */
- #define MAXLHSSIZE 200 /* max supported LHS size */
- #define MAXINTSTRSIZE 15 /* handle any long int -> string */
- typedef enum {
- __DtXLATE_TYPE_NONE = 0,
- __DtXLATE_TYPE_INHIBIT = 1,
- __DtXLATE_TYPE_REGEX = 2,
- __DtXLATE_TYPE_PURE = 3,
- __DtXLATE_TYPE_CONTAINS = 4
- } __DtXlateType;
- #if defined(sun)
- /* Sun doesn't support regcomp() and regexec() yet, so
- define this here and fill it will the results of advance() */
- typedef struct regmatch_t {
- int rm_so; /* start offset */
- int rm_eo; /* end offset */
- } regmatch_t;
- #endif
- /*========================================================*/
- /*====================== Typedefs ========================*/
- /*========================================================*/
- #if DOC
- /*========================================================*/
- $PTYPEBEG$: __DtXlateDbRec
- $1LINER$: A private object used to represent translation dbs
- $SUMMARY$:
- __DtXlateDbRec is the type of the contents of a translation database
- object. The database object must be opened before use and closed
- after use. The definition of the object is opaque to users.
- $ARGS$:
- xrmDb: Xrm database used to hold specs
- initGuard: used to test whether Db initialized
- /*================================================$SKIP$==*/
- #endif
- /*$DEF$*/
- typedef struct __DtXlateDbRec
- {
- XrmDatabase xrmDb;
- int initGuard;
- Boolean debugMode;
- } __DtXlateDbRec;
- /*$END$*/
- #if DOC
- /*========================================================*/
- $PTYPEBEG$: __DtXlateSrchData
- $1LINER$: A private object used to collect search-related data
- $SUMMARY$:
- __DtXlateSrchData stores all the data pertaining to a search
- and the search results. The search routines utilize this
- to maintain status info over multiple calls by the
- enumeration routines and to return info to the routine
- that initiated the search.
- $ARGS$:
- filterQuarks: quark list for the platform, version, and op filter
- stdValueQuarks: quark list for the std value
- opValue: ptr to operation-specific value string
- SpecRef: indices 1 to MAXSPECQUARKS point to matching Xrm strings
- SubEx: indices 1 to MAXSPECQUARKS index sub exprs in opValue
- /*================================================$SKIP$==*/
- #endif
- /*$DEF$*/
- typedef struct __DtXlateSrchData
- {
- /* db info */
- _DtXlateDb db;
- /* query info */
- const char * platformStr;
- XrmQuark platformQuark;
- int version;
- char verStr[MAXINTSTRSIZE]; /* handle any long int */
- const char * operStr;
- int operStrLen;
- XrmQuark operQuark;
- XrmQuark lessThanQuark;
- XrmQuark equalsToQuark;
- XrmQuark containsQuark;
- XrmQuark moreThanQuark;
- XrmQuark inhibitQuark;
- /* query or search info */
- XrmQuark stdValueQuarks[MAXSTDQUARKS];
- const char * opValue;
- /* search info */
- __DtXlateType curTransType;
- __DtXlateType bestTransType;
- int curScore;
- int bestScore;
- /* MAXSPECQUARKS is depended upon elsewhere to be the size of these */
- const char * curSpecRefs[MAXSPECQUARKS];
- const char * bestSpecRefs[MAXSPECQUARKS];
- regmatch_t curSubEx[MAXSPECQUARKS]; /* pattern match data */
- regmatch_t bestSubEx[MAXSPECQUARKS]; /* pattern match data */
- } __DtXlateSrchData;
- /*$END$*/
- /*========================================================*/
- /*================== Private routines ====================*/
- /*========================================================*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: ExpandPath()
- $1LINER$: adds current working directory to front of path if its relative
- $SUMMARY$:
- If path is absolute, returns a malloced copy.
- If path is relative, inserts the CWD in front of the relative path
- and returns a mallocedd memory.
- The caller must free the memory when no longer needed.
- $ARGS$:
- filespec: the pathname
- $RETURNS$:
- ptr to mallocedd memory or NULL
- /*================================================$SKIP$==*/
- #endif
- char * ExpandPath (
- const char * filespec)
- { /* $CODE$ */
- char tmpPath[MAXPATHLEN + 2];
- char * pathName;
- char * eos = NULL;
- const char * slash = NULL;
- /* test args */
- if (NULL == filespec) return NULL;
- /*** is the file absolute ***/
- /* if filespec begins with / then it is absolute */
- if ( ( MB_CUR_MAX == 1
- || mblen(filespec, MB_CUR_MAX) == 1)/* 1st char is 1 byte */
- && *filespec == DIR_SLASH) /* and its a / */
- {
- return strdup(filespec); /* RETURN */
- }
- /*** otherwise, make it relative to the current directory ***/
- /* get user's current working directory */
- if (getcwd(tmpPath, MAXPATHLEN) == 0) return NULL; /* RETURN: error */
- /*** add a slash to end of path component, if needed ***/
- /* get end of the string */
- eos = tmpPath + strlen(tmpPath);
- /* get last slash */
- _DtMBStrrchr(tmpPath,DIR_SLASH,-1,&slash);
- if (slash != (eos-1)) /* is slash last char of path? */
- {
- *eos++ = DIR_SLASH;
- *eos = EOS;
- }
- /* make a malloc'd copy of the path with room to grow */
- pathName = malloc(sizeof(char) *
- (strlen(filespec) + (eos-tmpPath) + 5) ); /* 5: arbitrary */
- if (NULL == pathName) return NULL; /* RETURN: error */
- /* build the absolute path */
- strcpy(pathName,tmpPath);
- strcat(pathName,filespec);
- return pathName; /* RETURN: found */
- } /* $END$ */
- #if DOC
- /*========================================================*/
- $PFUNBEG$: DeleteDbMem()
- $1LINER$: Zeros out the db mem & frees it
- $SUMMARY$:
- Zeros out the db mem & frees it
- The xrmDb should have already been destroyed before calling
- this function.
- $ARGS$:
- io_db: db to delete
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- void DeleteDbMem(
- _DtXlateDb * io_db)
- { /*$CODE$*/
- /* zero out object mem and free it */
- (*io_db)->xrmDb = NULL;
- (*io_db)->initGuard = 0;
- free(*io_db);
- *io_db= NULL;
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $IFUNBEG$: _DtMBStrchr()
- $1LINER$: Searches for a character in a multibyte string
- $SUMMARY$:
- Returns in 'ret_ptr' the address of the first occurence of 'value'
- in string s1. Value may also be the end of string marker '\0'.
- $ARGS$:
- $RETURNS$:
- -1 If found an invalid character.
- 0 If found value in string s2
- 1 If found the null byte character without finding 'value'.
- 'ret_ptr' will also be null in this case.
- /*================================================$SKIP$==*/
- #endif
- int _DtMBStrchr (
- const char * s1,
- int value,
- int max_len,
- const char * * ret_ptr )
- { /*$CODE$*/
- int len;
- const char * p1;
- wchar_t wcs;
- *ret_ptr = NULL;
- if (!s1 || *s1 == '\0')
- return 1;
- if (max_len == 1)
- {
- *ret_ptr = strchr (s1, value);
- if (*ret_ptr)
- return 0;
- return 1;
- }
- p1 = s1;
- while (*p1 != '\0')
- {
- len = mblen (p1, max_len);
- if (len == -1)
- return -1;
- if (len == 1)
- {
- if (*p1 == value)
- {
- *ret_ptr = p1;
- return 0;
- }
- p1++;
- }
- else
- {
- if (mbstowcs (&wcs, p1, 1) == value)
- {
- *ret_ptr = p1;
- return 0;
- }
- p1 += len;
- }
- }
- /* check for match on EOS */
- if (*p1 == value) *ret_ptr = p1;
- return ((*ret_ptr) ? 0 : 1);
- } /*$CODE$*/
- #if DOC
- /*========================================================*/
- $IFUNBEG$: _DtMBStrrchr()
- $1LINER$: Searches for a character in a multibyte string
- $SUMMARY$:
- Returns in 'ret_ptr' the address of the last occurence of 'value'
- in string s1. Value may also be the end of string marker '\0'.
- $ARGS$:
- $RETURNS$:
- -1 If found an invalid character.
- 0 If found value in string s2
- 1 If found the null byte character without finding 'value'.
- 'ret_ptr' will also be null in this case.
- /*================================================$SKIP$==*/
- #endif
- int _DtMBStrrchr (
- const char * s1,
- int value,
- int max_len,
- const char * * ret_ptr )
- { /*$CODE$*/
- int len;
- const char * p1;
- wchar_t wcs;
- *ret_ptr = NULL;
- if (!s1 || *s1 == '\0')
- return 1;
- if (max_len == 1)
- {
- *ret_ptr = strrchr (s1, value);
- if (*ret_ptr)
- return 0;
- return 1;
- }
- p1 = s1;
- while (*p1 != '\0')
- {
- len = mblen (p1, max_len);
- if (len == -1)
- return -1;
- if (len == 1)
- {
- if (*p1 == value) *ret_ptr = p1;
- p1++;
- }
- else
- {
- if (mbstowcs (&wcs, p1, 1) == value) *ret_ptr = p1;
- p1 += len;
- }
- }
- /* check for match on EOS */
- if (*p1 == value) *ret_ptr = p1;
- return ((*ret_ptr) ? 0 : 1);
- }
- #if DOC
- /*========================================================*/
- $PFUNBEG$: SetDebugModeState()
- $1LINER$: Checks db for debug mode and sets flag
- $SUMMARY$:
- $WARNING$:
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- void SetDebugModeState(
- _DtXlateDb dbRec)
- { /*$CODE$*/
- XrmValue value;
- char * str_type;
- if (XrmGetResource(dbRec->xrmDb,
- DEBUG_XLATE_NAME,DEBUG_XLATE_CLASS,&str_type,&value) == True)
- dbRec->debugMode = True;
- }
- #if DOC
- /*========================================================*/
- $PFUNBEG$: ReplaceMatchallSubex()
- $1LINER$: Replace matchall subexpression refs (e.g. ?1) with values
- $SUMMARY$:
- If subexpressions are specified and referenced, the
- routine assumes that the string pointed to by pStr was
- allocated using malloc() and can be resized using realloc().
- The value and size of pStr may be different after the call.
- $WARNING$:
- This routine assumes it is working on a stdvalue expression
- (e.g. from the LHS of a spec), that uses only stdvalue strings
- or matchall-style subexpression replacement specs, e.g. ?1.
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- void ReplaceMatchallSubex(
- char * * pStr,
- regmatch_t * subex,
- const char * matchedStr)
- { /*$CODE$*/
- char * nxt = *pStr;
- char * old = *pStr;
- /* strip escapes out */
- for ( *nxt = *old; /* xfer but don't advance */
- *old != EOS;
- *nxt = *old ) /* xfer but don't advance */
- {
- if ( *old == MATCHALL_CHAR ) /* if an escaped char follows */
- {
- /* if MATCHALL_CHAR is not followed by a digit, e.g. \1
- or no replacement values exist, ignore it */
- if ( NULL == subex
- || isdigit(*(old+1)) == 0 )
- {
- old++; /* go past the escape char */
- *nxt++ = *old++; /* keep just the char that was escaped
- and assign here to avoid tranlating
- that character, then move on to the
- next one */
- continue; /* CONTINUE */
- }
- else /* a value reference is being made */
- { /* get the refNum and advance the ptr */
- int refNum, numLen;
- int newOff, oldOff;
- sscanf(++old,"%d%n", &refNum, &numLen);
- old += numLen; /* move old ptr past the ref number */
- /* printf("%d=%s\n", refNum, &matchedStr[subex[refNum].rm_so]); ** DBG */
- /* test for valid replacement */
- if ( refNum >= 0
- && refNum < MAXSPECQUARKS
- && subex[refNum].rm_so != -1)
- {
- int repLen;
- int strLen;
- char * oldTmp;
- char * newTmp;
- newOff = nxt - *pStr;
- oldOff = old - *pStr;
- repLen = subex[refNum].rm_eo - subex[refNum].rm_so;
- strLen = strlen(*pStr);
- /* expand memory and reset pointers */
- *pStr = realloc(*pStr,strLen+repLen+1);
- if (NULL == *pStr) return; /* RETURN */
- nxt = *pStr + newOff;
- old = *pStr + oldOff;
- /* move rest back to leave room for the replacement value */
- oldTmp = *pStr+strLen; /* pts to old EOS */
- newTmp = *pStr+strLen-(oldOff-newOff)+repLen;/*pts to new EOS*/
- while (oldTmp >= old) *newTmp-- = *oldTmp--;
- /* replace the ref with a value but don't append EOS */
- strncpy(nxt,&matchedStr[subex[refNum].rm_so],repLen);
- nxt += repLen; /* move new to end of replace string */
- old += repLen - (oldOff-newOff);
- /* move old to end of expanded old string */
- } /* if valid replacement */
- } /* if a replacement requested */
- continue; /* CONTINUE */
- } /* if an escaped character */
- /* if survived all the checks, can advance to next char */
- nxt++;
- old++;
- }
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: StripMetaAndReplaceEscSubex()
- $1LINER$: Strips off meta chars and replaces escaped subex (e.g. \1) values
- $SUMMARY$:
- Strip is performed in place if replaceValues is NULL.
- If replaceValues are specified and referenced, the
- routine assumes that the string pointed to by pStr was
- allocated using malloc() and can be resized using realloc().
- The value and size of pStr may be different after the call.
- $WARNING$:
- This routine assumes it is working on a value expression
- (e.g. from the RHS of a spec), that uses meta chars and
- regex(5)-style subexpression replacement specs.
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- void StripMetaAndReplaceEscSubex(
- char * * pStr,
- const Boolean keepEscChar,
- const char * * replaceValues)
- { /*$CODE$*/
- char * nxt = *pStr;
- char * old = *pStr;
- Boolean inQuote = False;
- /* strip escapes out */
- for ( *nxt = *old; /* xfer but don't advance */
- *old != EOS;
- *nxt = *old ) /* xfer but don't advance */
- {
- if ( *old == ESCAPE_CHAR ) /* if an escaped char follows */
- {
- /* if ESCAPE_CHAR is not followed by a digit, e.g. \1
- or no replacement values exist, ignore it */
- if ( NULL == replaceValues
- || keepEscChar
- || isdigit(*(old+1)) == 0 )
- {
- if (!keepEscChar) old++; /* go past the escape char */
- else *nxt++ = *old++; /* copy esc char over */
- *nxt++ = *old++; /* keep just the char that was escaped
- and assign here to avoid tranlating
- that character, then move on to the
- next one */
- continue; /* CONTINUE */
- }
- else /* a value reference is being made */
- { /* get the refNum and advance the ptr */
- int refNum, numLen;
- int newOff, oldOff;
- sscanf(++old,"%d%n", &refNum, &numLen);
- old += numLen; /* move old ptr past the ref number */
- /* printf("%x=%s\n", replaceValues[refNum], replaceValues[refNum]); ** DBG */
- /* test for valid replacement */
- if ( refNum >= 0
- && refNum < MAXSPECQUARKS
- && replaceValues[refNum] != NULL)
- {
- int repLen;
- int strLen;
- char * oldTmp;
- char * newTmp;
- newOff = nxt - *pStr;
- oldOff = old - *pStr;
- repLen = strlen(replaceValues[refNum]);
- strLen = strlen(*pStr);
- /* expand memory and reset pointers */
- *pStr = realloc(*pStr,strlen(*pStr)+repLen+1);
- if (NULL == *pStr) return; /* RETURN */
- nxt = *pStr + newOff;
- old = *pStr + oldOff;
- /* move rest back to leave room for the replacement value */
- oldTmp = *pStr+strLen; /* pts to old EOS */
- newTmp = *pStr+strLen-(oldOff-newOff)+repLen;/*pts to new EOS*/
- while (oldTmp >= old) *newTmp-- = *oldTmp--;
- /* replace the ref with a value but don't append EOS */
- strncpy(nxt,replaceValues[refNum],repLen);
- nxt += repLen; /* move new to end of replace string */
- old += repLen - (oldOff-newOff);
- /* move old to end of expanded old string */
- } /* if valid replacement */
- } /* if a replacement requested */
- continue; /* CONTINUE */
- } /* if an escaped character */
- else
- { /* a non-escaped char; make further checks */
- if ( *old == COMMENT_CHAR )
- {
- *old = EOS; /* end the string */
- continue; /* CONTINUE */
- }
- else if ( *old == QUOTE_CHAR )
- {
- if ( !inQuote) inQuote = True; /* start quote */
- else inQuote = False; /* end quote */
- old++; /* go to next char */
- continue; /* CONTINUE */
- }
- else if ( !inQuote && isspace(*old) )
- {
- old++; /* skip the space */
- continue; /* CONTINUE */
- }
- } /* else non-escaped char */
- /* if survived all the checks, can advance to next char */
- nxt++;
- old++;
- }
- } /*$END$*/
- /*========================================================*/
- /*============== Private Xlate routines ==================*/
- /*========================================================*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: PrintDbEntry()
- $1LINER$: Prints a db entry to stdout
- $SUMMARY$:
- $ARGS$:
- quarks: NULLQUARK-terminated list of quarks for the LHS of the entry
- value: value of the RHS of the entry
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- void PrintDbEntry(
- XrmQuarkList quarks,
- XrmValue * value)
- { /*$CODE$*/
- char * str;
- XrmQuark quark;
- /* print the entry */
- quark=*quarks;
- while ( quark != NULLQUARK )
- {
- str = XrmQuarkToString(quark);
- fprintf(stderr,"%s", str);
- quark = *(++quarks);
- if (quark != NULLQUARK) fprintf(stderr,".");
- }
- fprintf(stderr,":%s\n",value->addr);
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: strCaseiCmp
- $1LINER$: case insensitive string comparison
- $SUMMARY$:
- Rolled my own because strcasecmp() not available on
- all platforms.
- $ARGS$:
- $RETURNS$:
- True: strings match
- False: they do not
- /*================================================$SKIP$==*/
- #endif
- static
- Boolean strCaseiCmp(
- const char * str1,
- const char * str2)
- { /*$CODE$*/
- /* if ( !str1 || !str2 ) return False; *//* unneeded performance hit */
- while ( *str1 && *str2 )
- if ( tolower(*str1++) != tolower(*str2++) ) return False;
- return (*str1 == *str2);
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: CheckForMatchall()
- $1LINER$: Matches search pattern to spec data
- $SUMMARY$:
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- Boolean CheckForMatchall(
- __DtXlateSrchData * srchData,
- const char * matchallString,
- const char * matchingString)
- { /*$CODE$*/
- int refNum = -1;
- int score = 0;
- /* test for a match all */
- if (! ( matchallString[0] == MATCHALL_CHAR
- && ( matchallString[1] == EOS
- || sscanf(matchallString+1,"%d", &refNum) == 1) ) )
- return False; /* RETURN: syntax error or non-matchall */
- /* matchall occurred; save the matching string if valid ref num */
- if ( refNum != -1
- && refNum >= 0
- && refNum < XtNumber(srchData->curSpecRefs) )
- {
- /* Don't store the string if it is just a matchall */
- /* This allows a replacement ref to be deleted on a match
- for which there is no replacement value. */
- if ( matchingString[0] == MATCHALL_CHAR
- && matchingString[1] == EOS )
- {
- srchData->curSpecRefs[refNum] = NULL;
- /* don't add to score for a matchall with no replacement value */
- }
- else
- {
- /* recall: string not owned by curSpecRefs */
- srchData->curSpecRefs[refNum] = matchingString;
- score = 1;
- }
- }
- else /* not a value reference; just determine if a plain match */
- {
- if ( matchingString[0] == MATCHALL_CHAR
- && matchingString[1] == EOS )
- score = 1; /* a plain matchall matches a plain matchall */
- }
- /* if a perfect matchall match, bump the score */
- srchData->curScore += score;
- return True; /* RETURN: matchall */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: CheckSearchPlatformMatchesSpec()
- $1LINER$: Matches search pattern to spec data
- $SUMMARY$:
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- Boolean CheckSearchPlatformMatchesSpec(
- __DtXlateSrchData * srchData,
- XrmQuark specPlatformQuark)
- { /*$CODE$*/
- /* CheckForMatchall stores away the matching string if of form ?n */
- if (srchData->platformQuark != NULLQUARK)
- {
- char * specStr = XrmQuarkToString(specPlatformQuark);
- /* CheckForMatchall incs score if appropriate */
- if (CheckForMatchall(srchData,specStr,srchData->platformStr) == True)
- return True; /* RETURN: platform matches */
- }
- if (srchData->platformQuark == specPlatformQuark)
- {
- srchData->curScore += 2; /* perfect match better than matchall match */
- return True; /* RETURN: platform matches */
- }
- return False; /* RETURN: platform doesnt match */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: CheckSearchVerMatchesSpec()
- $1LINER$: Matches search pattern to spec data
- $SUMMARY$:
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- Boolean CheckSearchVerMatchesSpec(
- __DtXlateSrchData * srchData,
- XrmQuark specVersionQuark)
- { /*$CODE$*/
- const char * numStr = XrmQuarkToString(specVersionQuark);
- int lowerBnd = 0;
- int upperBnd = INT_MAX;
- int score = 0;
- if ( srchData->version == MATCHALL_VER
- || CheckForMatchall(srchData,numStr,srchData->verStr) == True )
- return True; /* RETURN; matchall specified */
- /*** sscanf()-based parsing ***/
- /* note that the (score=x) is an assignment, not a compare */
- if ( (score=1) && sscanf(numStr,"%d-%d", &lowerBnd, &upperBnd) != 2
- && (score=1) && sscanf(numStr,"%d+", &lowerBnd) != 1
- && (score=2) && sscanf(numStr,"%d", &lowerBnd) != 1 )
- return False; /* RETURN: syntax error */
- if ( lowerBnd > srchData->version || upperBnd < srchData->version )
- return False; /* RETURN: version doesnt match */
- srchData->curScore += score;
- return True; /* RETURN: version matches */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: CheckSearchOperMatchesSpec()
- $1LINER$: Matches search pattern to spec data
- $SUMMARY$:
- $ARGS$:
- srchData: state of the search
- specOperationQuark: quark for the operation specification string
- $RETURNS$:
- True: if srchData->operation is found in specOperation string
- or the specOperation string is a match all
- False: if not
- /*================================================$SKIP$==*/
- #endif
- static
- Boolean CheckSearchOperMatchesSpec(
- __DtXlateSrchData * srchData,
- XrmQuark specOperationQuark)
- { /*$CODE$*/
- const char * opStr = XrmQuarkToString(specOperationQuark);
- int hitLen;
- const char * hit;
- const char * remainingOps;
- if ( srchData->operStr == NULL
- || CheckForMatchall(srchData,opStr,srchData->operStr) == True
- || CheckForMatchall(srchData,srchData->operStr,opStr) == True )
- return True; /* RETURN; matchall specified */
- /* quark compare search */
- if ( specOperationQuark == srchData->operQuark )
- goto matched;
- /*** strstr-based search ***/
- hitLen = srchData->operStrLen;
- remainingOps = opStr;
- do
- {
- /* look for operation in remainingOps */
- hit = strstr(remainingOps,srchData->operStr);
- /* see if the hit is on a complete token */
- if ( NULL != hit
- && (hit == remainingOps || *(hit-1) == OPER_SEPARATOR)
- && (hit[hitLen] == EOS || hit[hitLen] == OPER_SEPARATOR) )
- {
- matched:
- srchData->curScore += 2; /*perfect match better than a matchall match*/
- return True; /* RETURN: operation matches */
- }
- } while(hit != NULL && *(remainingOps = hit+1) != EOS);
- return False; /* RETURN: no match on operation */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: CheckSearchDirOpToStdMatchesSpec()
- $1LINER$: Matches search pattern to spec data
- $SUMMARY$:
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- Boolean CheckSearchDirOpToStdMatchesSpec(
- __DtXlateSrchData * srchData,
- XrmQuark specDirectionQuark)
- { /*$CODE$*/
- int score = 0;
- __DtXlateType type = __DtXLATE_TYPE_NONE;
- if (specDirectionQuark == srchData->inhibitQuark)
- return False; /* RETURN: no match */
- /* Note that the type and score expressions are assignments */
- if (! ( ( (type=__DtXLATE_TYPE_REGEX)
- && (specDirectionQuark == srchData->lessThanQuark))
- || ( (type=__DtXLATE_TYPE_PURE)
- && (score=1)
- && (specDirectionQuark == srchData->equalsToQuark))
- || ( (type=__DtXLATE_TYPE_CONTAINS)
- && (score=1)
- && (specDirectionQuark == srchData->containsQuark)) ) )
- return False; /* RETURN: no match */
- srchData->curScore += score;
- srchData->curTransType = type;
- return True; /* RETURN: direction matches */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: CheckSearchDirStdToOpMatchesSpec()
- $1LINER$: Matches search pattern to spec data
- $SUMMARY$:
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- Boolean CheckSearchDirStdToOpMatchesSpec(
- __DtXlateSrchData * srchData,
- XrmQuark specDirectionQuark)
- { /*$CODE$*/
- int score = 0;
- __DtXlateType type = __DtXLATE_TYPE_NONE;
- if (specDirectionQuark == srchData->inhibitQuark)
- return False; /* RETURN: no match */
- /* Note that the type and score expressions are assignments */
- if (! ( ( (type=__DtXLATE_TYPE_REGEX)
- && (specDirectionQuark == srchData->moreThanQuark))
- || ( (type=__DtXLATE_TYPE_PURE)
- && (score=1)
- && (specDirectionQuark == srchData->equalsToQuark))
- || ( (type=__DtXLATE_TYPE_CONTAINS)
- && (score=1)
- && (specDirectionQuark == srchData->containsQuark)) ) )
- return False; /* RETURN: no match */
- srchData->curScore += score;
- srchData->curTransType = type;
- return True; /* RETURN: direction matches */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: CheckSearchStdValueMatchesSpec()
- $1LINER$: Matches search pattern to spec data
- $SUMMARY$:
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- Boolean CheckSearchStdValueMatchesSpec(
- __DtXlateSrchData * srchData,
- XrmQuark * specStdValueQuarks)
- { /*$CODE$*/
- int score = 0;
- int unmatched = 0;
- XrmQuark * patQuarks;
- /* walk through all available quarks */
- for ( patQuarks = srchData->stdValueQuarks;
- *specStdValueQuarks != NULLQUARK && *patQuarks != NULLQUARK;
- specStdValueQuarks++, patQuarks++ )
- {
- char * specStr = XrmQuarkToString(*specStdValueQuarks);
- char * patStr = XrmQuarkToString(*patQuarks);
- if ( CheckForMatchall(srchData,specStr,patStr) == True
- || CheckForMatchall(srchData,patStr,specStr) == True )
- continue; /* no score for a matchall */
- /* is not exact match, match fails */
- /* be case insensitive when comparing standard values */
- if ( *patQuarks != *specStdValueQuarks
- && strCaseiCmp(specStr,patStr) == False )
- return False; /* RETURN: no match */
- /* one more match--increase score, go to next */
- score++;
- }
- /* find out how many stdValue fields were left unmatched */
- for ( unmatched = 0;
- *specStdValueQuarks != NULLQUARK;
- specStdValueQuarks++ )
- { unmatched++; }
- /* Score is combo of the number matched - the number unmatched
- and not counting the number matchalls that coincided with
- the search pattern. This technique allows the spec for
- val1 to be at "better" match than the one for val2, and
- val2 to be a better match than val3, and val3 to be a better
- match than val4.
- .a.std : val1 querypattern = a.std
- .?.std : val2 querypattern = a.std
- .?1.std : \\1val3 querypattern = a.std
- .a.std : val4 querypattern = ?.std
- .?.std : val5 querypattern = ?.std
- .?1.std : \\1val6 querypattern = ?.std
- .a.std.? : val4 querypattern = a.std
- .?.std.? : val5 querypattern = a.std
- .?.std.?1 : \\1val5 querypattern = a.std
- .?1.std.? : \\1val5 querypattern = a.std
- .?1.std.?2 : \\1\\2val5 querypattern = a.std
- .a.std.? : val4 querypattern = a.std.b
- .?.std.? : val5 querypattern = a.std.b
- .?.std.?1 : \\1val5 querypattern = a.std.b
- .?1.std.? : \\1val5 querypattern = a.std.b
- .?1.std.?2 : \\1\\2val5 querypattern = a.std.b
- */
- srchData->curScore += score + MAXSTDQUARKS - unmatched;
- return True; /* RETURN: direction matches */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: CheckSearchOpValueMatchesSpec()
- $1LINER$: Matches search pattern to spec data
- $SUMMARY$:
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- Boolean CheckSearchOpValueMatchesSpec(
- __DtXlateSrchData * srchData,
- const char * specOpValue)
- { /*$CODE$*/
- char opValBuf[MAXRHSSIZE]; /* max supported RHS size */
- char * pOpValBuf = opValBuf; /* need this for StripMeta... call */
- size_t opValLen;
- Boolean matches = False;
- /* copy value to mutable memory */
- strncpy(opValBuf,specOpValue,sizeof(opValBuf));
- opValBuf[sizeof(opValBuf)-1] = EOS;
- opValLen = strlen(opValBuf);
- /* depending on the translation type of the spec, do a
- regexex match of the spec value pattern to the search
- value or do a pure match */
- if (srchData->curTransType == __DtXLATE_TYPE_REGEX)
- {
- #if defined(sun)
- char * ex = NULL;
- /* True: leave escape char in place */
- StripMetaAndReplaceEscSubex(&pOpValBuf,True,NULL);
- /* we need to use regexex to pattern match */
- /* and we need to save of the reference value matches */
- if ( (ex = compile(opValBuf,NULL,NULL)) != NULL
- && advance(srchData->opValue,ex) != 0)
- {
- int matchSize;
- int subExCnt = nbra; /* Sun global for advance() */
- matches = True; /* if got this far */
- /* need due to bug in advance()--operation doesn't meet documentation */
- if (NULL == loc1) loc1=(char *)srchData->opValue;
- /* inc score by the size of the match after
- scaling for the maximum possible match size */
- matchSize = loc2 - loc1; /*loc[12] are Sun globals for advance()*/
- if (matchSize < 0 || matchSize >= sizeof(opValBuf)) matchSize = 0;
- /* NOTE: this scoring code should be identical in the
- Sun-specific and non-Sun code blocks */
- if (matchSize == strlen(srchData->opValue))
- {
- /* if the matchSize is the length of srchData->opValue,
- then we have a complete match. In this case, use the
- specificity of the pattern to pick the best match */
- /* NOTE: opValLen is a crude measure of specificity.
- A better measure would be to count the number of
- literals/ranges that matched exactly. When doing this,
- a perfect match without regex syntax should rank higher
- than a perfect match with regex syntax. This is one
- area where the current algorithm breaks. For example:
- opValue=23, pat1=23, pat2=[0-9]3.
- Both patterns match and pat1 is a better match,
- but not with the current length-based algorithm. */
- /* NOTE: this formula does not advance the score
- to sizeof(opValBuf) for a perfect match. Other match
- formulas use sizeof(opValBuf) as the max value
- to indicate a perfect match. */
- srchData->curScore += matchSize + opValLen;
- }
- else
- {
- /* if its not a complete match, inc score by match size */
- srchData->curScore += matchSize;
- }
- /* put sub expression matching stuff in srchData->curSubEx */
- for( ; nbra > 0; nbra-- )
- {
- srchData->curSubEx[nbra].rm_so = braslist[nbra-1] - loc1;
- srchData->curSubEx[nbra].rm_eo = braelist[nbra-1] - loc1;
- }
- }
- if (ex) free(ex);
- #else
- regex_t re;
- /* True: leave escape char in place */
- StripMetaAndReplaceEscSubex(&pOpValBuf,True,NULL);
- /* we need to use regexex to pattern match */
- /* and we need to save of the reference value matches */
- if ( regcomp(&re,opValBuf,0) == 0
- && regexec(&re,srchData->opValue,
- XtNumber(srchData->curSubEx),srchData->curSubEx,0) == 0)
- {
- int matchSize;
- matches = True; /* if got this far */
- /* inc score by the size of the match after
- scaling for the maximum possible match size */
- matchSize = srchData->curSubEx[0].rm_eo -
- srchData->curSubEx[0].rm_so;
- /* NOTE: this scoring code should be identical in the
- Sun-specific and non-Sun code blocks */
- if (matchSize == strlen(srchData->opValue))
- {
- /* if the matchSize is the length of srchData->opValue,
- then we have a complete match. In this case, use the
- specificity of the pattern to pick the best match */
- /* NOTE: opValLen is a crude measure of specificity.
- A better measure would be to count the number of
- literals/ranges that matched exactly. When doing this,
- a perfect match without regex syntax should rank higher
- than a perfect match with regex syntax. This is one
- area where the current algorithm breaks. For example:
- opValue=23, pat1=23, pat2=[0-9]3.
- Both patterns match and pat1 is a better match,
- but not with the current length-based algorithm. */
- /* NOTE: this formula does not advance the score
- to sizeof(opValBuf) for a perfect match. Other match
- formulas use sizeof(opValBuf) as the max value
- to indicate a perfect match. */
- srchData->curScore += matchSize + opValLen;
- }
- else
- {
- /* if its not a complete match, inc score by match size */
- srchData->curScore += matchSize;
- }
- /* sub expression matching stuff already in srchData->curSubEx */
- }
- regfree(&re);
- #endif
- }
- else /* (srchData->curTransType == __DtXLATE_TYPE_PURE || __DtXLATE_TYPE_CONTAINS */
- {
- char * opValueInBuf;
- /* False: strip escape char as well */
- StripMetaAndReplaceEscSubex(&pOpValBuf,False,NULL);
- matches = (strcmp(srchData->opValue,opValBuf) == 0);
- /* if matches, inc score to show a perfect match (max poss value) */
- if (matches) srchData->curScore += sizeof(opValBuf);
- /* don't test for contains if a perfect match or a pure match spec */
- if (matches || srchData->curTransType == __DtXLATE_TYPE_PURE)
- return matches; /* RETURN */
- /* (srchData->curTransType == __DtXLATE_TYPE_CONTAINS) */
- /* is opValue contained in opValBuf? */
- /* is opValBuf contained in opValue? */
- opValueInBuf = NULL;
- matches = (opValBuf[0] != EOS && srchData->opValue[0] != EOS)
- && ((opValueInBuf=strstr(opValBuf,srchData->opValue)) != NULL
- || strstr(srchData->opValue,opValBuf) != NULL);
- /* if matches, inc score to show a contains match */
- if (matches)
- {
- if (opValueInBuf) srchData->curScore += strlen(srchData->opValue);
- else srchData->curScore += strlen(opValBuf);
- }
- }
- return matches;
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: FindStdToOpMatchCB()
- $1LINER$: Matches std value of entry to search pattern; gets op value
- $SUMMARY$:
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- Bool FindStdToOpMatchCB(
- XrmDatabase * database,
- XrmBindingList bindings,
- XrmQuarkList quarks,
- XrmRepresentation * type,
- XrmValue * value,
- XPointer client_data)
- { /*$CODE$*/
- __DtXlateSrchData * srchData = (__DtXlateSrchData *) client_data;
- /* always begin scoring from 0 and replacement values at NULL */
- srchData->curScore = 0;
- memset(srchData->curSpecRefs,0, sizeof(srchData->curSpecRefs));
- #ifdef DBG_MATCHING
- fprintf(stderr,"FindStdToOpMatch: "); PrintDbEntry(quarks,value);
- #endif
- /* check for a match */
- if ( CheckSearchPlatformMatchesSpec(srchData,
- quarks[PLATFORM_QUARK]) == False)
- return False; /* continue enumeration */
- #ifdef DBG_MATCHING
- fprintf(stderr,"platform matches\n");
- #endif
- if ( CheckSearchVerMatchesSpec(srchData,
- quarks[VERSION_QUARK]) == False)
- return False; /* continue enumeration */
- #ifdef DBG_MATCHING
- fprintf(stderr,"ver matches\n");
- #endif
- if ( CheckSearchOperMatchesSpec(srchData,
- quarks[OPERS_QUARK]) == False)
- return False; /* continue enumeration */
- #ifdef DBG_MATCHING
- fprintf(stderr,"oper matches\n");
- #endif
- if ( CheckSearchDirStdToOpMatchesSpec(srchData,
- quarks[DIRECTION_QUARK]) == False)
- return False; /* continue enumeration */
- #ifdef DBG_MATCHING
- fprintf(stderr,"kind matches\n");
- #endif
- /* now check for std value match and, if it is
- the best match so far, record the value */
- if ( CheckSearchStdValueMatchesSpec(srchData,
- &quarks[FIRSTSTD_QUARK]) == False )
- {
- if (srchData->db->debugMode)
- {
- fprintf(stderr,"mismatch ");
- PrintDbEntry(quarks,value);
- }
-
- return False; /* continue enumeration */
- }
- #ifdef DBG_MATCHING
- fprintf(stderr,"std value matches\n");
- #endif
- if (srchData->db->debugMode)
- {
- fprintf(stderr,"match (%d) ",srchData->curScore);
- PrintDbEntry(quarks,value);
- }
-
- /* we have a match! (we made it through all match checks) */
- /* is it better than or same as any earlier match? */
- if ( srchData->curScore >= srchData->bestScore )
- {
- /* recall that all strings are owned by Xrm==>no need to free them */
- srchData->bestScore = srchData->curScore;
- srchData->bestTransType = srchData->curTransType;
- memcpy(srchData->bestSpecRefs,srchData->curSpecRefs,
- sizeof(srchData->bestSpecRefs)); /* no array assignment in C */
- srchData->opValue = value->addr;
- }
- return False; /* continue enumeration */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: FindOpToStdMatchCB()
- $1LINER$: Matches op value of entry to search pattern; gets std value
- $SUMMARY$:
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- Bool FindOpToStdMatchCB(
- XrmDatabase * database,
- XrmBindingList bindings,
- XrmQuarkList quarks,
- XrmRepresentation * type,
- XrmValue * value,
- XPointer client_data)
- { /*$CODE$*/
- __DtXlateSrchData * srchData = (__DtXlateSrchData *) client_data;
- /* always begin scoring from 0 and subexpression indices at -1 */
- srchData->curScore = 0;
- memset(srchData->curSubEx,-1, sizeof(srchData->curSubEx));
- #ifdef DBG_MATCHING
- fprintf(stderr,"FindOpToStdMatch: "); PrintDbEntry(quarks,value);
- #endif
- /* check for a match */
- if ( CheckSearchPlatformMatchesSpec(srchData,
- quarks[PLATFORM_QUARK]) == False)
- return False; /* continue enumeration */
- #ifdef DBG_MATCHING
- fprintf(stderr,"platform matches\n");
- #endif
- if ( CheckSearchVerMatchesSpec(srchData,
- quarks[VERSION_QUARK]) == False)
- return False; /* continue enumeration */
- #ifdef DBG_MATCHING
- fprintf(stderr,"ver matches\n");
- #endif
- if ( CheckSearchOperMatchesSpec(srchData,
- quarks[OPERS_QUARK]) == False)
- return False; /* continue enumeration */
- #ifdef DBG_MATCHING
- fprintf(stderr,"oper matches\n");
- #endif
- if ( CheckSearchDirOpToStdMatchesSpec(srchData,
- quarks[DIRECTION_QUARK]) == False)
- return False; /* continue enumeration */
- #ifdef DBG_MATCHING
- fprintf(stderr,"kind matches\n");
- #endif
- /* now check for op value match and, if it is
- the best match so far, record the std value */
- if ( CheckSearchOpValueMatchesSpec(srchData,
- value->addr) == False )
- {
- if (srchData->db->debugMode)
- {
- fprintf(stderr,"mismatch ");
- PrintDbEntry(quarks,value);
- }
-
- return False; /* continue enumeration */
- }
- #ifdef DBG_MATCHING
- fprintf(stderr,"op value matches\n");
- #endif
- if (srchData->db->debugMode)
- {
- fprintf(stderr,"match (%d) ",srchData->curScore);
- PrintDbEntry(quarks,value);
- }
- /* we have a match! (we made it through all match checks) */
- /* is it better than or same as any earlier match? */
- if ( srchData->curScore >= srchData->bestScore )
- {
- XrmQuarkList stdQ;
- XrmQuarkList curQ;
- /* recall that all strings are owned by Xrm==>no need to free them */
- srchData->bestScore = srchData->curScore;
- srchData->bestTransType = srchData->curTransType;
- memcpy(srchData->bestSubEx,srchData->curSubEx,
- sizeof(srchData->bestSubEx)); /* no array assignment in C */
- /* store off the std value of the best match */
- stdQ = srchData->stdValueQuarks;
- curQ = &quarks[FIRSTSTD_QUARK];
- while ( (*stdQ = *curQ) != NULLQUARK ) stdQ++, curQ++;
- }
- return False; /* continue enumeration */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $PFUNBEG$: DoCommonSrchDataPrep
- $1LINER$: Prep srchData to search for a pattern
- $SUMMARY$:
- $ARGS$:
- $RETURNS$:
- /*================================================$SKIP$==*/
- #endif
- static
- void DoCommonSrchDataPrep(
- __DtXlateSrchData * srchData,
- _DtXlateDb db,
- const char * platform,
- const int version,
- const char * operation)
- { /*$CODE$*/
- int verNum = version; /* for lint */
- /* zero the search data */
- memset(srchData,0,sizeof(__DtXlateSrchData));
- /* set the db */
- srchData->db = db;
-
- /* build filter list for enumerating the db */
- if (verNum < MATCHALL_VER) verNum = MATCHALL_VER;
- srchData->platformStr = platform;
- srchData->platformQuark = (platform?XrmStringToQuark(platform):NULLQUARK);
- srchData->version = verNum;
- sprintf(srchData->verStr,"%d",verNum);
- srchData->operStr = operation;
- srchData->operStrLen = strlen(operation);
- srchData->operQuark = (operation ? XrmStringToQuark(operation) : NULLQUARK);
- srchData->lessThanQuark = XrmStringToQuark(LESSTHAN_STR);
- srchData->equalsToQuark = XrmStringToQuark(EQUALS_STR);
- srchData->containsQuark = XrmStringToQuark(CONTAINS_STR);
- srchData->moreThanQuark = XrmStringToQuark(MORETHAN_STR);
- srchData->inhibitQuark = XrmStringToQuark(INHIBIT_STR);
- } /*$END$*/
- /*========================================================*/
- /*=============== Public Xlate routines ==================*/
- /*========================================================*/
- #if DOC
- /*========================================================*/
- $FUNBEG$: _DtXlateOpenDb()
- $1LINER$: Open a translation database
- $SUMMARY$:
- Opens a translation resource database and returns a
- reference to it in ret_db.
- Initializes the _DtXlateDb object to ready for use.
- If an error occurs, _DtXlateDb is set to NULL.
- $ARGS$:
- $RETURNS$:
- 0: no error occurred
- -1: if ret_db is NULL
- if XrmGetFileDatabase() failed on databaseName
- if malloc fails to alloc a db structure
- /*================================================$SKIP$==*/
- #endif
- int _DtXlateOpenDb(
- const char * databaseName,
- _DtXlateDb * ret_db)
- { /*$CODE$*/
- XrmDatabase xrmDb;
- __DtXlateDbRec * dbRec = NULL;
- char * path = NULL;
- if(NULL == ret_db) return -1; /* RETURN */
- *ret_db = NULL;
- /* Do NOT check for whether *ret_db is already
- a valid db; this is none of our affair. */
- /* get an absolute path for the file */
- path = ExpandPath(databaseName);
- if (NULL == path) return -1; /* RETURN */
- xrmDb = XrmGetFileDatabase(path);
- if (NULL == xrmDb) { free(path); return -1; } /* RETURN */
- /* alloc a db ref */
- dbRec = (__DtXlateDbRec *) calloc(1,sizeof(__DtXlateDbRec));
- if(NULL == dbRec)
- {
- XrmDestroyDatabase(xrmDb);
- free(path);
- return -1; /* RETURN */
- }
- /* and populate it */
- dbRec->xrmDb = xrmDb;
- dbRec->initGuard = INIT_OCCURRED;
- /* check for debug mode */
- SetDebugModeState(dbRec);
- if (dbRec->debugMode)
- fprintf(stderr,"_DtXlateOpenDb: opened: %s; new db: %p\n",path, (void *)dbRec);
- *ret_db = dbRec;
- free(path);
- return 0; /* RETURN */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $FUNBEG$: _DtXlateOpenAndMergeDbs()
- $1LINER$: Opens a translation database and merges with earlier dbs
- $SUMMARY$:
- Opens a translation resource database and returns a
- reference to it in ret_db.
- Initializes the _DtXlateDb object to ready for use.
- $ARGS$:
- $RETURNS$:
- 0: no error occurred
- -1: if io_db is NULL
- if XrmGetFileDatabase() failed on databaseName
- /*================================================$SKIP$==*/
- #endif
- int _DtXlateOpenAndMergeDbs(
- const char * databaseName,
- _DtXlateDb * io_db)
- { /*$CODE$*/
- XrmDatabase xrmDb;
- char * path;
- int ret;
- if(NULL == io_db) return -1; /* RETURN */
- /* if a db has not yet been opened */
- if( NULL == *io_db
- || (*io_db)->initGuard != INIT_OCCURRED
- || (*io_db)->xrmDb == NULL)
- {
- ret = _DtXlateOpenDb(databaseName,io_db); /* RETURN */
- if ( (*io_db) && (*io_db)->debugMode)
- fprintf(stderr,"_DtXlateOpenAndMergeDb: "
- "used _DtXlateOpenDb to open first file\n");
- return ret; /* RETURN */
- }
-
- if ( (*io_db) && (*io_db)->debugMode)
- fprintf(stderr,"_DtXlateOpenAndMergeDb: "
- "target file: %s; existing db: %p\n",databaseName, (void *) *io_db);
- /* a db has been opened, let's merge with it */
- /* get an absolute path for the file */
- path = ExpandPath(databaseName);
- if (NULL == path) goto Failed; /* RETURN */
- xrmDb = XrmGetFileDatabase(path);
- if (NULL == xrmDb) goto Failed; /* RETURN */
- /* merge and destroy xrmDb for me */
- XrmMergeDatabases(xrmDb,&(*io_db)->xrmDb);
- /* check for debug mode */
- SetDebugModeState(*io_db);
- if ((*io_db)->debugMode)
- fprintf(stderr,"_DtXlateOpenAndMergeDb: "
- "opened: %s; merged db: %p\n",path, (void *) *io_db);
- free(path);
- return 0; /* RETURN */
- Failed:
- if ( (*io_db) && (*io_db)->debugMode)
- fprintf(stderr,"_DtXlateOpenAndMergeDb: open failed; file: %s\n",
- (path ? path : (databaseName ? databaseName : "NULL") ) );
- if (path) free(path);
- return -1; /* RETURN */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $FUNBEG$: _DtXlateMergeDbs()
- $1LINER$: Merges two open dbs into one and closes the merged-in db.
- $SUMMARY$:
- Merges two databases into one and closes the merged db.
- The io_dbToMerge database must be a valid translation database.
- The io_dbToMerge database is merged into the io_mergeIntoDb.
- The io_mergeIntoDb may either be invalid or valid. If invalid,
- the io_dbToMerge database is simply moved over to io_mergeIntoDb.
- If io_mergeIntoDb is valid, the entries in the io_dbToMerge
- database are merged into it and take precedence over entries in the
- io_mergeIntoDb, and the io_dbToMerge database is closed.
- $ARGS$:
- io_dbToMerge: database to merge into io_mergeIntoDb
- io_mergeIntoDb: database to hold merged result
- $RETURNS$:
- 0: no error occurred
- -1: if io_dbToMerge or io_mergeIntoDb is NULL
- if *io_dbToMerge is NULL or uninitialized
- /*================================================$SKIP$==*/
- #endif
- int _DtXlateMergeDbs(
- _DtXlateDb * io_dbToMerge,
- _DtXlateDb * io_mergeIntoDb)
- { /*$CODE$*/
- /* check args */
- if( NULL == io_mergeIntoDb
- || NULL == io_dbToMerge
- || NULL == *io_dbToMerge
- || (*io_dbToMerge)->initGuard != INIT_OCCURRED
- || (*io_dbToMerge)->xrmDb == NULL)
- return -1; /* RETURN */
- /* check for debug mode */
- if ( ((*io_mergeIntoDb) && (*io_mergeIntoDb)->debugMode)
- || (*io_dbToMerge)->debugMode)
- fprintf(stderr,"_DtXlateMergeDbs: "
- "mergeIntoDb: %p; dbToMerge: %p\n", (void *) *io_mergeIntoDb, (void *) *io_dbToMerge);
- /* if db_mergeIntoDb has not yet been opened */
- if( NULL == *io_mergeIntoDb
- || (*io_mergeIntoDb)->initGuard != INIT_OCCURRED
- || (*io_mergeIntoDb)->xrmDb == NULL)
- {
- /* just move dbToMerge into mergeIntoDb */
- *io_mergeIntoDb = *io_dbToMerge;
- DeleteDbMem(io_dbToMerge);
- return 0; /* RETURN */
- }
-
- /* merge and destroy io_dbToMerge->xrmDb for me */
- XrmMergeDatabases((*io_dbToMerge)->xrmDb,&(*io_mergeIntoDb)->xrmDb);
- DeleteDbMem(io_dbToMerge);
- /* check for debug mode */
- SetDebugModeState(*io_mergeIntoDb);
- if ((*io_mergeIntoDb)->debugMode)
- fprintf(stderr,"merged db: %p\n", (void *) *io_mergeIntoDb);
- return 0;
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $FUNBEG$: _DtXlateOpenAllDbs()
- $1LINER$: Open and merge all locale translation databases that can be found
- $SUMMARY$:
- DtXlateOpenAllDbs() locates all translation databases
- present in the search paths directories.
- $ARGS$:
- searchPaths: ':' separated list of directories
- databaseName: name of the database file in those directories
- ret_db: the reference to the open database is stored here
- $RETURNS$:
- 0: at least one database was opened
- -1: no database was opened
- /*================================================$SKIP$==*/
- #endif
- int _DtXlateOpenAllDbs(
- const char * searchPaths,
- const char * databaseName,
- _DtXlateDb * ret_db)
- { /*$CODE$*/
- const char * workStart = searchPaths;
- const char * separator = NULL;
- char dbFile[MAXPATHLEN+1];
- int ret = ~0; /* all bits set */
- /* cycle through the paths, opening each one */
- do
- {
- int workLen = 0;
- const char * slash = NULL;
- dbFile[0] = EOS;
- /* isolate the next part of the path */
- _DtMBStrchr (workStart, PATH_SEPARATOR, -1, &separator);
- if (NULL == separator) _DtMBStrchr (workStart, EOS, -1, &separator);
- if (NULL == separator) break; /* BREAK */
- workLen = separator - workStart; /* don't include +1 for EOS */
- /* copy over the path component */
- strncpy(dbFile,workStart,workLen);
- workStart = separator + 1;
- /* add a slash to end of path component, if needed */
- *(dbFile+workLen) = EOS; /* add an EOS for _DtMBStrrchr to find */
- _DtMBStrrchr(dbFile,DIR_SLASH,-1,&slash);
- if (slash != dbFile+workLen-1) /* is slash last char of path? */
- {
- *(dbFile+workLen) = DIR_SLASH;
- workLen++;
- }
- /* append the filename and EOS */
- strcpy(dbFile+workLen,databaseName);
- /*printf("Working on: %s\n", dbFile); **DBG*/
- /* open and merge the database with previously opened dbs */
- /* by ANDing, we determine whether at least one call returned 0 */
- ret &= _DtXlateOpenAndMergeDbs(dbFile,ret_db);
- } while ( *separator != EOS );
- if (*ret_db && (*ret_db)->debugMode)
- fprintf(stderr,"_DtXlateOpenAllDbs: completed\n"
- " srchpaths: %s; db file: %s\n",searchPaths,databaseName);
- return (ret == 0 ? 0 : -1); /* ret != 0 ==> no db was opened */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $FUNBEG$: _DtXlateCloseDb()
- $1LINER$: Close an open translation database
- $SUMMARY$:
- _DtXlafteCloseDb() releases all memory associated with
- the translation database. Further use of the database
- object is an error.
- $ARGS$:
- $RETURNS$:
- 0: database was valid and has been closed
- -1: invalid database pointer
- /*================================================$SKIP$==*/
- #endif
- int _DtXlateCloseDb(
- _DtXlateDb * io_db)
- { /*$CODE$*/
- __DtXlateDbRec * dbRec;
-
- if( NULL == io_db
- || NULL == (dbRec = *io_db) /* dbRec assigned */
- || dbRec->initGuard != INIT_OCCURRED)
- return -1; /* RETURN */
-
- XrmDestroyDatabase(dbRec->xrmDb);
- if (dbRec->debugMode) fprintf(stderr,"_DtXlateCloseDb: %p\n", (void *) dbRec);
- /* zero out object mem and free it */
- DeleteDbMem(io_db);
- return 0;
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $FUNBEG$: _DbXlateStdToOpValue()
- $1LINER$: Translates a standardized spec to an operation-specific value
- $SUMMARY$:
- Looks up the best translation of the standard value for an
- operation and places a pointer to the translation string
- at the location pointed to by ret_opValue.
- The translated string was allocated using malloc() and
- must be freed when no longer needed.
- If ret_opValue is NULL, the function merely verifies that
- a valid translation exists.
- $ARGS$:
- db: a translation database
- platform: the platform string (see _DtXlateGetXlateEnv())
- version: the version number (see _DtXlateGetXlateEnv())
- operation: the operation of interest, e.g. "setlocale"
- stdValue: the standard value pattern
- ret_opValue: location where ptr to translated string is stored
- ret_reserved: reserved for future use
- $RETURNS$:
- 0: translation found
- -1: invalid database (NULL ptr, not opened)
- no operation was specified
- query failed to find a match
- /*================================================$SKIP$==*/
- #endif
- int _DtXlateStdToOpValue(
- _DtXlateDb db,
- const char * platform,
- const int version,
- const char * operation,
- const char * stdValue,
- char * * ret_opValue,
- void * ret_reserved)
- { /*$CODE$*/
- __DtXlateSrchData srchData;
- XrmQuark empty = NULLQUARK;
- if ( NULL == db
- || db->initGuard != INIT_OCCURRED
- || NULL == operation
- || operation[0] == EOS)
- return -1; /* RETURN error */
- /* prep srch data for search */
- DoCommonSrchDataPrep(&srchData,db,platform,version,operation);
- /* handle a rare case */
- if (NULL == stdValue)
- {
- if (db->debugMode) fprintf(stderr,"_DtXlateStdToOpValue: NULL std value\n");
- if (ret_opValue) *ret_opValue = NULL;
- return -1; /* RETURN error */
- }
- /* build std value list for use during comparison */
- srchData.stdValueQuarks[0] = NULLQUARK;
- if (NULL != stdValue && stdValue[0] != EOS)
- XrmStringToQuarkList(stdValue,srchData.stdValueQuarks);
- if (db->debugMode)
- fprintf(stderr,"_DtXlateStdToOpValue: %s.%d.%s.%s: <op>\n",
- platform,version,operation,stdValue);
- /* scan through this Db looking for matches and put in search */
- XrmEnumerateDatabase(db->xrmDb,&empty,&empty,
- XrmEnumAllLevels, FindStdToOpMatchCB, (XPointer) &srchData);
- if ( srchData.opValue != NULL
- && srchData.bestTransType != __DtXLATE_TYPE_INHIBIT )
- {
- char * opValue;
-
- if (ret_opValue == NULL)
- {
- if (db->debugMode) fprintf(stderr,"translation exists\n");
- return 0; /* RETURN: translation exists */
- }
-
- /* alloc the string to return */
- opValue = strdup(srchData.opValue);
- if (db->debugMode) fprintf(stderr,"raw opval:%s\n",opValue);
- /* do quote and escape removal and ref replacement in the opValue */
- if ( srchData.bestTransType == __DtXLATE_TYPE_REGEX )
- StripMetaAndReplaceEscSubex(&opValue,False,srchData.bestSpecRefs);
- else
- StripMetaAndReplaceEscSubex(&opValue,False,NULL);
- if (db->debugMode) fprintf(stderr,"op value:%s\n",opValue);
- *ret_opValue = opValue;
- return 0; /* RETURN: search successful */
- }
- return -1; /* RETURN: search failed */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $FUNBEG$: _DbXlateOpToStdValue()
- $1LINER$: Translates an operation-specific value to a standardized one
- $SUMMARY$:
- Looks up the best translation of the operation value for an
- operation and places a pointer to the standard string
- at the location pointed to by ret_stdValue.
- The standard string was allocated using malloc() and
- must be freed when no longer needed.
- If ret_stdValue is NULL, the function merely verifies that
- a valid translation exists.
- $ARGS$:
- db: a translation database
- platform: the platform string (see _DtXlateGetXlateEnv())
- version: the version number (see _DtXlateGetXlateEnv())
- operation: the operation of interest, e.g. "setlocale"
- opValue: the operation-specific value pattern
- ret_stdValue: location where ptr to standard string is stored
- ret_reserved: reserved for future use
- $RETURNS$:
- 0: translation found
- -1: invalid database (NULL ptr, not opened)
- no operation was specified
- query failed to find a match
- /*================================================$SKIP$==*/
- #endif
- int _DtXlateOpToStdValue(
- _DtXlateDb db,
- const char * platform,
- const int version,
- const char * operation,
- const char * opValue,
- char * * ret_stdValue,
- void * ret_reserved)
- { /*$CODE$*/
- __DtXlateSrchData srchData;
- XrmQuark empty = NULLQUARK;
- char lhs[MAXLHSSIZE];
- if ( NULL == db
- || db->initGuard != INIT_OCCURRED
- || NULL == operation
- || operation[0] == EOS)
- return -1; /* RETURN error */
- /* prep srch data for search */
- DoCommonSrchDataPrep(&srchData,db,platform,version,operation);
- /* after check on value, store op value for use during comparison */
- /* not meaningful to check for a NULL value */
- if (NULL == opValue)
- {
- if (db->debugMode) fprintf(stderr,"_DtXlateOpToStdValue: NULL op value\n");
- if (ret_stdValue) *ret_stdValue = NULL;
- return -1; /* RETURN error */
- }
- srchData.opValue = opValue;
- if (db->debugMode)
- fprintf(stderr,"_DtXlateOpToStdValue: %s.%d.%s.<std>: %s\n",
- platform,version,operation,opValue);
- /* scan through this Db looking for matches and put in search */
- XrmEnumerateDatabase(db->xrmDb,&empty,&empty,
- XrmEnumAllLevels, FindOpToStdMatchCB, (XPointer) &srchData);
- if ( srchData.stdValueQuarks[0] != NULLQUARK
- && srchData.bestTransType != __DtXLATE_TYPE_INHIBIT )
- {
- XrmQuarkList stdQ;
- char * stdValue = lhs;
- int stdValueLen = 0;
- if (ret_stdValue == NULL)
- {
- if (db->debugMode) fprintf(stderr,"translation exists\n");
- return 0; /* RETURN: translation exists */
- }
- /* make a STDVALUE_SEPARATOR separated string out of the std data */
- for ( stdQ = srchData.stdValueQuarks;
- *stdQ != NULLQUARK;
- stdQ++ )
- {
- const char * str = XrmQuarkToString(*stdQ);
- int strLen;
- if (NULL == str || str[0] == EOS) continue;
-
- strLen = strlen(str);
- if (stdValue != lhs)
- {*stdValue++ = STDVALUE_SEPARATOR; stdValueLen++; }
- if ((stdValueLen + strLen) > sizeof(lhs) )
- strLen = sizeof(lhs)-stdValueLen;
- strncpy(stdValue,str,strLen);
- stdValueLen += strLen;
- stdValue += strLen;
- }
- *stdValue = EOS;
- if (db->debugMode) fprintf(stderr,"raw stdval:%s\n",lhs);
- /* do quote and escape removal and ref replacement in the stdValue */
- stdValue = strdup(lhs); /* reset stdValue ptr */
- if ( srchData.bestTransType == __DtXLATE_TYPE_REGEX )
- ReplaceMatchallSubex(&stdValue,srchData.bestSubEx,srchData.opValue);
- if (db->debugMode) fprintf(stderr,"std value:%s\n",stdValue);
- *ret_stdValue = stdValue;
- return 0; /* RETURN: search successful */
- }
- return -1; /* RETURN: search failed */
- } /*$END$*/
- #if DOC
- /*========================================================*/
- $FUNBEG$: _DtXlateGetXlateEnv()
- $1LINER$: Get the DtXlate compilation and execution environments.
- $SUMMARY$:
- _DtXlateGetXlateEnv() recovers the identity of the application
- current platform, the version value of the application
- execution environment, and the version value of the operating
- system version for which DtXlateGetXlateEnv() was
- compiled. These values can be used in formulating queries,
- especially for the _DtXlateStdToOpValue() query.
- The technique used by this routine is as follows. Using
- uname(2), the routine retrieves the sysname, release, and version
- strings. The sysname is used as the platform name. The
- release and version strings are concatenated in that order
- and as treated below as the <op-rel-ver>. An OpToStd translation
- looks for a match to
- <sysname>.?.version.<.<std-version>: <op-rel-ver>
- or
- <sysname>.?.version.=.<std-version>: <op-rel-ver>
- If no match is found, the next fallback position is to
- get the specification with the same sysname and the highest
- std-version integer value. If no specifications exist for
- that sysname, then sysname is set to the empty string and
- std-version is -1.
- ret_AppExecEnvPlatform should point to a character array at least
- _DtPLATFORM_MAX_LEN characters long. The sysname is copied to it.
- ret_AppExecEnvVersion is given the integer value of the
- std-version recovered from the translation.
- ret_XlateCompiledForOSVersion is given the integer value
- determined by using the OSMajorVersion and OSMinorVersion
- constants defined by the build environment of _DtXlate as follows:
- #define _STR(V) #V
- #define STR(V) _STR(V)
- sprintf(buf,"%s%s%s", STR(OSMAJORVERSION),
- nl_langinfo(RADIXCHAR), STR(OSMAJORVERSION));
- verNum = (int) (100.0 * atof(buf));
- For example:
- OSMAJORVERSION & OSMINORVERSION are compile-time constants
- that must be defined as part of the build environment.
- It is assumed that these constants are of the form:
- e.g. Sun 5.3
- #define OSMAJORVERSION 5
- #define OSMINORVERSION 3
-
- 530 = (int) 100.0 * atof("5.3");
-
- e.g. HP-UX 8.09
- #define OSMAJORVERSION 8
- #define OSMINORVERSION 09
-
- 809 = (int) 100.0 * atof("8.09");
-
- Note that it may be necessary for the application to determine
- the version number of an operation in some platform-specific
- and operation-specific manner, for example using a library
- version value. In many cases, however, the O.S. version value
- for which _DtXlate was compiled will be sufficient
- when identifying version numbers for standard development
- environment libraries, such as libc.
- $EXAMPLE$:
- char *
- xlateStd2Op(_DtXlateDb db,Boolean runtimeOp, char * operation,char * stdVal)
- {
- char platform[_DtPLATFORM_MAX_LEN];
- int version;
- char * opVal = NULL;
- int ret;
- if (runtimeOp)
- ret=_DtXlateGetXlateEnv(db,platform,&version,NULL);
- else
- ret=_DtXlateGetXlateEnv(db,platform,NULL,&version);
- if (ret == 0)
- _DtXlateStdToOpValue(db,platform,version,operation,stdVal,&opVal,NULL);
- return opVal; /* will be NULL if error occurred */
- }
- $ARGS$:
- ret_AppExecEnvPlatform: pts to a string at least _DtPLATFORM_MAX_LEN long
- that will hold the string uname(2) returns for sysname
- ret_AppExecEnvVersion: pts to an integer that will receive the platform
- standardized version number, as determined by
- a translation on uname(2) release+version.
- ret_XlateCompiledForOSVersion: pts to an integer that will receive the
- operating system version for which _DtXlate was
- compiled using OSMajorVersion * 100 + OSMinorVersion
- Any of the arguments may be NULL.
- $RETURNS$:
- 0: if no error occurred
- -1: if no translation was possible to get the AppExecEnvVersion
- /*================================================$SKIP$==*/
- #endif
- int _DtXlateGetXlateEnv(
- _DtXlateDb db,
- char * ret_AppExecEnvPlatform,
- int * ret_AppExecEnvVersion,
- int * ret_XlateCompiledForOSVersion)
- { /*$CODE$*/
- struct utsname names;
- int ret = 0;
- char * platform = "NULL";
- int execver = -1;
- int compver = -1;
- /* get host specifics */
- uname(&names);
- /* first get execution host name */
- if (ret_AppExecEnvPlatform)
- {
- strncpy(ret_AppExecEnvPlatform,names.sysname,_DtPLATFORM_MAX_LEN-1);
- ret_AppExecEnvPlatform[_DtPLATFORM_MAX_LEN-1] = EOS;
- platform=ret_AppExecEnvPlatform;
- }
- /* then look up version number of execution host */
- if (ret_AppExecEnvVersion)
- {
- char version[sizeof(names.release)+sizeof(names.version)-1];
- char * stdVer = NULL;
- int verNum = MATCHALL_VER;
- /* cat release version and do a translation on it to a std value */
- /* then convert the std value to a integer */
- strncpy(version,names.release,sizeof(names.release)-1);
- version[sizeof(names.release)-1] = EOS;
- strncat(version,names.version,sizeof(names.version)-1);
- ret = _DtXlateOpToStdValue(db,names.sysname,0,
- _DtXLATE_OPER_VERSION,version,&stdVer,NULL);
- if (ret == 0)
- {
- if (sscanf(stdVer,"%d",&verNum) != 1) verNum = MATCHALL_VER;;
- free(stdVer);
- }
- *ret_AppExecEnvVersion = verNum;
- execver = verNum;
- }
-
- /* then look up version number of execution host */
- if (ret_XlateCompiledForOSVersion)
- {
- char buf[MAXINTSTRSIZE];
- #define _STR(V) #V
- #define STR(V) _STR(V)
- /*===========================
- OSMAJORVERSION & OSMINORVERSION are compile-time constants
- that must be defined as part of the build environment.
- It is assumed that these constants are of the form:
- e.g. Sun 5.3
- #define OSMAJORVERSION 5
- #define OSMINORVERSION 3
-
- 530 = (int) (100.0 * atof("5.3"));
-
- e.g. HP-UX 8.09
- #define OSMAJORVERSION 8
- #define OSMINORVERSION 09
-
- 809 = (int) (100.0 * atof("8.09"));
- ===========================*/
- #if !defined(OSMAJORVERSION) && !defined(OSMINORVERSION)
- #warning "OSMAJORVERSION and OSMINORVERSION not defined, assuming 99.0:
- #define OSMAJORVERSION 99
- #define OSMINORVERSION 0
- #endif
- #if defined(__linux__) || defined(CSRG_BASED)
- sprintf(buf,"%s%s%s", STR(OSMAJORVERSION),
- nl_langinfo('.'), STR(OSMINORVERSION));
- #else
- sprintf(buf,"%s%s%s", STR(OSMAJORVERSION),
- nl_langinfo(RADIXCHAR), STR(OSMINORVERSION));
- #endif
- *ret_XlateCompiledForOSVersion = (int) (100.0 * atof(buf));
- compver = *ret_XlateCompiledForOSVersion;
- }
- if (db->debugMode)
- fprintf(stderr,"_DtXlateGetXlateEnv: "
- "Platform: %s; Execution Ver: %d; Compiled Ver: %d\n",
- platform,execver,compver);
- return ret;
- } /*$END$*/
- /*========================================================*/
- /*================ Introductory Info =====================*/
- /*========================================================*/
- #if DOC
- /*========================================================*/
- $INTROBEG$: _DtXlate family
- $1LINER$: API to translate any value to a standard value and back again
- $SUMMARY$:
- _DtXlate is a collection of routines that allow translation
- between platform, version, and operation specific values
- into standard values and back again. Translation is
- based on the contents of database files specified using
- Xrm-style resources. The semantics of the translation
- are a combination of standard semantics for specifying
- platform, version, operation, and translation type, and
- caller-specific semantics for the standard value format
- and operation values.
- The API contains routines to process translation databases
- in a useful manner.
- _DtXlateOpenDb() opens a particular translation database
- _DtXlateOpenAndMergeDb() opens a particular database and
- merges it with an already opened one, overriding any
- repeated specifications.
- _DtXlateOpenAllDbs() opens all occurrences of a translation
- database found in a search path and cumulatively merges
- the contents, allowing for the override of existing
- specifications as well as the addition of new ones.
- _DtXlateCloseDb() closes an open database
- _DtXlateOpToStdValue() translates an platform, version,
- and operation specific value into a standard value.
- _DtXlateStdToOpValue() translates a standard value into
- a platform, version, and operation specific value.
- /*=$END$================================================*/
- #endif
- #if DOC
- /*========================================================*/
- $INTROBEG$: Design and Implementation Considerations
- $1LINER$: Factors influencing design and implementation
- $SUMMARY$:
- The syntax of the translation specification table is designed
- to be compatible with Xrm resource specifications. This
- allows Xrm to be used to load, parse, and merge the databases
- for processing. This also causes the specifications to be
- case-sensitive, as case is preserved by Xrm and is used when
- processing queries.
- However, due to the semantics of translation specifications
- and limitations of Xrm, XrmGetResource() queries generally
- will not be useful. Rather, a pattern matching API is provided
- that implements the query capability used for the translations.
- The initial implementation will use XrmEnumerateDatabase().
- Using Xrm leads to an in-memory approach to translation, meaning
- that all the resources files are parsed and loaded into memory
- as the first step of a translation. A line-at-a-time approach,
- that process one line at a time directly from the file in a
- grep- or awk-like manner, is likely more memory-efficient.
- Note that the line-at-a-time approach does not avoid parsing
- all the specification files, as the API supports inheritence
- and override of specifications. Hence, to ensure the correct
- value, the entire file set must be processed. Note also that
- in a situation where translations will be repeatedly performed,
- the Xrm in-memory approach may be more time-efficient, as the
- files need only be parsed once, and then are utilized repeatedly.
- Because of time constraints, a line-at-a-time approach will not
- be used for the first implementation, as Xrm provides all the
- necessary parsing, filtering, and symbol hashing routines
- for free. Given the likely large size of the tables and their
- infrequent use, a line-at-a-time approach is likely the better
- choice.
- /*=$END$================================================*/
- #endif
- #if DOC
- /*========================================================*/
- $INTROBEG$: translation BNF syntax and semantics
- $1LINER$: _DtXlate translation specification syntax and semantics
- $SUMMARY$:
- BNF Syntax of Translation Specification
- =======================================
- <specfile> ::= (<xlatespec> | <comment> | <cr>)*
- <xlatespec> ::= <platform>.<version>.<operations>.<transtype>
- .<stdvalue>:<opvalue> (<comment>|<cr>)
- <platform> ::= <identifier> | <matchall>
- <version> ::= <number> [+ | (- <number>)] | <matchall>
- <operations> ::= <identifier> [',' <identifier>]* | <matchall>
- <transtype> ::= '<' | '=' | '~' | '>' | '0'
- <stdvalue> ::= <identifier> [.<identifier>]*
- <langterr> ::= <identifier> | <matchall>
- <codeset> ::= <identifier> | <matchall>
- <modifier> ::= <identifier> | <matchall>
- <opvalue> ::= (<vischars>|<metachar>)+ | '"'(<anychar>|<metachar>)+'"'
- <matchall> ::= '?'[<number>]
- <cr> ::= '\n'
- <comment> ::= '!' [^<cr>]* <cr>
- <number> ::= [0-9]+
- <identifier> ::= [-_a-ZA-Z0-9]
- <vischar> ::= any non-whitespace character; meta and regular
- expression chars must be escaped with "\\"
- <anychar> ::= any printable character; meta and regular
- expression chars must be escaped with "\\"
- <metachar> ::= '!' | '"' | <backslash> | <valex> | <regex>
- <valex> ::= <backslash><number>
- <regex> ::= see regexp(5)
- <backslash> ::= the backslash character (\).
- Semantics of the Translation Specification
- ==========================================
- <specfile> : a file containing zero or more translation specifications
- or comments
- <xlatespec> : a translation specification defines a fully qualified
- string value which may be recovered by query pattern matching the
- specification. The qualifiers identify the semantics of the usage
- of the value, allowing queries to be meaningful. The entire xlatespec
- must be on one line of the file.
- <platform> : a CDE-standardized identifier for an operating system
- platform. The platform need not be supported by CDE, but CDE must
- have standardized an identifier for the platform in order for it to
- be used. For example, candidate platform identifiers are "HP-UX",
- "AIX", "SunOS", "Solaris", "SCO", etc. These identifiers are the
- values returned by uname(2):utsname.sysname and uname(1) -s, and
- I propose CDE standardize on using these values.
- The identifier string and matching constant value must be added to
- the source code of the translation routine in order for it to be
- recognized. This allows control over the platform registry
- and enables automatic generation of the platform on the execution
- host through the use of #ifdef <PLATFORM_CONST> in the source code.
- <version> : a platform-specific numeric value or range of numberic
- values that allows the value to be qualified to a particular version
- and release (version + release = version) or range of versions and
- releases of the platform. The version numbers must be integral and
- suitable for numeric comparison. The '+' can be used to specify an
- open upwards bound, as in 900+. The '- <number>' can be used to
- specify an upper bound, as in 900-999. If no range is specified,
- the version number must match exactly to the query pattern and/or
- execution environment.
- Platforms may not directly provide version numbers in a numeric
- format suitable for use when comparing with a translation
- specification. As part of the translation API source code,
- conversion routines must be supplied that translate the platform-
- specific values, such as those provided by uname(2), into a
- translation specification-compliant format suitable for comparison
- to <version>. Understanding the conversion routines operation
- will be necessary to ensure correct translation specifications.
- <operations> : a CDE-standardized identifier for the operation(s) to
- which the value applies. The operation(s) need not be supported by every
- platform, but CDE must have standardized an identifier for the operation
- in order for it to be used. More than one identifier may be included by
- concatenating them using the ',' separator, eg. "iconv1,iconv3".
- <transtype> : The <transtype> field records the direction of
- translation that the specification supports: '<', '=', '~', '>', '0'.
- Use '<' if the <opvalue> contains a regular expression; the
- specification may only be used to match an operation value in
- a _DtLcxXlateOpToStd() translation. Use '>' if the <opvalue>
- contains value replacement expressions using values from
- the <stdvalue> strings; the specification may only be used by a
- _DtLcxXlateStdToOp() translation. Use '=' if the <opvalue>
- is a pure string that may be used for either OpToStd() or
- StdToOp() translations, and the specification op-value must exactly
- match the op-value of the translation request. use '~' if the
- <opvalue> is a pure string that may be used for either OpToStd() or
- StdToOp() translations, and the specifation op-value must be
- a string within the op-value of the translation request.
- Use the '0' translation to represent that this particular
- translation should result in an error, that is should not result
- in a translation.
- Translations are two-way operations: from a host- and
- operation-specific value to standardized value, and back again.
- In many cases, a straight string value for string value translation
- is sufficient.
- But often, more sophisticated pattern matching and value generation
- mechanisms are useful to keep the table size small and as general
- as possible. In these cases, wildcard and regular expression
- operators are useful. Unfortunately, these specifications are not
- bi-direction. That is, the pattern matching string can be used
- to match against a pattern, but not to generate a result string.
- For example, the vi expression s/he*lo/hello/ matches "hello"
- as well as "hey look out below", but the reverse direction of
- "hello"->"he*lo" will not work.
- <stdvalue> : a sequence of one or more '.'-separated CDE-standardizd
- identifiers or matchall characters. This represents the canonical
- string used as a standard representation of a semantic value that
- may vary in different situations.
- <opvalue> : a string that has different uses depending on the
- value of <transtype>. If transtype is '<', the string is used
- as a regular expression to match the opValue in _DtLcxXlateOpToStd()
- requests. If the transtype is '>', the string is used as a
- replacement expression to generate a opValue in _DtLcxXlateStdToOp().
- If transtype is '=' or '~', the string is used as a straight string to
- both match for the OpToStd translation and as a value for
- the StdToOp translation.
- %
- If the opvalue contains whitespace, the opvalue must be enclosed in
- double quote characters. If the opvalue contains any meta characters
- that should not be treated as meta characters, they must be escaped by
- two preceding backslashs.Lack of an opvalue is not an error, but will
- be ignored during matches and return an empty string in a StdToOp
- translation; to specify that a given translation does not exist, the
- '0' translation type should be used or the specification should not
- occur.
- <comment> : a comment begins on an empty line with an unescaped !
- and continues to the end of the line.
- <matchall> : The matchall character is a universal quantifier, meaning
- that it symbolizes all possible values of the field where it is used.
- The matchall character may occur only in the qualifers side of
- a translation specification. Traditionally, the matchall character
- has been '*', but because of the semantics of Xrm, if the '*' is used
- as the matchall, Xrm does not restrict enumeration as needed.
- The matchall character may be followed by a number when the <transtype>
- is '>'. When this occurs, the string that matches the matchall
- character may be referenced in the <opvalue> by using the sequence
- \<number>, as in "\1". The occurrence is replaced with the matched
- string.
- /*=$END$================================================*/
- #endif
- #if DOC
- /*========================================================*/
- $INTROBEG$: translation specification examples
- $1LINER$: examples of _DtXlate translation specifications
- $EXAMPLE$:
- !! These are examples of bi-directional straight translations
- HP-UX.900-999.setlocale.=.en_US.hp-roman8: american
- HP-UX.900-999.setlocale.=.en_US.iso88591: american.iso88591
- HP-UX.900-999.setlocale.=.nl_BE.hp-roman8.fold: dutch@fold
- HP-UX.900-999.setlocale.=.nl_BE.hp-roman8.nofold: dutch@nofold
- !! These are examples of OpToStd translations utilizing regular
- !! expression patterns to match the search value.
- HP-UX.?.version.<.900: "A\\.09\\..*" !! any HPUX 9.x version
- HP-UX.?.version.<.807: "A\\.08\\.07.*"
- HP-UX.?.version.<.800: "A\\.08\\..*"
- AIX.?.version.<.320: "2 3"
- AIX.?.version.<.300: "[0-9] 3"
- SunOS.?.version.<.530: "5\\.3.*"
- SunOS.?.version.<.500: "5\\..*"
- !! These are examples of StdToOp translations utilizing matchall
- !! specifiers in the std value to match the search value.
- HP-UX.900+.iconv1.>.?.iso88596: arabic8
- HP-UX.900+.iconv1.>.?.iso88597: greek8
- HP-UX.900+.iconv1.>.?.hp-kana8: kana8
- HP-UX.900+.iconv1.>.?.hp-roman8: roman8
- !! The following examples use value replacement as part of their
- !! specifications. Using this can lead to much sparser tables, but
- !! it depends on op-specific and std values sharing the same strings.
- HP-UX.900-999.setlocale.<.nl_BE.hp-roman8.?1: [dD][uU][tT][cC][hH]@\\(.*\\)
- !HP-UX.900-999.setlocale.<.nl_BE.hp-roman8.?1: dutch@\\(.*\\)
- HP-UX.1000+.setlocale.>.?1.hp-roman8: \\1.roman8 !! all non-modif cases
- HP-UX.1000+.setlocale.>.?1.hp-roman8.?2: \\1.roman8@\\2 !! all modif cases
- /*=$END$================================================*/
- #endif
- #if DOC
- /*========================================================*/
- $INTROBEG$: _DtXlate example usage
- $1LINER$: Examples of how to _DtXlate
- $EXAMPLE$:
- #include <XlationSvc.h>
- main()
- {
- _DtXlateDb db = NULL;
- int ret;
- char plat[_DtPLATFORM_MAX_LEN];
- int execver;
- int compver;
- char * val = NULL;
- char * str = NULL;
- char empty = 0;
- #define OPER_YOUROP "myop"
- env = getenv("MYPATH");
- if (env == NULL) env = ∅
- ret = _DtXlateOpenAllDbs(env,"myfile.xlt",&db);
- ret = _DtXlateGetXlateEnv(db,plat,&execver,&compver);
- printf("Platform: %s\nExec Ver: %d\nComp Ver: %d\n",
- plat,execver,compver);
- ret = _DtXlateStdToOpValue(db,plat,compver,OPER_YOUROP,
- str="en_US.hp-roman8",&val,NULL);
- if (ret==0) printf("setlocale(%s) xlation=%s\n", str, val);
- else printf("no xlation\n", val);
- ret = _DtXlateOpToStdValue(db,plat,execver,OPER_YOUROP,
- str="american",&val,NULL);
- if (ret==0) printf("setlocale(%s) xlation=%s\n", str, val);
- else printf("no xlation\n", val);
- ret = _DtXlateCloseDb(&db);
- }
- /*=$END$================================================*/
- #endif
|