2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: XlationSvc.c /main/13 1999/10/14 15:59:35 mgreess $ */
24 /****************************************************************************
25 $FILEBEG$: XlationSvc.c
27 $COMPONENT$: DtXlate service
28 $1LINER$: Implements a translation service using tables and regex search
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.
35 ****************************************************************************
36 ************************************<+>*************************************/
42 #include <sys/utsname.h>
44 #include <limits.h> /* INT_MAX */
45 #include <pwd.h> /* for getpw... */
46 #include <sys/utsname.h> /* for uname */
47 #include <sys/param.h> /* MAXPATHLEN */
49 /* for RADIXCHAR and nl_langinfo */
51 # define RADIXCHAR MON_DECIMAL_POINT
55 #if defined(sun) || defined(USL) || defined(__uxp__)
56 #include <regexpr.h> /* for compile,advance */
58 #include <regex.h> /* for regcomp,regexec */
62 #include <X11/Intrinsic.h>
63 #include <X11/Xresource.h>
65 /*=================================================================
66 $SHAREDBEG$: This header appears in all appropriate DtXlate topics
67 =======================================================$SKIP$======*/
69 #include "XlationSvc.h"
70 #include "LocaleXlate.h"
73 /**** For extensive Introductory info, go to the end of this file ****/
75 /*========================================================*/
76 /*====================== Constants =======================*/
77 /*========================================================*/
79 /*=============== private =================*/
80 /*#define DBG_MATCHING ** if defined, debugging matching stages are compiled */
82 #define DEBUG_XLATE_NAME "dtXlate.debugDtXlate"
83 #define DEBUG_XLATE_CLASS "DtXlate.DebugDtXlate"
87 /* A "random" number used to ensure that the Db has been initalized */
88 #define INIT_OCCURRED 2329479
89 #define PATH_SEPARATOR ':'
92 #define LESSTHAN_STR "<"
93 #define EQUALS_STR "="
94 #define CONTAINS_STR "~"
95 #define MORETHAN_STR ">"
96 #define INHIBIT_STR "0"
98 #define MATCHALL_CHAR '?'
99 #define ESCAPE_CHAR '\\'
100 #define COMMENT_CHAR '!'
101 #define QUOTE_CHAR '\"'
102 #define OPER_SEPARATOR ','
103 #define STDVALUE_SEPARATOR '.'
104 #define MATCHALL_VER 0
106 #define PLATFORM_QUARK 0 /* index offsets into quarklist */
107 #define VERSION_QUARK 1
108 #define OPERS_QUARK 2
109 #define DIRECTION_QUARK 3
110 #define FIRSTSTD_QUARK 4
112 #define MAXSPECQUARKS 43 /* std + platform + version + operation */
113 #define MAXSTDQUARKS 40
114 #define MAXRHSSIZE 100 /* max supported RHS size */
115 #define MAXLHSSIZE 200 /* max supported LHS size */
116 #define MAXINTSTRSIZE 15 /* handle any long int -> string */
119 __DtXLATE_TYPE_NONE = 0,
120 __DtXLATE_TYPE_INHIBIT = 1,
121 __DtXLATE_TYPE_REGEX = 2,
122 __DtXLATE_TYPE_PURE = 3,
123 __DtXLATE_TYPE_CONTAINS = 4
126 #if defined(sun) || defined(USL) || defined(__uxp__)
127 /* Sun doesn't support regcomp() and regexec() yet, so
128 define this here and fill it will the results of advance() */
129 typedef struct regmatch_t {
130 int rm_so; /* start offset */
131 int rm_eo; /* end offset */
135 /*========================================================*/
136 /*====================== Typedefs ========================*/
137 /*========================================================*/
140 /*========================================================*/
141 $PTYPEBEG$: __DtXlateDbRec
142 $1LINER$: A private object used to represent translation dbs
144 __DtXlateDbRec is the type of the contents of a translation database
145 object. The database object must be opened before use and closed
146 after use. The definition of the object is opaque to users.
148 xrmDb: Xrm database used to hold specs
149 initGuard: used to test whether Db initialized
150 /*================================================$SKIP$==*/
154 typedef struct __DtXlateDbRec
163 /*========================================================*/
164 $PTYPEBEG$: __DtXlateSrchData
165 $1LINER$: A private object used to collect search-related data
167 __DtXlateSrchData stores all the data pertaining to a search
168 and the search results. The search routines utilize this
169 to maintain status info over multiple calls by the
170 enumeration routines and to return info to the routine
171 that initiated the search.
174 filterQuarks: quark list for the platform, version, and op filter
175 stdValueQuarks: quark list for the std value
176 opValue: ptr to operation-specific value string
177 SpecRef: indices 1 to MAXSPECQUARKS point to matching Xrm strings
178 SubEx: indices 1 to MAXSPECQUARKS index sub exprs in opValue
179 /*================================================$SKIP$==*/
182 typedef struct __DtXlateSrchData
188 const char * platformStr;
189 XrmQuark platformQuark;
191 char verStr[MAXINTSTRSIZE]; /* handle any long int */
192 const char * operStr;
195 XrmQuark lessThanQuark;
196 XrmQuark equalsToQuark;
197 XrmQuark containsQuark;
198 XrmQuark moreThanQuark;
199 XrmQuark inhibitQuark;
201 /* query or search info */
202 XrmQuark stdValueQuarks[MAXSTDQUARKS];
203 const char * opValue;
206 __DtXlateType curTransType;
207 __DtXlateType bestTransType;
210 /* MAXSPECQUARKS is depended upon elsewhere to be the size of these */
211 const char * curSpecRefs[MAXSPECQUARKS];
212 const char * bestSpecRefs[MAXSPECQUARKS];
213 regmatch_t curSubEx[MAXSPECQUARKS]; /* pattern match data */
214 regmatch_t bestSubEx[MAXSPECQUARKS]; /* pattern match data */
218 /*========================================================*/
219 /*================== Private routines ====================*/
220 /*========================================================*/
223 /*========================================================*/
224 $PFUNBEG$: ExpandPath()
225 $1LINER$: adds current working directory to front of path if its relative
227 If path is absolute, returns a malloced copy.
228 If path is relative, inserts the CWD in front of the relative path
229 and returns a mallocedd memory.
231 The caller must free the memory when no longer needed.
233 filespec: the pathname
235 ptr to mallocedd memory or NULL
236 /*================================================$SKIP$==*/
240 const char * filespec)
242 char tmpPath[MAXPATHLEN + 2];
245 const char * slash = NULL;
248 if (NULL == filespec) return NULL;
250 /*** is the file absolute ***/
251 /* if filespec begins with / then it is absolute */
252 if ( ( MB_CUR_MAX == 1
253 || mblen(filespec, MB_CUR_MAX) == 1)/* 1st char is 1 byte */
254 && *filespec == DIR_SLASH) /* and its a / */
256 return strdup(filespec); /* RETURN */
259 /*** otherwise, make it relative to the current directory ***/
261 /* get user's current working directory */
262 if (getcwd(tmpPath, MAXPATHLEN) == NULL) return NULL; /* RETURN: error */
264 /*** add a slash to end of path component, if needed ***/
265 /* get end of the string */
266 eos = tmpPath + strlen(tmpPath);
268 _DtMBStrrchr(tmpPath,DIR_SLASH,-1,&slash);
269 if (slash != (eos-1)) /* is slash last char of path? */
275 /* make a malloc'd copy of the path with room to grow */
276 pathName = malloc(sizeof(char) *
277 (strlen(filespec) + (eos-tmpPath) + 5) ); /* 5: arbitrary */
278 if (NULL == pathName) return NULL; /* RETURN: error */
280 /* build the absolute path */
281 strcpy(pathName,tmpPath);
282 strcat(pathName,filespec);
284 return pathName; /* RETURN: found */
288 /*========================================================*/
289 $PFUNBEG$: DeleteDbMem()
290 $1LINER$: Zeros out the db mem & frees it
292 Zeros out the db mem & frees it
293 The xrmDb should have already been destroyed before calling
298 /*================================================$SKIP$==*/
305 /* zero out object mem and free it */
306 (*io_db)->xrmDb = NULL;
307 (*io_db)->initGuard = 0;
313 /*========================================================*/
314 $IFUNBEG$: _DtMBStrchr()
315 $1LINER$: Searches for a character in a multibyte string
317 Returns in 'ret_ptr' the address of the first occurence of 'value'
318 in string s1. Value may also be the end of string marker '\0'.
321 -1 If found an invalid character.
322 0 If found value in string s2
323 1 If found the null byte character without finding 'value'.
324 'ret_ptr' will also be null in this case.
325 /*================================================$SKIP$==*/
332 const char * * ret_ptr )
340 if (!s1 || *s1 == '\0')
345 *ret_ptr = strchr (s1, value);
354 len = mblen (p1, max_len);
368 if (mbstowcs (&wcs, p1, 1) == value)
377 /* check for match on EOS */
378 if (*p1 == value) *ret_ptr = p1;
380 return ((*ret_ptr) ? 0 : 1);
385 /*========================================================*/
386 $IFUNBEG$: _DtMBStrrchr()
387 $1LINER$: Searches for a character in a multibyte string
389 Returns in 'ret_ptr' the address of the last occurence of 'value'
390 in string s1. Value may also be the end of string marker '\0'.
393 -1 If found an invalid character.
394 0 If found value in string s2
395 1 If found the null byte character without finding 'value'.
396 'ret_ptr' will also be null in this case.
397 /*================================================$SKIP$==*/
404 const char * * ret_ptr )
412 if (!s1 || *s1 == '\0')
417 *ret_ptr = strrchr (s1, value);
426 len = mblen (p1, max_len);
431 if (*p1 == value) *ret_ptr = p1;
436 if (mbstowcs (&wcs, p1, 1) == value) *ret_ptr = p1;
441 /* check for match on EOS */
442 if (*p1 == value) *ret_ptr = p1;
444 return ((*ret_ptr) ? 0 : 1);
449 /*========================================================*/
450 $PFUNBEG$: SetDebugModeState()
451 $1LINER$: Checks db for debug mode and sets flag
456 /*================================================$SKIP$==*/
460 void SetDebugModeState(
465 if (XrmGetResource(dbRec->xrmDb,
466 DEBUG_XLATE_NAME,DEBUG_XLATE_CLASS,&str_type,&value) == True)
467 dbRec->debugMode = True;
472 /*========================================================*/
473 $PFUNBEG$: ReplaceMatchallSubex()
474 $1LINER$: Replace matchall subexpression refs (e.g. ?1) with values
476 If subexpressions are specified and referenced, the
477 routine assumes that the string pointed to by pStr was
478 allocated using malloc() and can be resized using realloc().
479 The value and size of pStr may be different after the call.
481 This routine assumes it is working on a stdvalue expression
482 (e.g. from the LHS of a spec), that uses only stdvalue strings
483 or matchall-style subexpression replacement specs, e.g. ?1.
486 /*================================================$SKIP$==*/
490 void ReplaceMatchallSubex(
493 const char * matchedStr)
498 /* strip escapes out */
499 for ( *nxt = *old; /* xfer but don't advance */
501 *nxt = *old ) /* xfer but don't advance */
503 if ( *old == MATCHALL_CHAR ) /* if an escaped char follows */
505 /* if MATCHALL_CHAR is not followed by a digit, e.g. \1
506 or no replacement values exist, ignore it */
508 || isdigit(*(old+1)) == 0 )
510 old++; /* go past the escape char */
511 *nxt++ = *old++; /* keep just the char that was escaped
512 and assign here to avoid tranlating
513 that character, then move on to the
515 continue; /* CONTINUE */
517 else /* a value reference is being made */
518 { /* get the refNum and advance the ptr */
522 sscanf(++old,"%d%n", &refNum, &numLen);
523 old += numLen; /* move old ptr past the ref number */
525 /* printf("%d=%s\n", refNum, &matchedStr[subex[refNum].rm_so]); ** DBG */
527 /* test for valid replacement */
529 && refNum < MAXSPECQUARKS
530 && subex[refNum].rm_so != -1)
537 newOff = nxt - *pStr;
538 oldOff = old - *pStr;
539 repLen = subex[refNum].rm_eo - subex[refNum].rm_so;
540 strLen = strlen(*pStr);
542 /* expand memory and reset pointers */
543 *pStr = realloc(*pStr,strLen+repLen+1);
544 if (NULL == *pStr) return; /* RETURN */
545 nxt = *pStr + newOff;
546 old = *pStr + oldOff;
548 /* move rest back to leave room for the replacement value */
549 oldTmp = *pStr+strLen; /* pts to old EOS */
550 newTmp = *pStr+strLen-(oldOff-newOff)+repLen;/*pts to new EOS*/
551 while (oldTmp >= old) *newTmp-- = *oldTmp--;
553 /* replace the ref with a value but don't append EOS */
554 strncpy(nxt,&matchedStr[subex[refNum].rm_so],repLen);
555 nxt += repLen; /* move new to end of replace string */
556 old += repLen - (oldOff-newOff);
557 /* move old to end of expanded old string */
558 } /* if valid replacement */
559 } /* if a replacement requested */
560 continue; /* CONTINUE */
561 } /* if an escaped character */
562 /* if survived all the checks, can advance to next char */
570 /*========================================================*/
571 $PFUNBEG$: StripMetaAndReplaceEscSubex()
572 $1LINER$: Strips off meta chars and replaces escaped subex (e.g. \1) values
574 Strip is performed in place if replaceValues is NULL.
576 If replaceValues are specified and referenced, the
577 routine assumes that the string pointed to by pStr was
578 allocated using malloc() and can be resized using realloc().
579 The value and size of pStr may be different after the call.
582 This routine assumes it is working on a value expression
583 (e.g. from the RHS of a spec), that uses meta chars and
584 regex(5)-style subexpression replacement specs.
587 /*================================================$SKIP$==*/
591 void StripMetaAndReplaceEscSubex(
593 const Boolean keepEscChar,
594 const char * * replaceValues)
598 Boolean inQuote = False;
600 /* strip escapes out */
601 for ( *nxt = *old; /* xfer but don't advance */
603 *nxt = *old ) /* xfer but don't advance */
605 if ( *old == ESCAPE_CHAR ) /* if an escaped char follows */
607 /* if ESCAPE_CHAR is not followed by a digit, e.g. \1
608 or no replacement values exist, ignore it */
609 if ( NULL == replaceValues
611 || isdigit(*(old+1)) == 0 )
613 if (!keepEscChar) old++; /* go past the escape char */
614 else *nxt++ = *old++; /* copy esc char over */
615 *nxt++ = *old++; /* keep just the char that was escaped
616 and assign here to avoid tranlating
617 that character, then move on to the
619 continue; /* CONTINUE */
621 else /* a value reference is being made */
622 { /* get the refNum and advance the ptr */
626 sscanf(++old,"%d%n", &refNum, &numLen);
627 old += numLen; /* move old ptr past the ref number */
629 /* printf("%x=%s\n", replaceValues[refNum], replaceValues[refNum]); ** DBG */
631 /* test for valid replacement */
633 && refNum < MAXSPECQUARKS
634 && replaceValues[refNum] != NULL)
641 newOff = nxt - *pStr;
642 oldOff = old - *pStr;
643 repLen = strlen(replaceValues[refNum]);
644 strLen = strlen(*pStr);
645 /* expand memory and reset pointers */
646 *pStr = realloc(*pStr,strlen(*pStr)+repLen+1);
647 if (NULL == *pStr) return; /* RETURN */
648 nxt = *pStr + newOff;
649 old = *pStr + oldOff;
651 /* move rest back to leave room for the replacement value */
652 oldTmp = *pStr+strLen; /* pts to old EOS */
653 newTmp = *pStr+strLen-(oldOff-newOff)+repLen;/*pts to new EOS*/
654 while (oldTmp >= old) *newTmp-- = *oldTmp--;
656 /* replace the ref with a value but don't append EOS */
657 strncpy(nxt,replaceValues[refNum],repLen);
658 nxt += repLen; /* move new to end of replace string */
659 old += repLen - (oldOff-newOff);
660 /* move old to end of expanded old string */
661 } /* if valid replacement */
662 } /* if a replacement requested */
663 continue; /* CONTINUE */
664 } /* if an escaped character */
666 { /* a non-escaped char; make further checks */
667 if ( *old == COMMENT_CHAR )
669 *old = EOS; /* end the string */
670 continue; /* CONTINUE */
672 else if ( *old == QUOTE_CHAR )
674 if ( !inQuote) inQuote = True; /* start quote */
675 else inQuote = False; /* end quote */
676 old++; /* go to next char */
677 continue; /* CONTINUE */
679 else if ( !inQuote && isspace(*old) )
681 old++; /* skip the space */
682 continue; /* CONTINUE */
684 } /* else non-escaped char */
686 /* if survived all the checks, can advance to next char */
692 /*========================================================*/
693 /*============== Private Xlate routines ==================*/
694 /*========================================================*/
698 /*========================================================*/
699 $PFUNBEG$: PrintDbEntry()
700 $1LINER$: Prints a db entry to stdout
703 quarks: NULLQUARK-terminated list of quarks for the LHS of the entry
704 value: value of the RHS of the entry
706 /*================================================$SKIP$==*/
716 /* print the entry */
718 while ( quark != NULLQUARK )
720 str = XrmQuarkToString(quark);
721 fprintf(stderr,"%s", str);
723 if (quark != NULLQUARK) fprintf(stderr,".");
725 fprintf(stderr,":%s\n",value->addr);
730 /*========================================================*/
731 $PFUNBEG$: strCaseiCmp
732 $1LINER$: case insensitive string comparison
734 Rolled my own because strcasecmp() not available on
740 /*================================================$SKIP$==*/
748 /* if ( !str1 || !str2 ) return False; *//* unneeded performance hit */
749 while ( *str1 && *str2 )
750 if ( tolower(*str1++) != tolower(*str2++) ) return False;
751 return (*str1 == *str2);
755 /*========================================================*/
756 $PFUNBEG$: CheckForMatchall()
757 $1LINER$: Matches search pattern to spec data
761 /*================================================$SKIP$==*/
765 Boolean CheckForMatchall(
766 __DtXlateSrchData * srchData,
767 const char * matchallString,
768 const char * matchingString)
773 /* test for a match all */
774 if (! ( matchallString[0] == MATCHALL_CHAR
775 && ( matchallString[1] == EOS
776 || sscanf(matchallString+1,"%d", &refNum) == 1) ) )
777 return False; /* RETURN: syntax error or non-matchall */
779 /* matchall occurred; save the matching string if valid ref num */
782 && refNum < XtNumber(srchData->curSpecRefs) )
784 /* Don't store the string if it is just a matchall */
785 /* This allows a replacement ref to be deleted on a match
786 for which there is no replacement value. */
788 if ( matchingString[0] == MATCHALL_CHAR
789 && matchingString[1] == EOS )
791 srchData->curSpecRefs[refNum] = NULL;
792 /* don't add to score for a matchall with no replacement value */
796 /* recall: string not owned by curSpecRefs */
797 srchData->curSpecRefs[refNum] = matchingString;
801 else /* not a value reference; just determine if a plain match */
803 if ( matchingString[0] == MATCHALL_CHAR
804 && matchingString[1] == EOS )
805 score = 1; /* a plain matchall matches a plain matchall */
808 /* if a perfect matchall match, bump the score */
809 srchData->curScore += score;
811 return True; /* RETURN: matchall */
816 /*========================================================*/
817 $PFUNBEG$: CheckSearchPlatformMatchesSpec()
818 $1LINER$: Matches search pattern to spec data
822 /*================================================$SKIP$==*/
826 Boolean CheckSearchPlatformMatchesSpec(
827 __DtXlateSrchData * srchData,
828 XrmQuark specPlatformQuark)
830 /* CheckForMatchall stores away the matching string if of form ?n */
831 if (srchData->platformQuark != NULLQUARK)
833 char * specStr = XrmQuarkToString(specPlatformQuark);
834 /* CheckForMatchall incs score if appropriate */
835 if (CheckForMatchall(srchData,specStr,srchData->platformStr) == True)
836 return True; /* RETURN: platform matches */
838 if (srchData->platformQuark == specPlatformQuark)
840 srchData->curScore += 2; /* perfect match better than matchall match */
841 return True; /* RETURN: platform matches */
843 return False; /* RETURN: platform doesnt match */
848 /*========================================================*/
849 $PFUNBEG$: CheckSearchVerMatchesSpec()
850 $1LINER$: Matches search pattern to spec data
854 /*================================================$SKIP$==*/
858 Boolean CheckSearchVerMatchesSpec(
859 __DtXlateSrchData * srchData,
860 XrmQuark specVersionQuark)
862 const char * numStr = XrmQuarkToString(specVersionQuark);
864 int upperBnd = INT_MAX;
867 if ( srchData->version == MATCHALL_VER
868 || CheckForMatchall(srchData,numStr,srchData->verStr) == True )
869 return True; /* RETURN; matchall specified */
871 /*** sscanf()-based parsing ***/
872 /* note that the (score=x) is an assignment, not a compare */
873 if ( (score=1) && sscanf(numStr,"%d-%d", &lowerBnd, &upperBnd) != 2
874 && (score=1) && sscanf(numStr,"%d+", &lowerBnd) != 1
875 && (score=2) && sscanf(numStr,"%d", &lowerBnd) != 1 )
876 return False; /* RETURN: syntax error */
878 if ( lowerBnd > srchData->version || upperBnd < srchData->version )
879 return False; /* RETURN: version doesnt match */
881 srchData->curScore += score;
882 return True; /* RETURN: version matches */
888 /*========================================================*/
889 $PFUNBEG$: CheckSearchOperMatchesSpec()
890 $1LINER$: Matches search pattern to spec data
893 srchData: state of the search
894 specOperationQuark: quark for the operation specification string
896 True: if srchData->operation is found in specOperation string
897 or the specOperation string is a match all
899 /*================================================$SKIP$==*/
903 Boolean CheckSearchOperMatchesSpec(
904 __DtXlateSrchData * srchData,
905 XrmQuark specOperationQuark)
907 const char * opStr = XrmQuarkToString(specOperationQuark);
910 const char * remainingOps;
912 if ( srchData->operStr == NULL
913 || CheckForMatchall(srchData,opStr,srchData->operStr) == True
914 || CheckForMatchall(srchData,srchData->operStr,opStr) == True )
915 return True; /* RETURN; matchall specified */
917 /* quark compare search */
918 if ( specOperationQuark == srchData->operQuark )
921 /*** strstr-based search ***/
922 hitLen = srchData->operStrLen;
923 remainingOps = opStr;
926 /* look for operation in remainingOps */
927 hit = strstr(remainingOps,srchData->operStr);
928 /* see if the hit is on a complete token */
930 && (hit == remainingOps || *(hit-1) == OPER_SEPARATOR)
931 && (hit[hitLen] == EOS || hit[hitLen] == OPER_SEPARATOR) )
934 srchData->curScore += 2; /*perfect match better than a matchall match*/
935 return True; /* RETURN: operation matches */
937 } while(hit != NULL && *(remainingOps = hit+1) != EOS);
939 return False; /* RETURN: no match on operation */
945 /*========================================================*/
946 $PFUNBEG$: CheckSearchDirOpToStdMatchesSpec()
947 $1LINER$: Matches search pattern to spec data
951 /*================================================$SKIP$==*/
955 Boolean CheckSearchDirOpToStdMatchesSpec(
956 __DtXlateSrchData * srchData,
957 XrmQuark specDirectionQuark)
960 __DtXlateType type = __DtXLATE_TYPE_NONE;
962 if (specDirectionQuark == srchData->inhibitQuark)
963 return False; /* RETURN: no match */
965 /* Note that the type and score expressions are assignments */
966 if (! ( ( (type=__DtXLATE_TYPE_REGEX)
967 && (specDirectionQuark == srchData->lessThanQuark))
968 || ( (type=__DtXLATE_TYPE_PURE)
970 && (specDirectionQuark == srchData->equalsToQuark))
971 || ( (type=__DtXLATE_TYPE_CONTAINS)
973 && (specDirectionQuark == srchData->containsQuark)) ) )
974 return False; /* RETURN: no match */
976 srchData->curScore += score;
977 srchData->curTransType = type;
978 return True; /* RETURN: direction matches */
983 /*========================================================*/
984 $PFUNBEG$: CheckSearchDirStdToOpMatchesSpec()
985 $1LINER$: Matches search pattern to spec data
989 /*================================================$SKIP$==*/
993 Boolean CheckSearchDirStdToOpMatchesSpec(
994 __DtXlateSrchData * srchData,
995 XrmQuark specDirectionQuark)
998 __DtXlateType type = __DtXLATE_TYPE_NONE;
1000 if (specDirectionQuark == srchData->inhibitQuark)
1001 return False; /* RETURN: no match */
1003 /* Note that the type and score expressions are assignments */
1004 if (! ( ( (type=__DtXLATE_TYPE_REGEX)
1005 && (specDirectionQuark == srchData->moreThanQuark))
1006 || ( (type=__DtXLATE_TYPE_PURE)
1008 && (specDirectionQuark == srchData->equalsToQuark))
1009 || ( (type=__DtXLATE_TYPE_CONTAINS)
1011 && (specDirectionQuark == srchData->containsQuark)) ) )
1012 return False; /* RETURN: no match */
1014 srchData->curScore += score;
1015 srchData->curTransType = type;
1016 return True; /* RETURN: direction matches */
1022 /*========================================================*/
1023 $PFUNBEG$: CheckSearchStdValueMatchesSpec()
1024 $1LINER$: Matches search pattern to spec data
1028 /*================================================$SKIP$==*/
1032 Boolean CheckSearchStdValueMatchesSpec(
1033 __DtXlateSrchData * srchData,
1034 XrmQuark * specStdValueQuarks)
1038 XrmQuark * patQuarks;
1040 /* walk through all available quarks */
1041 for ( patQuarks = srchData->stdValueQuarks;
1042 *specStdValueQuarks != NULLQUARK && *patQuarks != NULLQUARK;
1043 specStdValueQuarks++, patQuarks++ )
1045 char * specStr = XrmQuarkToString(*specStdValueQuarks);
1046 char * patStr = XrmQuarkToString(*patQuarks);
1047 if ( CheckForMatchall(srchData,specStr,patStr) == True
1048 || CheckForMatchall(srchData,patStr,specStr) == True )
1049 continue; /* no score for a matchall */
1051 /* is not exact match, match fails */
1052 /* be case insensitive when comparing standard values */
1053 if ( *patQuarks != *specStdValueQuarks
1054 && strCaseiCmp(specStr,patStr) == False )
1055 return False; /* RETURN: no match */
1057 /* one more match--increase score, go to next */
1061 /* find out how many stdValue fields were left unmatched */
1062 for ( unmatched = 0;
1063 *specStdValueQuarks != NULLQUARK;
1064 specStdValueQuarks++ )
1067 /* Score is combo of the number matched - the number unmatched
1068 and not counting the number matchalls that coincided with
1069 the search pattern. This technique allows the spec for
1070 val1 to be at "better" match than the one for val2, and
1071 val2 to be a better match than val3, and val3 to be a better
1073 .a.std : val1 querypattern = a.std
1074 .?.std : val2 querypattern = a.std
1075 .?1.std : \\1val3 querypattern = a.std
1076 .a.std : val4 querypattern = ?.std
1077 .?.std : val5 querypattern = ?.std
1078 .?1.std : \\1val6 querypattern = ?.std
1080 .a.std.? : val4 querypattern = a.std
1081 .?.std.? : val5 querypattern = a.std
1082 .?.std.?1 : \\1val5 querypattern = a.std
1083 .?1.std.? : \\1val5 querypattern = a.std
1084 .?1.std.?2 : \\1\\2val5 querypattern = a.std
1085 .a.std.? : val4 querypattern = a.std.b
1086 .?.std.? : val5 querypattern = a.std.b
1087 .?.std.?1 : \\1val5 querypattern = a.std.b
1088 .?1.std.? : \\1val5 querypattern = a.std.b
1089 .?1.std.?2 : \\1\\2val5 querypattern = a.std.b
1091 srchData->curScore += score + MAXSTDQUARKS - unmatched;
1093 return True; /* RETURN: direction matches */
1099 /*========================================================*/
1100 $PFUNBEG$: CheckSearchOpValueMatchesSpec()
1101 $1LINER$: Matches search pattern to spec data
1105 /*================================================$SKIP$==*/
1109 Boolean CheckSearchOpValueMatchesSpec(
1110 __DtXlateSrchData * srchData,
1111 const char * specOpValue)
1113 char opValBuf[MAXRHSSIZE]; /* max supported RHS size */
1114 char * pOpValBuf = opValBuf; /* need this for StripMeta... call */
1116 Boolean matches = False;
1118 /* copy value to mutable memory */
1119 strncpy(opValBuf,specOpValue,sizeof(opValBuf));
1120 opValBuf[sizeof(opValBuf)-1] = EOS;
1121 opValLen = strlen(opValBuf);
1123 /* depending on the translation type of the spec, do a
1124 regexex match of the spec value pattern to the search
1125 value or do a pure match */
1126 if (srchData->curTransType == __DtXLATE_TYPE_REGEX)
1128 #if defined(sun) || defined(USL) || defined(__uxp__)
1131 /* True: leave escape char in place */
1132 StripMetaAndReplaceEscSubex(&pOpValBuf,True,NULL);
1134 /* we need to use regexex to pattern match */
1135 /* and we need to save of the reference value matches */
1136 if ( (ex = compile(opValBuf,NULL,NULL)) != NULL
1137 && advance(srchData->opValue,ex) != 0)
1140 int subExCnt = nbra; /* Sun global for advance() */
1141 matches = True; /* if got this far */
1143 /* need due to bug in advance()--operation doesn't meet documentation */
1144 if (NULL == loc1) loc1=(char *)srchData->opValue;
1146 /* inc score by the size of the match after
1147 scaling for the maximum possible match size */
1148 matchSize = loc2 - loc1; /*loc[12] are Sun globals for advance()*/
1149 if (matchSize < 0 || matchSize >= sizeof(opValBuf)) matchSize = 0;
1151 /* NOTE: this scoring code should be identical in the
1152 Sun-specific and non-Sun code blocks */
1153 if (matchSize == strlen(srchData->opValue))
1155 /* if the matchSize is the length of srchData->opValue,
1156 then we have a complete match. In this case, use the
1157 specificity of the pattern to pick the best match */
1158 /* NOTE: opValLen is a crude measure of specificity.
1159 A better measure would be to count the number of
1160 literals/ranges that matched exactly. When doing this,
1161 a perfect match without regex syntax should rank higher
1162 than a perfect match with regex syntax. This is one
1163 area where the current algorithm breaks. For example:
1164 opValue=23, pat1=23, pat2=[0-9]3.
1165 Both patterns match and pat1 is a better match,
1166 but not with the current length-based algorithm. */
1167 /* NOTE: this formula does not advance the score
1168 to sizeof(opValBuf) for a perfect match. Other match
1169 formulas use sizeof(opValBuf) as the max value
1170 to indicate a perfect match. */
1171 srchData->curScore += matchSize + opValLen;
1175 /* if its not a complete match, inc score by match size */
1176 srchData->curScore += matchSize;
1179 /* put sub expression matching stuff in srchData->curSubEx */
1180 for( ; nbra > 0; nbra-- )
1182 srchData->curSubEx[nbra].rm_so = braslist[nbra-1] - loc1;
1183 srchData->curSubEx[nbra].rm_eo = braelist[nbra-1] - loc1;
1190 /* True: leave escape char in place */
1191 StripMetaAndReplaceEscSubex(&pOpValBuf,True,NULL);
1193 /* we need to use regexex to pattern match */
1194 /* and we need to save of the reference value matches */
1195 if ( regcomp(&re,opValBuf,0) == 0
1196 && regexec(&re,srchData->opValue,
1197 XtNumber(srchData->curSubEx),srchData->curSubEx,0) == 0)
1200 matches = True; /* if got this far */
1202 /* inc score by the size of the match after
1203 scaling for the maximum possible match size */
1204 matchSize = srchData->curSubEx[0].rm_eo -
1205 srchData->curSubEx[0].rm_so;
1207 /* NOTE: this scoring code should be identical in the
1208 Sun-specific and non-Sun code blocks */
1209 if (matchSize == strlen(srchData->opValue))
1211 /* if the matchSize is the length of srchData->opValue,
1212 then we have a complete match. In this case, use the
1213 specificity of the pattern to pick the best match */
1214 /* NOTE: opValLen is a crude measure of specificity.
1215 A better measure would be to count the number of
1216 literals/ranges that matched exactly. When doing this,
1217 a perfect match without regex syntax should rank higher
1218 than a perfect match with regex syntax. This is one
1219 area where the current algorithm breaks. For example:
1220 opValue=23, pat1=23, pat2=[0-9]3.
1221 Both patterns match and pat1 is a better match,
1222 but not with the current length-based algorithm. */
1223 /* NOTE: this formula does not advance the score
1224 to sizeof(opValBuf) for a perfect match. Other match
1225 formulas use sizeof(opValBuf) as the max value
1226 to indicate a perfect match. */
1227 srchData->curScore += matchSize + opValLen;
1231 /* if its not a complete match, inc score by match size */
1232 srchData->curScore += matchSize;
1235 /* sub expression matching stuff already in srchData->curSubEx */
1240 else /* (srchData->curTransType == __DtXLATE_TYPE_PURE || __DtXLATE_TYPE_CONTAINS */
1242 char * opValueInBuf;
1244 /* False: strip escape char as well */
1245 StripMetaAndReplaceEscSubex(&pOpValBuf,False,NULL);
1246 matches = (strcmp(srchData->opValue,opValBuf) == 0);
1248 /* if matches, inc score to show a perfect match (max poss value) */
1249 if (matches) srchData->curScore += sizeof(opValBuf);
1251 /* don't test for contains if a perfect match or a pure match spec */
1252 if (matches || srchData->curTransType == __DtXLATE_TYPE_PURE)
1253 return matches; /* RETURN */
1255 /* (srchData->curTransType == __DtXLATE_TYPE_CONTAINS) */
1256 /* is opValue contained in opValBuf? */
1257 /* is opValBuf contained in opValue? */
1258 opValueInBuf = NULL;
1259 matches = (opValBuf[0] != EOS && srchData->opValue[0] != EOS)
1260 && ((opValueInBuf=strstr(opValBuf,srchData->opValue)) != NULL
1261 || strstr(srchData->opValue,opValBuf) != NULL);
1263 /* if matches, inc score to show a contains match */
1266 if (opValueInBuf) srchData->curScore += strlen(srchData->opValue);
1267 else srchData->curScore += strlen(opValBuf);
1277 /*========================================================*/
1278 $PFUNBEG$: FindStdToOpMatchCB()
1279 $1LINER$: Matches std value of entry to search pattern; gets op value
1283 /*================================================$SKIP$==*/
1287 Bool FindStdToOpMatchCB(
1288 XrmDatabase * database,
1289 XrmBindingList bindings,
1290 XrmQuarkList quarks,
1291 XrmRepresentation * type,
1293 XPointer client_data)
1295 __DtXlateSrchData * srchData = (__DtXlateSrchData *) client_data;
1297 /* always begin scoring from 0 and replacement values at NULL */
1298 srchData->curScore = 0;
1299 memset(srchData->curSpecRefs,0, sizeof(srchData->curSpecRefs));
1302 fprintf(stderr,"FindStdToOpMatch: "); PrintDbEntry(quarks,value);
1305 /* check for a match */
1306 if ( CheckSearchPlatformMatchesSpec(srchData,
1307 quarks[PLATFORM_QUARK]) == False)
1308 return False; /* continue enumeration */
1311 fprintf(stderr,"platform matches\n");
1314 if ( CheckSearchVerMatchesSpec(srchData,
1315 quarks[VERSION_QUARK]) == False)
1316 return False; /* continue enumeration */
1319 fprintf(stderr,"ver matches\n");
1322 if ( CheckSearchOperMatchesSpec(srchData,
1323 quarks[OPERS_QUARK]) == False)
1324 return False; /* continue enumeration */
1327 fprintf(stderr,"oper matches\n");
1330 if ( CheckSearchDirStdToOpMatchesSpec(srchData,
1331 quarks[DIRECTION_QUARK]) == False)
1332 return False; /* continue enumeration */
1335 fprintf(stderr,"kind matches\n");
1338 /* now check for std value match and, if it is
1339 the best match so far, record the value */
1340 if ( CheckSearchStdValueMatchesSpec(srchData,
1341 &quarks[FIRSTSTD_QUARK]) == False )
1343 if (srchData->db->debugMode)
1345 fprintf(stderr,"mismatch ");
1346 PrintDbEntry(quarks,value);
1349 return False; /* continue enumeration */
1353 fprintf(stderr,"std value matches\n");
1356 if (srchData->db->debugMode)
1358 fprintf(stderr,"match (%d) ",srchData->curScore);
1359 PrintDbEntry(quarks,value);
1362 /* we have a match! (we made it through all match checks) */
1363 /* is it better than or same as any earlier match? */
1364 if ( srchData->curScore >= srchData->bestScore )
1366 /* recall that all strings are owned by Xrm==>no need to free them */
1367 srchData->bestScore = srchData->curScore;
1368 srchData->bestTransType = srchData->curTransType;
1369 memcpy(srchData->bestSpecRefs,srchData->curSpecRefs,
1370 sizeof(srchData->bestSpecRefs)); /* no array assignment in C */
1371 srchData->opValue = value->addr;
1374 return False; /* continue enumeration */
1379 /*========================================================*/
1380 $PFUNBEG$: FindOpToStdMatchCB()
1381 $1LINER$: Matches op value of entry to search pattern; gets std value
1385 /*================================================$SKIP$==*/
1389 Bool FindOpToStdMatchCB(
1390 XrmDatabase * database,
1391 XrmBindingList bindings,
1392 XrmQuarkList quarks,
1393 XrmRepresentation * type,
1395 XPointer client_data)
1397 __DtXlateSrchData * srchData = (__DtXlateSrchData *) client_data;
1399 /* always begin scoring from 0 and subexpression indices at -1 */
1400 srchData->curScore = 0;
1401 memset(srchData->curSubEx,-1, sizeof(srchData->curSubEx));
1404 fprintf(stderr,"FindOpToStdMatch: "); PrintDbEntry(quarks,value);
1407 /* check for a match */
1408 if ( CheckSearchPlatformMatchesSpec(srchData,
1409 quarks[PLATFORM_QUARK]) == False)
1410 return False; /* continue enumeration */
1413 fprintf(stderr,"platform matches\n");
1416 if ( CheckSearchVerMatchesSpec(srchData,
1417 quarks[VERSION_QUARK]) == False)
1418 return False; /* continue enumeration */
1421 fprintf(stderr,"ver matches\n");
1424 if ( CheckSearchOperMatchesSpec(srchData,
1425 quarks[OPERS_QUARK]) == False)
1426 return False; /* continue enumeration */
1429 fprintf(stderr,"oper matches\n");
1432 if ( CheckSearchDirOpToStdMatchesSpec(srchData,
1433 quarks[DIRECTION_QUARK]) == False)
1434 return False; /* continue enumeration */
1437 fprintf(stderr,"kind matches\n");
1440 /* now check for op value match and, if it is
1441 the best match so far, record the std value */
1442 if ( CheckSearchOpValueMatchesSpec(srchData,
1443 value->addr) == False )
1445 if (srchData->db->debugMode)
1447 fprintf(stderr,"mismatch ");
1448 PrintDbEntry(quarks,value);
1451 return False; /* continue enumeration */
1455 fprintf(stderr,"op value matches\n");
1458 if (srchData->db->debugMode)
1460 fprintf(stderr,"match (%d) ",srchData->curScore);
1461 PrintDbEntry(quarks,value);
1464 /* we have a match! (we made it through all match checks) */
1465 /* is it better than or same as any earlier match? */
1466 if ( srchData->curScore >= srchData->bestScore )
1470 /* recall that all strings are owned by Xrm==>no need to free them */
1471 srchData->bestScore = srchData->curScore;
1472 srchData->bestTransType = srchData->curTransType;
1473 memcpy(srchData->bestSubEx,srchData->curSubEx,
1474 sizeof(srchData->bestSubEx)); /* no array assignment in C */
1475 /* store off the std value of the best match */
1476 stdQ = srchData->stdValueQuarks;
1477 curQ = &quarks[FIRSTSTD_QUARK];
1478 while ( (*stdQ = *curQ) != NULLQUARK ) stdQ++, curQ++;
1481 return False; /* continue enumeration */
1486 /*========================================================*/
1487 $PFUNBEG$: DoCommonSrchDataPrep
1488 $1LINER$: Prep srchData to search for a pattern
1492 /*================================================$SKIP$==*/
1495 void DoCommonSrchDataPrep(
1496 __DtXlateSrchData * srchData,
1498 const char * platform,
1500 const char * operation)
1502 int verNum = version; /* for lint */
1504 /* zero the search data */
1505 memset(srchData,0,sizeof(__DtXlateSrchData));
1510 /* build filter list for enumerating the db */
1511 if (verNum < MATCHALL_VER) verNum = MATCHALL_VER;
1512 srchData->platformStr = platform;
1513 srchData->platformQuark = (platform?XrmStringToQuark(platform):NULLQUARK);
1514 srchData->version = verNum;
1515 sprintf(srchData->verStr,"%d",verNum);
1516 srchData->operStr = operation;
1517 srchData->operStrLen = strlen(operation);
1518 srchData->operQuark = (operation ? XrmStringToQuark(operation) : NULLQUARK);
1519 srchData->lessThanQuark = XrmStringToQuark(LESSTHAN_STR);
1520 srchData->equalsToQuark = XrmStringToQuark(EQUALS_STR);
1521 srchData->containsQuark = XrmStringToQuark(CONTAINS_STR);
1522 srchData->moreThanQuark = XrmStringToQuark(MORETHAN_STR);
1523 srchData->inhibitQuark = XrmStringToQuark(INHIBIT_STR);
1526 /*========================================================*/
1527 /*=============== Public Xlate routines ==================*/
1528 /*========================================================*/
1533 /*========================================================*/
1534 $FUNBEG$: _DtXlateOpenDb()
1535 $1LINER$: Open a translation database
1537 Opens a translation resource database and returns a
1538 reference to it in ret_db.
1540 Initializes the _DtXlateDb object to ready for use.
1541 If an error occurs, _DtXlateDb is set to NULL.
1544 0: no error occurred
1545 -1: if ret_db is NULL
1546 if XrmGetFileDatabase() failed on databaseName
1547 if malloc fails to alloc a db structure
1548 /*================================================$SKIP$==*/
1552 const char * databaseName,
1553 _DtXlateDb * ret_db)
1556 __DtXlateDbRec * dbRec = NULL;
1559 if(NULL == ret_db) return -1; /* RETURN */
1562 /* Do NOT check for whether *ret_db is already
1563 a valid db; this is none of our affair. */
1565 /* get an absolute path for the file */
1566 path = ExpandPath(databaseName);
1568 if (NULL == path) return -1; /* RETURN */
1570 xrmDb = XrmGetFileDatabase(path);
1571 if (NULL == xrmDb) { free(path); return -1; } /* RETURN */
1573 /* alloc a db ref */
1574 dbRec = (__DtXlateDbRec *) calloc(1,sizeof(__DtXlateDbRec));
1577 XrmDestroyDatabase(xrmDb);
1579 return -1; /* RETURN */
1582 /* and populate it */
1583 dbRec->xrmDb = xrmDb;
1584 dbRec->initGuard = INIT_OCCURRED;
1586 /* check for debug mode */
1587 SetDebugModeState(dbRec);
1589 if (dbRec->debugMode)
1590 fprintf(stderr,"_DtXlateOpenDb: opened: %s; new db: %p\n",path,dbRec);
1594 return 0; /* RETURN */
1598 /*========================================================*/
1599 $FUNBEG$: _DtXlateOpenAndMergeDbs()
1600 $1LINER$: Opens a translation database and merges with earlier dbs
1602 Opens a translation resource database and returns a
1603 reference to it in ret_db.
1605 Initializes the _DtXlateDb object to ready for use.
1608 0: no error occurred
1609 -1: if io_db is NULL
1610 if XrmGetFileDatabase() failed on databaseName
1611 /*================================================$SKIP$==*/
1614 int _DtXlateOpenAndMergeDbs(
1615 const char * databaseName,
1622 if(NULL == io_db) return -1; /* RETURN */
1624 /* if a db has not yet been opened */
1626 || (*io_db)->initGuard != INIT_OCCURRED
1627 || (*io_db)->xrmDb == NULL)
1629 ret = _DtXlateOpenDb(databaseName,io_db); /* RETURN */
1630 if ( (*io_db) && (*io_db)->debugMode)
1631 fprintf(stderr,"_DtXlateOpenAndMergeDb: "
1632 "used _DtXlateOpenDb to open first file\n");
1633 return ret; /* RETURN */
1636 if ( (*io_db) && (*io_db)->debugMode)
1637 fprintf(stderr,"_DtXlateOpenAndMergeDb: "
1638 "target file: %s; existing db: %p\n",databaseName,*io_db);
1640 /* a db has been opened, let's merge with it */
1642 /* get an absolute path for the file */
1643 path = ExpandPath(databaseName);
1645 if (NULL == path) goto Failed; /* RETURN */
1647 xrmDb = XrmGetFileDatabase(path);
1648 if (NULL == xrmDb) goto Failed; /* RETURN */
1650 /* merge and destroy xrmDb for me */
1651 XrmMergeDatabases(xrmDb,&(*io_db)->xrmDb);
1653 /* check for debug mode */
1654 SetDebugModeState(*io_db);
1656 if ((*io_db)->debugMode)
1657 fprintf(stderr,"_DtXlateOpenAndMergeDb: "
1658 "opened: %s; merged db: %p\n",path,*io_db);
1661 return 0; /* RETURN */
1664 if ( (*io_db) && (*io_db)->debugMode)
1665 fprintf(stderr,"_DtXlateOpenAndMergeDb: open failed; file: %s\n",
1666 (path ? path : (databaseName ? databaseName : "NULL") ) );
1667 if (path) free(path);
1668 return -1; /* RETURN */
1672 /*========================================================*/
1673 $FUNBEG$: _DtXlateMergeDbs()
1674 $1LINER$: Merges two open dbs into one and closes the merged-in db.
1676 Merges two databases into one and closes the merged db.
1678 The io_dbToMerge database must be a valid translation database.
1679 The io_dbToMerge database is merged into the io_mergeIntoDb.
1680 The io_mergeIntoDb may either be invalid or valid. If invalid,
1681 the io_dbToMerge database is simply moved over to io_mergeIntoDb.
1682 If io_mergeIntoDb is valid, the entries in the io_dbToMerge
1683 database are merged into it and take precedence over entries in the
1684 io_mergeIntoDb, and the io_dbToMerge database is closed.
1686 io_dbToMerge: database to merge into io_mergeIntoDb
1687 io_mergeIntoDb: database to hold merged result
1689 0: no error occurred
1690 -1: if io_dbToMerge or io_mergeIntoDb is NULL
1691 if *io_dbToMerge is NULL or uninitialized
1692 /*================================================$SKIP$==*/
1695 int _DtXlateMergeDbs(
1696 _DtXlateDb * io_dbToMerge,
1697 _DtXlateDb * io_mergeIntoDb)
1701 if( NULL == io_mergeIntoDb
1702 || NULL == io_dbToMerge
1703 || NULL == *io_dbToMerge
1704 || (*io_dbToMerge)->initGuard != INIT_OCCURRED
1705 || (*io_dbToMerge)->xrmDb == NULL)
1706 return -1; /* RETURN */
1708 /* check for debug mode */
1709 if ( ((*io_mergeIntoDb) && (*io_mergeIntoDb)->debugMode)
1710 || (*io_dbToMerge)->debugMode)
1711 fprintf(stderr,"_DtXlateMergeDbs: "
1712 "mergeIntoDb: %p; dbToMerge: %p\n",*io_mergeIntoDb,*io_dbToMerge);
1714 /* if db_mergeIntoDb has not yet been opened */
1715 if( NULL == *io_mergeIntoDb
1716 || (*io_mergeIntoDb)->initGuard != INIT_OCCURRED
1717 || (*io_mergeIntoDb)->xrmDb == NULL)
1719 /* just move dbToMerge into mergeIntoDb */
1720 *io_mergeIntoDb = *io_dbToMerge;
1721 DeleteDbMem(io_dbToMerge);
1723 return 0; /* RETURN */
1726 /* merge and destroy io_dbToMerge->xrmDb for me */
1727 XrmMergeDatabases((*io_dbToMerge)->xrmDb,&(*io_mergeIntoDb)->xrmDb);
1728 DeleteDbMem(io_dbToMerge);
1730 /* check for debug mode */
1731 SetDebugModeState(*io_mergeIntoDb);
1733 if ((*io_mergeIntoDb)->debugMode)
1734 fprintf(stderr,"merged db: %p\n",*io_mergeIntoDb);
1740 /*========================================================*/
1741 $FUNBEG$: _DtXlateOpenAllDbs()
1742 $1LINER$: Open and merge all locale translation databases that can be found
1744 DtXlateOpenAllDbs() locates all translation databases
1745 present in the search paths directories.
1747 searchPaths: ':' separated list of directories
1748 databaseName: name of the database file in those directories
1749 ret_db: the reference to the open database is stored here
1751 0: at least one database was opened
1752 -1: no database was opened
1753 /*================================================$SKIP$==*/
1756 int _DtXlateOpenAllDbs(
1757 const char * searchPaths,
1758 const char * databaseName,
1759 _DtXlateDb * ret_db)
1761 const char * workStart = searchPaths;
1762 const char * separator = NULL;
1763 char dbFile[MAXPATHLEN+1];
1764 int ret = ~0; /* all bits set */
1766 /* cycle through the paths, opening each one */
1770 const char * slash = NULL;
1774 /* isolate the next part of the path */
1775 _DtMBStrchr (workStart, PATH_SEPARATOR, -1, &separator);
1776 if (NULL == separator) _DtMBStrchr (workStart, EOS, -1, &separator);
1777 if (NULL == separator) break; /* BREAK */
1778 workLen = separator - workStart; /* dont include +1 for EOS */
1780 /* copy over the path component */
1781 strncpy(dbFile,workStart,workLen);
1782 workStart = separator + 1;
1784 /* add a slash to end of path component, if needed */
1785 *(dbFile+workLen) = EOS; /* add an EOS for _DtMBStrrchr to find */
1786 _DtMBStrrchr(dbFile,DIR_SLASH,-1,&slash);
1787 if (slash != dbFile+workLen-1) /* is slash last char of path? */
1789 *(dbFile+workLen) = DIR_SLASH;
1793 /* append the filename and EOS */
1794 strcpy(dbFile+workLen,databaseName);
1796 /*printf("Working on: %s\n", dbFile); **DBG*/
1798 /* open and merge the database with previously opened dbs */
1799 /* by ANDing, we determine whether at least one call returned 0 */
1800 ret &= _DtXlateOpenAndMergeDbs(dbFile,ret_db);
1802 } while ( *separator != EOS );
1804 if (*ret_db && (*ret_db)->debugMode)
1805 fprintf(stderr,"_DtXlateOpenAllDbs: completed\n"
1806 " srchpaths: %s; db file: %s\n",searchPaths,databaseName);
1808 return (ret == 0 ? 0 : -1); /* ret != 0 ==> no db was opened */
1813 /*========================================================*/
1814 $FUNBEG$: _DtXlateCloseDb()
1815 $1LINER$: Close an open translation database
1817 _DtXlafteCloseDb() releases all memory associated with
1818 the translation database. Further use of the database
1822 0: database was valid and has been closed
1823 -1: invalid database pointer
1824 /*================================================$SKIP$==*/
1827 int _DtXlateCloseDb(
1830 __DtXlateDbRec * dbRec;
1833 || NULL == (dbRec = *io_db) /* dbRec assigned */
1834 || dbRec->initGuard != INIT_OCCURRED)
1835 return -1; /* RETURN */
1837 XrmDestroyDatabase(dbRec->xrmDb);
1839 if (dbRec->debugMode) fprintf(stderr,"_DtXlateCloseDb: %p\n",dbRec);
1841 /* zero out object mem and free it */
1849 /*========================================================*/
1850 $FUNBEG$: _DbXlateStdToOpValue()
1851 $1LINER$: Translates a standardized spec to an operation-specific value
1853 Looks up the best translation of the standard value for an
1854 operation and places a pointer to the translation string
1855 at the location pointed to by ret_opValue.
1857 The translated string was allocated using malloc() and
1858 must be freed when no longer needed.
1860 If ret_opValue is NULL, the function merely verifies that
1861 a valid translation exists.
1863 db: a translation database
1864 platform: the platform string (see _DtXlateGetXlateEnv())
1865 version: the version number (see _DtXlateGetXlateEnv())
1866 operation: the operation of interest, e.g. "setlocale"
1867 stdValue: the standard value pattern
1868 ret_opValue: location where ptr to translated string is stored
1869 ret_reserved: reserved for future use
1871 0: translation found
1872 -1: invalid database (NULL ptr, not opened)
1873 no operation was specified
1874 query failed to find a match
1875 /*================================================$SKIP$==*/
1878 int _DtXlateStdToOpValue(
1880 const char * platform,
1882 const char * operation,
1883 const char * stdValue,
1884 char * * ret_opValue,
1885 void * ret_reserved)
1887 __DtXlateSrchData srchData;
1888 XrmQuark empty = NULLQUARK;
1891 || db->initGuard != INIT_OCCURRED
1892 || NULL == operation
1893 || operation[0] == EOS)
1894 return -1; /* RETURN error */
1896 /* prep srch data for search */
1897 DoCommonSrchDataPrep(&srchData,db,platform,version,operation);
1899 /* handle a rare case */
1900 if (NULL == stdValue)
1902 if (db->debugMode) fprintf(stderr,"_DtXlateStdToOpValue: NULL std value\n");
1903 if (ret_opValue) *ret_opValue = NULL;
1904 return -1; /* RETURN error */
1907 /* build std value list for use during comparison */
1908 srchData.stdValueQuarks[0] = NULLQUARK;
1909 if (NULL != stdValue && stdValue[0] != EOS)
1910 XrmStringToQuarkList(stdValue,srchData.stdValueQuarks);
1913 fprintf(stderr,"_DtXlateStdToOpValue: %s.%d.%s.%s: <op>\n",
1914 platform,version,operation,stdValue);
1916 /* scan through this Db looking for matches and put in search */
1917 XrmEnumerateDatabase(db->xrmDb,&empty,&empty,
1918 XrmEnumAllLevels, FindStdToOpMatchCB, (XPointer) &srchData);
1920 if ( srchData.opValue != NULL
1921 && srchData.bestTransType != __DtXLATE_TYPE_INHIBIT )
1925 if (ret_opValue == NULL)
1927 if (db->debugMode) fprintf(stderr,"translation exists\n");
1928 return 0; /* RETURN: translation exists */
1931 /* alloc the string to return */
1932 opValue = strdup(srchData.opValue);
1934 if (db->debugMode) fprintf(stderr,"raw opval:%s\n",opValue);
1936 /* do quote and escape removal and ref replacement in the opValue */
1937 if ( srchData.bestTransType == __DtXLATE_TYPE_REGEX )
1938 StripMetaAndReplaceEscSubex(&opValue,False,srchData.bestSpecRefs);
1940 StripMetaAndReplaceEscSubex(&opValue,False,NULL);
1942 if (db->debugMode) fprintf(stderr,"op value:%s\n",opValue);
1944 *ret_opValue = opValue;
1945 return 0; /* RETURN: search successful */
1947 return -1; /* RETURN: search failed */
1952 /*========================================================*/
1953 $FUNBEG$: _DbXlateOpToStdValue()
1954 $1LINER$: Translates an operation-specific value to a standardized one
1956 Looks up the best translation of the operation value for an
1957 operation and places a pointer to the standard string
1958 at the location pointed to by ret_stdValue.
1960 The standard string was allocated using malloc() and
1961 must be freed when no longer needed.
1963 If ret_stdValue is NULL, the function merely verifies that
1964 a valid translation exists.
1966 db: a translation database
1967 platform: the platform string (see _DtXlateGetXlateEnv())
1968 version: the version number (see _DtXlateGetXlateEnv())
1969 operation: the operation of interest, e.g. "setlocale"
1970 opValue: the operation-specific value pattern
1971 ret_stdValue: location where ptr to standard string is stored
1972 ret_reserved: reserved for future use
1974 0: translation found
1975 -1: invalid database (NULL ptr, not opened)
1976 no operation was specified
1977 query failed to find a match
1978 /*================================================$SKIP$==*/
1981 int _DtXlateOpToStdValue(
1983 const char * platform,
1985 const char * operation,
1986 const char * opValue,
1987 char * * ret_stdValue,
1988 void * ret_reserved)
1990 __DtXlateSrchData srchData;
1991 XrmQuark empty = NULLQUARK;
1992 char lhs[MAXLHSSIZE];
1995 || db->initGuard != INIT_OCCURRED
1996 || NULL == operation
1997 || operation[0] == EOS)
1998 return -1; /* RETURN error */
2000 /* prep srch data for search */
2001 DoCommonSrchDataPrep(&srchData,db,platform,version,operation);
2003 /* after check on value, store op value for use during comparison */
2004 /* not meaningful to check for a NULL value */
2005 if (NULL == opValue)
2007 if (db->debugMode) fprintf(stderr,"_DtXlateOpToStdValue: NULL op value\n");
2008 if (ret_stdValue) *ret_stdValue = NULL;
2009 return -1; /* RETURN error */
2011 srchData.opValue = opValue;
2014 fprintf(stderr,"_DtXlateOpToStdValue: %s.%d.%s.<std>: %s\n",
2015 platform,version,operation,opValue);
2017 /* scan through this Db looking for matches and put in search */
2018 XrmEnumerateDatabase(db->xrmDb,&empty,&empty,
2019 XrmEnumAllLevels, FindOpToStdMatchCB, (XPointer) &srchData);
2021 if ( srchData.stdValueQuarks[0] != NULLQUARK
2022 && srchData.bestTransType != __DtXLATE_TYPE_INHIBIT )
2025 char * stdValue = lhs;
2026 int stdValueLen = 0;
2028 if (ret_stdValue == NULL)
2030 if (db->debugMode) fprintf(stderr,"translation exists\n");
2031 return 0; /* RETURN: translation exists */
2034 /* make a STDVALUE_SEPARATOR separated string out of the std data */
2035 for ( stdQ = srchData.stdValueQuarks;
2039 const char * str = XrmQuarkToString(*stdQ);
2041 if (NULL == str || str[0] == EOS) continue;
2043 strLen = strlen(str);
2044 if (stdValue != lhs)
2045 {*stdValue++ = STDVALUE_SEPARATOR; stdValueLen++; }
2046 if ((stdValueLen + strLen) > sizeof(lhs) )
2047 strLen = sizeof(lhs)-stdValueLen;
2048 strncpy(stdValue,str,strLen);
2049 stdValueLen += strLen;
2054 if (db->debugMode) fprintf(stderr,"raw stdval:%s\n",lhs);
2056 /* do quote and escape removal and ref replacement in the stdValue */
2057 stdValue = strdup(lhs); /* reset stdValue ptr */
2058 if ( srchData.bestTransType == __DtXLATE_TYPE_REGEX )
2059 ReplaceMatchallSubex(&stdValue,srchData.bestSubEx,srchData.opValue);
2061 if (db->debugMode) fprintf(stderr,"std value:%s\n",stdValue);
2063 *ret_stdValue = stdValue;
2064 return 0; /* RETURN: search successful */
2066 return -1; /* RETURN: search failed */
2072 /*========================================================*/
2073 $FUNBEG$: _DtXlateGetXlateEnv()
2074 $1LINER$: Get the DtXlate compilation and execution environments.
2076 _DtXlateGetXlateEnv() recovers the identity of the application
2077 current platform, the version value of the application
2078 execution environment, and the version value of the operating
2079 system version for which DtXlateGetXlateEnv() was
2080 compiled. These values can be used in formulating queries,
2081 especially for the _DtXlateStdToOpValue() query.
2083 The technique used by this routine is as follows. Using
2084 uname(2), the routine retrieves the sysname, release, and version
2085 strings. The sysname is used as the platform name. The
2086 release and version strings are concatenated in that order
2087 and as treated below as the <op-rel-ver>. An OpToStd translation
2088 looks for a match to
2089 <sysname>.?.version.<.<std-version>: <op-rel-ver>
2091 <sysname>.?.version.=.<std-version>: <op-rel-ver>
2093 If no match is found, the next fallback position is to
2094 get the specification with the same sysname and the highest
2095 std-version integer value. If no specifications exist for
2096 that sysname, then sysname is set to the empty string and
2099 ret_AppExecEnvPlatform should point to a character array at least
2100 _DtPLATFORM_MAX_LEN characters long. The sysname is copied to it.
2102 ret_AppExecEnvVersion is given the integer value of the
2103 std-version recovered from the translation.
2105 ret_XlateCompiledForOSVersion is given the integer value
2106 determined by using the OSMajorVersion and OSMinorVersion
2107 constants defined by the build environment of _DtXlate as follows:
2110 #define STR(V) _STR(V)
2111 sprintf(buf,"%s%s%s", STR(OSMAJORVERSION),
2112 nl_langinfo(RADIXCHAR), STR(OSMAJORVERSION));
2113 verNum = (int) (100.0 * atof(buf));
2116 OSMAJORVERSION & OSMINORVERSION are compile-time constants
2117 that must be defined as part of the build environment.
2118 It is assumed that these constants are of the form:
2121 #define OSMAJORVERSION 5
2122 #define OSMINORVERSION 3
2124 530 = (int) 100.0 * atof("5.3");
2127 #define OSMAJORVERSION 8
2128 #define OSMINORVERSION 09
2130 809 = (int) 100.0 * atof("8.09");
2132 Note that it may be necessary for the application to determine
2133 the version number of an operation in some platform-specific
2134 and operation-specific manner, for example using a library
2135 version value. In many cases, however, the O.S. version value
2136 for which _DtXlate was compiled will be sufficient
2137 when identifying version numbers for standard development
2138 environment libraries, such as libc.
2142 xlateStd2Op(_DtXlateDb db,Boolean runtimeOp, char * operation,char * stdVal)
2144 char platform[_DtPLATFORM_MAX_LEN];
2146 char * opVal = NULL;
2150 ret=_DtXlateGetXlateEnv(db,platform,&version,NULL);
2152 ret=_DtXlateGetXlateEnv(db,platform,NULL,&version);
2154 _DtXlateStdToOpValue(db,platform,version,operation,stdVal,&opVal,NULL);
2155 return opVal; /* will be NULL if error occurred */
2159 ret_AppExecEnvPlatform: pts to a string at least _DtPLATFORM_MAX_LEN long
2160 that will hold the string uname(2) returns for sysname
2161 ret_AppExecEnvVersion: pts to an integer that will receive the platform
2162 standardized version number, as determined by
2163 a translation on uname(2) release+version.
2164 ret_XlateCompiledForOSVersion: pts to an integer that will receive the
2165 operating system version for which _DtXlate was
2166 compiled using OSMajorVersion * 100 + OSMinorVersion
2167 Any of the arguments may be NULL.
2169 0: if no error occurred
2170 -1: if no translation was possible to get the AppExecEnvVersion
2171 /*================================================$SKIP$==*/
2174 int _DtXlateGetXlateEnv(
2176 char * ret_AppExecEnvPlatform,
2177 int * ret_AppExecEnvVersion,
2178 int * ret_XlateCompiledForOSVersion)
2180 struct utsname names;
2182 char * platform = "NULL";
2186 /* get host specifics */
2189 /* first get execution host name */
2190 if (ret_AppExecEnvPlatform)
2192 strncpy(ret_AppExecEnvPlatform,names.sysname,_DtPLATFORM_MAX_LEN-1);
2193 ret_AppExecEnvPlatform[_DtPLATFORM_MAX_LEN-1] = EOS;
2194 platform=ret_AppExecEnvPlatform;
2197 /* then look up version number of execution host */
2198 if (ret_AppExecEnvVersion)
2200 #if defined(sun) || defined(_AIX) || defined(USL) || defined(__uxp__) || defined(__osf__) || defined(linux)
2201 char version[SYS_NMLN+SYS_NMLN+2];
2203 char version[UTSLEN+UTSLEN+2];
2205 char * stdVer = NULL;
2206 int verNum = MATCHALL_VER;
2208 /* cat release version and do a translation on it to a std value */
2209 /* then convert the std value to a integer */
2210 strcpy(version,names.release);
2211 strcat(version,names.version);
2212 ret = _DtXlateOpToStdValue(db,names.sysname,NULL,
2213 _DtXLATE_OPER_VERSION,version,&stdVer,NULL);
2216 if (sscanf(stdVer,"%d",&verNum) != 1) verNum = MATCHALL_VER;;
2219 *ret_AppExecEnvVersion = verNum;
2223 /* then look up version number of execution host */
2224 if (ret_XlateCompiledForOSVersion)
2226 char buf[MAXINTSTRSIZE];
2229 #define STR(V) _STR(V)
2231 /*===========================
2232 OSMAJORVERSION & OSMINORVERSION are compile-time constants
2233 that must be defined as part of the build environment.
2234 It is assumed that these constants are of the form:
2237 #define OSMAJORVERSION 5
2238 #define OSMINORVERSION 3
2240 530 = (int) (100.0 * atof("5.3"));
2243 #define OSMAJORVERSION 8
2244 #define OSMINORVERSION 09
2246 809 = (int) (100.0 * atof("8.09"));
2247 ===========================*/
2249 #if !defined(OSMAJORVERSION) || !defined(OSMINORVERSION) || OSMAJORVERSION == 0
2250 #error OSMAJORVERSION and/or OSMINORVERSION not defined
2253 sprintf(buf,"%s%s%s", STR(OSMAJORVERSION),
2254 nl_langinfo(RADIXCHAR), STR(OSMINORVERSION));
2256 *ret_XlateCompiledForOSVersion = (int) (100.0 * atof(buf));
2257 compver = *ret_XlateCompiledForOSVersion;
2261 fprintf(stderr,"_DtXlateGetXlateEnv: "
2262 "Platform: %s; Execution Ver: %d; Compiled Ver: %d\n",
2263 platform,execver,compver);
2269 /*========================================================*/
2270 /*================ Introductory Info =====================*/
2271 /*========================================================*/
2274 /*========================================================*/
2275 $INTROBEG$: _DtXlate family
2276 $1LINER$: API to translate any value to a standard value and back again
2278 _DtXlate is a collection of routines that allow translation
2279 between platform, version, and operation specific values
2280 into standard values and back again. Translation is
2281 based on the contents of database files specified using
2282 Xrm-style resources. The semantics of the translation
2283 are a combination of standard semantics for specifying
2284 platform, version, operation, and translation type, and
2285 caller-specific semantics for the standard value format
2286 and operation values.
2288 The API contains routines to process translation databases
2291 _DtXlateOpenDb() opens a particular translation database
2292 _DtXlateOpenAndMergeDb() opens a particular database and
2293 merges it with an already opened one, overriding any
2294 repeated specifications.
2295 _DtXlateOpenAllDbs() opens all occurances of a translation
2296 database found in a search path and cumulatively merges
2297 the contents, allowing for the override of existing
2298 specifications as well as the addition of new ones.
2299 _DtXlateCloseDb() closes an open database
2300 _DtXlateOpToStdValue() translates an platform, version,
2301 and operation specific value into a standard value.
2302 _DtXlateStdToOpValue() translates a standard value into
2303 a platform, version, and operation specific value.
2304 /*=$END$================================================*/
2308 /*========================================================*/
2309 $INTROBEG$: Design and Implementation Considerations
2310 $1LINER$: Factors influencing design and implementation
2312 The syntax of the translation specification table is designed
2313 to be compatible with Xrm resource specifications. This
2314 allows Xrm to be used to load, parse, and merge the databases
2315 for processing. This also causes the specifications to be
2316 case-sensitive, as case is preserved by Xrm and is used when
2319 However, due to the semantics of translation specifications
2320 and limitations of Xrm, XrmGetResource() queries generally
2321 will not be useful. Rather, a pattern matching API is provided
2322 that implements the query capability used for the translations.
2323 The initial implementation will use XrmEnumerateDatabase().
2325 Using Xrm leads to an in-memory approach to translation, meaning
2326 that all the resources files are parsed and loaded into memory
2327 as the first step of a translation. A line-at-a-time approach,
2328 that process one line at a time directly from the file in a
2329 grep- or awk-like manner, is likely more memory-efficient.
2331 Note that the line-at-a-time approach does not avoid parsing
2332 all the specification files, as the API supports inheritence
2333 and override of specifications. Hence, to ensure the correct
2334 value, the entire file set must be processed. Note also that
2335 in a situation where translations will be repeatedly performed,
2336 the Xrm in-memory approach may be more time-efficient, as the
2337 files need only be parsed once, and then are utilized repeatedly.
2339 Because of time constraints, a line-at-a-time approach will not
2340 be used for the first implementation, as Xrm provides all the
2341 necessary parsing, filtering, and symbol hashing routines
2342 for free. Given the likely large size of the tables and their
2343 infrequent use, a line-at-a-time approach is likely the better
2346 /*=$END$================================================*/
2351 /*========================================================*/
2352 $INTROBEG$: translation BNF syntax and semantics
2353 $1LINER$: _DtXlate translation specification syntax and semantics
2355 BNF Syntax of Translation Specification
2356 =======================================
2358 <specfile> ::= (<xlatespec> | <comment> | <cr>)*
2359 <xlatespec> ::= <platform>.<version>.<operations>.<transtype>
2360 .<stdvalue>:<opvalue> (<comment>|<cr>)
2361 <platform> ::= <identifier> | <matchall>
2362 <version> ::= <number> [+ | (- <number>)] | <matchall>
2363 <operations> ::= <identifier> [',' <identifier>]* | <matchall>
2364 <transtype> ::= '<' | '=' | '~' | '>' | '0'
2365 <stdvalue> ::= <identifier> [.<identifier>]*
2366 <langterr> ::= <identifier> | <matchall>
2367 <codeset> ::= <identifier> | <matchall>
2368 <modifier> ::= <identifier> | <matchall>
2369 <opvalue> ::= (<vischars>|<metachar>)+ | '"'(<anychar>|<metachar>)+'"'
2371 <matchall> ::= '?'[<number>]
2373 <comment> ::= '!' [^<cr>]* <cr>
2375 <identifier> ::= [-_a-ZA-Z0-9]
2376 <vischar> ::= any non-whitespace character; meta and regular
2377 expression chars must be escaped with "\\"
2378 <anychar> ::= any printable character; meta and regular
2379 expression chars must be escaped with "\\"
2380 <metachar> ::= '!' | '"' | <backslash> | <valex> | <regex>
2381 <valex> ::= <backslash><number>
2382 <regex> ::= see regexp(5)
2383 <backslash> ::= the backslash character (\).
2385 Semantics of the Translation Specification
2386 ==========================================
2388 <specfile> : a file containing zero or more translation specifications
2391 <xlatespec> : a translation specification defines a fully qualified
2392 string value which may be recovered by query pattern matching the
2393 specification. The qualifiers identify the semantics of the usage
2394 of the value, allowing queries to be meaningful. The entire xlatespec
2395 must be on one line of the file.
2397 <platform> : a CDE-standardized identifier for an operating system
2398 platform. The platform need not be supported by CDE, but CDE must
2399 have standardized an identifier for the platform in order for it to
2400 be used. For example, candidate platform identifiers are "HP-UX",
2401 "AIX", "SunOS", "Solaris", "SCO", etc. These identifiers are the
2402 values returned by uname(2):utsname.sysname and uname(1) -s, and
2403 I propose CDE standardize on using these values.
2405 The identifier string and matching constant value must be added to
2406 the source code of the translation routine in order for it to be
2407 recognized. This allows control over the platform registry
2408 and enables automatic generation of the platform on the execution
2409 host through the use of #ifdef <PLATFORM_CONST> in the source code.
2411 <version> : a platform-specific numeric value or range of numberic
2412 values that allows the value to be qualified to a particular version
2413 and release (version + release = version) or range of versions and
2414 releases of the platform. The version numbers must be integral and
2415 suitable for numeric comparison. The '+' can be used to specify an
2416 open upwards bound, as in 900+. The '- <number>' can be used to
2417 specify an upper bound, as in 900-999. If no range is specified,
2418 the version number must match exactly to the query pattern and/or
2419 execution environment.
2421 Platforms may not directly provide version numbers in a numeric
2422 format suitable for use when comparing with a translation
2423 specification. As part of the translation API source code,
2424 conversion routines must be supplied that translate the platform-
2425 specific values, such as those provided by uname(2), into a
2426 translation specification-compliant format suitable for comparison
2427 to <version>. Understanding the conversion routines operation
2428 will be necessary to ensure correct translation specifications.
2430 <operations> : a CDE-standardized identifier for the operation(s) to
2431 which the value applies. The operation(s) need not be supported by every
2432 platform, but CDE must have standardized an identifier for the operation
2433 in order for it to be used. More than one identifer may be included by
2434 concatenating them using the ',' separator, eg. "iconv1,iconv3".
2436 <transtype> : The <transtype> field records the direction of
2437 translation that the specification supports: '<', '=', '~', '>', '0'.
2438 Use '<' if the <opvalue> contains a regular expression; the
2439 specification may only be used to match an operation value in
2440 a _DtLcxXlateOpToStd() translation. Use '>' if the <opvalue>
2441 contains value replacement expressions using values from
2442 the <stdvalue> strings; the specification may only be used by a
2443 _DtLcxXlateStdToOp() translation. Use '=' if the <opvalue>
2444 is a pure string that may be used for either OpToStd() or
2445 StdToOp() translations, and the specification op-value must exactly
2446 match the op-value of the translation request. use '~' if the
2447 <opvalue> is a pure string that may be used for either OpToStd() or
2448 StdToOp() translations, and the specifation op-value must be
2449 a string within the op-value of the translation request.
2450 Use the '0' translation to represent that this particular
2451 translation should result in an error, that is should not result
2454 Translations are two-way operations: from a host- and
2455 operation-specific value to standardized value, and back again.
2456 In many cases, a straight string value for string value translation
2459 But often, more sophisticated pattern matching and value generation
2460 mechanisms are useful to keep the table size small and as general
2461 as possible. In these cases, wildcard and regular expression
2462 operators are useful. Unfortunately, these specifications are not
2463 bi-direction. That is, the pattern matching string can be used
2464 to match against a pattern, but not to generate a result string.
2465 For example, the vi expression s/he*lo/hello/ matches "hello"
2466 as well as "hey look out below", but the reverse direction of
2467 "hello"->"he*lo" will not work.
2469 <stdvalue> : a sequence of one or more '.'-separated CDE-standardizd
2470 identifiers or matchall characters. This represents the canonical
2471 string used as a standard representation of a semantic value that
2472 may vary in different situations.
2474 <opvalue> : a string that has different uses depending on the
2475 value of <transtype>. If transtype is '<', the string is used
2476 as a regular expression to match the opValue in _DtLcxXlateOpToStd()
2477 requests. If the transtype is '>', the string is used as a
2478 replacement expression to generate a opValue in _DtLcxXlateStdToOp().
2479 If transtype is '=' or '~', the string is used as a straight string to
2480 both match for the OpToStd translation and as a value for
2481 the StdToOp translation.
2483 If the opvalue contains whitespace, the opvalue must be enclosed in
2484 double quote characters. If the opvalue contains any meta characters
2485 that should not be treated as meta characters, they must be escaped by
2486 two preceding backslashs.Lack of an opvalue is not an error, but will
2487 be ignored during matches and return an empty string in a StdToOp
2488 translation; to specify that a given translation does not exist, the
2489 '0' translation type should be used or the specification should not
2492 <comment> : a comment begins on an empty line with an unescaped !
2493 and continues to the end of the line.
2495 <matchall> : The matchall character is a universal quantifier, meaning
2496 that it symbolizes all possible values of the field where it is used.
2497 The matchall character may occur only in the qualifers side of
2498 a translation specification. Traditionally, the matchall character
2499 has been '*', but because of the semantics of Xrm, if the '*' is used
2500 as the matchall, Xrm does not restrict enumeration as needed.
2502 The matchall character may be followed by a number when the <transtype>
2503 is '>'. When this occurs, the string that matches the matchall
2504 character may be referenced in the <opvalue> by using the sequence
2505 \<number>, as in "\1". The occurance is replaced with the matched
2507 /*=$END$================================================*/
2511 /*========================================================*/
2512 $INTROBEG$: translation specification examples
2513 $1LINER$: examples of _DtXlate translation specifications
2516 !! These are examples of bi-directional straight translations
2517 HP-UX.900-999.setlocale.=.en_US.hp-roman8: american
2518 HP-UX.900-999.setlocale.=.en_US.iso88591: american.iso88591
2519 HP-UX.900-999.setlocale.=.nl_BE.hp-roman8.fold: dutch@fold
2520 HP-UX.900-999.setlocale.=.nl_BE.hp-roman8.nofold: dutch@nofold
2522 !! These are examples of OpToStd translations utilizing regular
2523 !! expression patterns to match the search value.
2524 HP-UX.?.version.<.900: "A\\.09\\..*" !! any HPUX 9.x version
2525 HP-UX.?.version.<.807: "A\\.08\\.07.*"
2526 HP-UX.?.version.<.800: "A\\.08\\..*"
2527 AIX.?.version.<.320: "2 3"
2528 AIX.?.version.<.300: "[0-9] 3"
2529 SunOS.?.version.<.530: "5\\.3.*"
2530 SunOS.?.version.<.500: "5\\..*"
2532 !! These are examples of StdToOp translations utilizing matchall
2533 !! specifiers in the std value to match the search value.
2534 HP-UX.900+.iconv1.>.?.iso88596: arabic8
2535 HP-UX.900+.iconv1.>.?.iso88597: greek8
2536 HP-UX.900+.iconv1.>.?.hp-kana8: kana8
2537 HP-UX.900+.iconv1.>.?.hp-roman8: roman8
2539 !! The following examples use value replacement as part of their
2540 !! specifications. Using this can lead to much sparser tables, but
2541 !! it depends on op-specific and std values sharing the same strings.
2542 HP-UX.900-999.setlocale.<.nl_BE.hp-roman8.?1: [dD][uU][tT][cC][hH]@\\(.*\\)
2543 !HP-UX.900-999.setlocale.<.nl_BE.hp-roman8.?1: dutch@\\(.*\\)
2544 HP-UX.1000+.setlocale.>.?1.hp-roman8: \\1.roman8 !! all non-modif cases
2545 HP-UX.1000+.setlocale.>.?1.hp-roman8.?2: \\1.roman8@\\2 !! all modif cases
2547 /*=$END$================================================*/
2552 /*========================================================*/
2553 $INTROBEG$: _DtXlate example usage
2554 $1LINER$: Examples of how to _DtXlate
2556 #include <XlationSvc.h>
2559 _DtXlateDb db = NULL;
2561 char plat[_DtPLATFORM_MAX_LEN];
2567 #define OPER_YOUROP "myop"
2569 env = getenv("MYPATH");
2570 if (env == NULL) env = ∅
2572 ret = _DtXlateOpenAllDbs(env,"myfile.xlt",&db);
2574 ret = _DtXlateGetXlateEnv(db,plat,&execver,&compver);
2575 printf("Platform: %s\nExec Ver: %d\nComp Ver: %d\n",
2576 plat,execver,compver);
2578 ret = _DtXlateStdToOpValue(db,plat,compver,OPER_YOUROP,
2579 str="en_US.hp-roman8",&val,NULL);
2580 if (ret==0) printf("setlocale(%s) xlation=%s\n", str, val);
2581 else printf("no xlation\n", val);
2583 ret = _DtXlateOpToStdValue(db,plat,execver,OPER_YOUROP,
2584 str="american",&val,NULL);
2585 if (ret==0) printf("setlocale(%s) xlation=%s\n", str, val);
2586 else printf("no xlation\n", val);
2588 ret = _DtXlateCloseDb(&db);
2590 /*=$END$================================================*/