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 libraries 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 ************************************<+>*************************************/
44 #include <sys/utsname.h>
46 #include <limits.h> /* INT_MAX */
47 #include <pwd.h> /* for getpw... */
48 #include <sys/utsname.h> /* for uname */
49 #include <sys/param.h> /* MAXPATHLEN */
51 /* for RADIXCHAR and nl_langinfo */
53 # define RADIXCHAR MON_DECIMAL_POINT
58 #include <regexpr.h> /* for compile,advance */
60 #include <regex.h> /* for regcomp,regexec */
64 #include <X11/Intrinsic.h>
65 #include <X11/Xresource.h>
67 /*=================================================================
68 $SHAREDBEG$: This header appears in all appropriate DtXlate topics
69 =======================================================$SKIP$======*/
71 #include "XlationSvc.h"
72 #include "LocaleXlate.h"
75 /**** For extensive Introductory info, go to the end of this file ****/
77 /*========================================================*/
78 /*====================== Constants =======================*/
79 /*========================================================*/
81 /*=============== private =================*/
82 /*#define DBG_MATCHING ** if defined, debugging matching stages are compiled */
84 #define DEBUG_XLATE_NAME "dtXlate.debugDtXlate"
85 #define DEBUG_XLATE_CLASS "DtXlate.DebugDtXlate"
89 /* A "random" number used to ensure that the Db has been initalized */
90 #define INIT_OCCURRED 2329479
91 #define PATH_SEPARATOR ':'
94 #define LESSTHAN_STR "<"
95 #define EQUALS_STR "="
96 #define CONTAINS_STR "~"
97 #define MORETHAN_STR ">"
98 #define INHIBIT_STR "0"
100 #define MATCHALL_CHAR '?'
101 #define ESCAPE_CHAR '\\'
102 #define COMMENT_CHAR '!'
103 #define QUOTE_CHAR '\"'
104 #define OPER_SEPARATOR ','
105 #define STDVALUE_SEPARATOR '.'
106 #define MATCHALL_VER 0
108 #define PLATFORM_QUARK 0 /* index offsets into quarklist */
109 #define VERSION_QUARK 1
110 #define OPERS_QUARK 2
111 #define DIRECTION_QUARK 3
112 #define FIRSTSTD_QUARK 4
114 #define MAXSPECQUARKS 43 /* std + platform + version + operation */
115 #define MAXSTDQUARKS 40
116 #define MAXRHSSIZE 100 /* max supported RHS size */
117 #define MAXLHSSIZE 200 /* max supported LHS size */
118 #define MAXINTSTRSIZE 15 /* handle any long int -> string */
121 __DtXLATE_TYPE_NONE = 0,
122 __DtXLATE_TYPE_INHIBIT = 1,
123 __DtXLATE_TYPE_REGEX = 2,
124 __DtXLATE_TYPE_PURE = 3,
125 __DtXLATE_TYPE_CONTAINS = 4
129 /* Sun doesn't support regcomp() and regexec() yet, so
130 define this here and fill it will the results of advance() */
131 typedef struct regmatch_t {
132 int rm_so; /* start offset */
133 int rm_eo; /* end offset */
137 /*========================================================*/
138 /*====================== Typedefs ========================*/
139 /*========================================================*/
142 /*========================================================*/
143 $PTYPEBEG$: __DtXlateDbRec
144 $1LINER$: A private object used to represent translation dbs
146 __DtXlateDbRec is the type of the contents of a translation database
147 object. The database object must be opened before use and closed
148 after use. The definition of the object is opaque to users.
150 xrmDb: Xrm database used to hold specs
151 initGuard: used to test whether Db initialized
152 /*================================================$SKIP$==*/
156 typedef struct __DtXlateDbRec
165 /*========================================================*/
166 $PTYPEBEG$: __DtXlateSrchData
167 $1LINER$: A private object used to collect search-related data
169 __DtXlateSrchData stores all the data pertaining to a search
170 and the search results. The search routines utilize this
171 to maintain status info over multiple calls by the
172 enumeration routines and to return info to the routine
173 that initiated the search.
176 filterQuarks: quark list for the platform, version, and op filter
177 stdValueQuarks: quark list for the std value
178 opValue: ptr to operation-specific value string
179 SpecRef: indices 1 to MAXSPECQUARKS point to matching Xrm strings
180 SubEx: indices 1 to MAXSPECQUARKS index sub exprs in opValue
181 /*================================================$SKIP$==*/
184 typedef struct __DtXlateSrchData
190 const char * platformStr;
191 XrmQuark platformQuark;
193 char verStr[MAXINTSTRSIZE]; /* handle any long int */
194 const char * operStr;
197 XrmQuark lessThanQuark;
198 XrmQuark equalsToQuark;
199 XrmQuark containsQuark;
200 XrmQuark moreThanQuark;
201 XrmQuark inhibitQuark;
203 /* query or search info */
204 XrmQuark stdValueQuarks[MAXSTDQUARKS];
205 const char * opValue;
208 __DtXlateType curTransType;
209 __DtXlateType bestTransType;
212 /* MAXSPECQUARKS is depended upon elsewhere to be the size of these */
213 const char * curSpecRefs[MAXSPECQUARKS];
214 const char * bestSpecRefs[MAXSPECQUARKS];
215 regmatch_t curSubEx[MAXSPECQUARKS]; /* pattern match data */
216 regmatch_t bestSubEx[MAXSPECQUARKS]; /* pattern match data */
220 /*========================================================*/
221 /*================== Private routines ====================*/
222 /*========================================================*/
225 /*========================================================*/
226 $PFUNBEG$: ExpandPath()
227 $1LINER$: adds current working directory to front of path if its relative
229 If path is absolute, returns a malloced copy.
230 If path is relative, inserts the CWD in front of the relative path
231 and returns a mallocedd memory.
233 The caller must free the memory when no longer needed.
235 filespec: the pathname
237 ptr to mallocedd memory or NULL
238 /*================================================$SKIP$==*/
242 const char * filespec)
244 char tmpPath[MAXPATHLEN + 2];
247 const char * slash = NULL;
250 if (NULL == filespec) return NULL;
252 /*** is the file absolute ***/
253 /* if filespec begins with / then it is absolute */
254 if ( ( MB_CUR_MAX == 1
255 || mblen(filespec, MB_CUR_MAX) == 1)/* 1st char is 1 byte */
256 && *filespec == DIR_SLASH) /* and its a / */
258 return strdup(filespec); /* RETURN */
261 /*** otherwise, make it relative to the current directory ***/
263 /* get user's current working directory */
264 if (getcwd(tmpPath, MAXPATHLEN) == 0) return NULL; /* RETURN: error */
266 /*** add a slash to end of path component, if needed ***/
267 /* get end of the string */
268 eos = tmpPath + strlen(tmpPath);
270 _DtMBStrrchr(tmpPath,DIR_SLASH,-1,&slash);
271 if (slash != (eos-1)) /* is slash last char of path? */
277 /* make a malloc'd copy of the path with room to grow */
278 pathName = malloc(sizeof(char) *
279 (strlen(filespec) + (eos-tmpPath) + 5) ); /* 5: arbitrary */
280 if (NULL == pathName) return NULL; /* RETURN: error */
282 /* build the absolute path */
283 strcpy(pathName,tmpPath);
284 strcat(pathName,filespec);
286 return pathName; /* RETURN: found */
290 /*========================================================*/
291 $PFUNBEG$: DeleteDbMem()
292 $1LINER$: Zeros out the db mem & frees it
294 Zeros out the db mem & frees it
295 The xrmDb should have already been destroyed before calling
300 /*================================================$SKIP$==*/
307 /* zero out object mem and free it */
308 (*io_db)->xrmDb = NULL;
309 (*io_db)->initGuard = 0;
315 /*========================================================*/
316 $IFUNBEG$: _DtMBStrchr()
317 $1LINER$: Searches for a character in a multibyte string
319 Returns in 'ret_ptr' the address of the first occurence of 'value'
320 in string s1. Value may also be the end of string marker '\0'.
323 -1 If found an invalid character.
324 0 If found value in string s2
325 1 If found the null byte character without finding 'value'.
326 'ret_ptr' will also be null in this case.
327 /*================================================$SKIP$==*/
334 const char * * ret_ptr )
342 if (!s1 || *s1 == '\0')
347 *ret_ptr = strchr (s1, value);
356 len = mblen (p1, max_len);
370 if (mbstowcs (&wcs, p1, 1) == value)
379 /* check for match on EOS */
380 if (*p1 == value) *ret_ptr = p1;
382 return ((*ret_ptr) ? 0 : 1);
387 /*========================================================*/
388 $IFUNBEG$: _DtMBStrrchr()
389 $1LINER$: Searches for a character in a multibyte string
391 Returns in 'ret_ptr' the address of the last occurence of 'value'
392 in string s1. Value may also be the end of string marker '\0'.
395 -1 If found an invalid character.
396 0 If found value in string s2
397 1 If found the null byte character without finding 'value'.
398 'ret_ptr' will also be null in this case.
399 /*================================================$SKIP$==*/
406 const char * * ret_ptr )
414 if (!s1 || *s1 == '\0')
419 *ret_ptr = strrchr (s1, value);
428 len = mblen (p1, max_len);
433 if (*p1 == value) *ret_ptr = p1;
438 if (mbstowcs (&wcs, p1, 1) == value) *ret_ptr = p1;
443 /* check for match on EOS */
444 if (*p1 == value) *ret_ptr = p1;
446 return ((*ret_ptr) ? 0 : 1);
451 /*========================================================*/
452 $PFUNBEG$: SetDebugModeState()
453 $1LINER$: Checks db for debug mode and sets flag
458 /*================================================$SKIP$==*/
462 void SetDebugModeState(
467 if (XrmGetResource(dbRec->xrmDb,
468 DEBUG_XLATE_NAME,DEBUG_XLATE_CLASS,&str_type,&value) == True)
469 dbRec->debugMode = True;
474 /*========================================================*/
475 $PFUNBEG$: ReplaceMatchallSubex()
476 $1LINER$: Replace matchall subexpression refs (e.g. ?1) with values
478 If subexpressions are specified and referenced, the
479 routine assumes that the string pointed to by pStr was
480 allocated using malloc() and can be resized using realloc().
481 The value and size of pStr may be different after the call.
483 This routine assumes it is working on a stdvalue expression
484 (e.g. from the LHS of a spec), that uses only stdvalue strings
485 or matchall-style subexpression replacement specs, e.g. ?1.
488 /*================================================$SKIP$==*/
492 void ReplaceMatchallSubex(
495 const char * matchedStr)
500 /* strip escapes out */
501 for ( *nxt = *old; /* xfer but don't advance */
503 *nxt = *old ) /* xfer but don't advance */
505 if ( *old == MATCHALL_CHAR ) /* if an escaped char follows */
507 /* if MATCHALL_CHAR is not followed by a digit, e.g. \1
508 or no replacement values exist, ignore it */
510 || isdigit(*(old+1)) == 0 )
512 old++; /* go past the escape char */
513 *nxt++ = *old++; /* keep just the char that was escaped
514 and assign here to avoid tranlating
515 that character, then move on to the
517 continue; /* CONTINUE */
519 else /* a value reference is being made */
520 { /* get the refNum and advance the ptr */
524 sscanf(++old,"%d%n", &refNum, &numLen);
525 old += numLen; /* move old ptr past the ref number */
527 /* printf("%d=%s\n", refNum, &matchedStr[subex[refNum].rm_so]); ** DBG */
529 /* test for valid replacement */
531 && refNum < MAXSPECQUARKS
532 && subex[refNum].rm_so != -1)
539 newOff = nxt - *pStr;
540 oldOff = old - *pStr;
541 repLen = subex[refNum].rm_eo - subex[refNum].rm_so;
542 strLen = strlen(*pStr);
544 /* expand memory and reset pointers */
545 *pStr = realloc(*pStr,strLen+repLen+1);
546 if (NULL == *pStr) return; /* RETURN */
547 nxt = *pStr + newOff;
548 old = *pStr + oldOff;
550 /* move rest back to leave room for the replacement value */
551 oldTmp = *pStr+strLen; /* pts to old EOS */
552 newTmp = *pStr+strLen-(oldOff-newOff)+repLen;/*pts to new EOS*/
553 while (oldTmp >= old) *newTmp-- = *oldTmp--;
555 /* replace the ref with a value but don't append EOS */
556 strncpy(nxt,&matchedStr[subex[refNum].rm_so],repLen);
557 nxt += repLen; /* move new to end of replace string */
558 old += repLen - (oldOff-newOff);
559 /* move old to end of expanded old string */
560 } /* if valid replacement */
561 } /* if a replacement requested */
562 continue; /* CONTINUE */
563 } /* if an escaped character */
564 /* if survived all the checks, can advance to next char */
572 /*========================================================*/
573 $PFUNBEG$: StripMetaAndReplaceEscSubex()
574 $1LINER$: Strips off meta chars and replaces escaped subex (e.g. \1) values
576 Strip is performed in place if replaceValues is NULL.
578 If replaceValues are specified and referenced, the
579 routine assumes that the string pointed to by pStr was
580 allocated using malloc() and can be resized using realloc().
581 The value and size of pStr may be different after the call.
584 This routine assumes it is working on a value expression
585 (e.g. from the RHS of a spec), that uses meta chars and
586 regex(5)-style subexpression replacement specs.
589 /*================================================$SKIP$==*/
593 void StripMetaAndReplaceEscSubex(
595 const Boolean keepEscChar,
596 const char * * replaceValues)
600 Boolean inQuote = False;
602 /* strip escapes out */
603 for ( *nxt = *old; /* xfer but don't advance */
605 *nxt = *old ) /* xfer but don't advance */
607 if ( *old == ESCAPE_CHAR ) /* if an escaped char follows */
609 /* if ESCAPE_CHAR is not followed by a digit, e.g. \1
610 or no replacement values exist, ignore it */
611 if ( NULL == replaceValues
613 || isdigit(*(old+1)) == 0 )
615 if (!keepEscChar) old++; /* go past the escape char */
616 else *nxt++ = *old++; /* copy esc char over */
617 *nxt++ = *old++; /* keep just the char that was escaped
618 and assign here to avoid tranlating
619 that character, then move on to the
621 continue; /* CONTINUE */
623 else /* a value reference is being made */
624 { /* get the refNum and advance the ptr */
628 sscanf(++old,"%d%n", &refNum, &numLen);
629 old += numLen; /* move old ptr past the ref number */
631 /* printf("%x=%s\n", replaceValues[refNum], replaceValues[refNum]); ** DBG */
633 /* test for valid replacement */
635 && refNum < MAXSPECQUARKS
636 && replaceValues[refNum] != NULL)
643 newOff = nxt - *pStr;
644 oldOff = old - *pStr;
645 repLen = strlen(replaceValues[refNum]);
646 strLen = strlen(*pStr);
647 /* expand memory and reset pointers */
648 *pStr = realloc(*pStr,strlen(*pStr)+repLen+1);
649 if (NULL == *pStr) return; /* RETURN */
650 nxt = *pStr + newOff;
651 old = *pStr + oldOff;
653 /* move rest back to leave room for the replacement value */
654 oldTmp = *pStr+strLen; /* pts to old EOS */
655 newTmp = *pStr+strLen-(oldOff-newOff)+repLen;/*pts to new EOS*/
656 while (oldTmp >= old) *newTmp-- = *oldTmp--;
658 /* replace the ref with a value but don't append EOS */
659 strncpy(nxt,replaceValues[refNum],repLen);
660 nxt += repLen; /* move new to end of replace string */
661 old += repLen - (oldOff-newOff);
662 /* move old to end of expanded old string */
663 } /* if valid replacement */
664 } /* if a replacement requested */
665 continue; /* CONTINUE */
666 } /* if an escaped character */
668 { /* a non-escaped char; make further checks */
669 if ( *old == COMMENT_CHAR )
671 *old = EOS; /* end the string */
672 continue; /* CONTINUE */
674 else if ( *old == QUOTE_CHAR )
676 if ( !inQuote) inQuote = True; /* start quote */
677 else inQuote = False; /* end quote */
678 old++; /* go to next char */
679 continue; /* CONTINUE */
681 else if ( !inQuote && isspace(*old) )
683 old++; /* skip the space */
684 continue; /* CONTINUE */
686 } /* else non-escaped char */
688 /* if survived all the checks, can advance to next char */
694 /*========================================================*/
695 /*============== Private Xlate routines ==================*/
696 /*========================================================*/
700 /*========================================================*/
701 $PFUNBEG$: PrintDbEntry()
702 $1LINER$: Prints a db entry to stdout
705 quarks: NULLQUARK-terminated list of quarks for the LHS of the entry
706 value: value of the RHS of the entry
708 /*================================================$SKIP$==*/
718 /* print the entry */
720 while ( quark != NULLQUARK )
722 str = XrmQuarkToString(quark);
723 fprintf(stderr,"%s", str);
725 if (quark != NULLQUARK) fprintf(stderr,".");
727 fprintf(stderr,":%s\n",value->addr);
732 /*========================================================*/
733 $PFUNBEG$: strCaseiCmp
734 $1LINER$: case insensitive string comparison
736 Rolled my own because strcasecmp() not available on
742 /*================================================$SKIP$==*/
750 /* if ( !str1 || !str2 ) return False; *//* unneeded performance hit */
751 while ( *str1 && *str2 )
752 if ( tolower(*str1++) != tolower(*str2++) ) return False;
753 return (*str1 == *str2);
757 /*========================================================*/
758 $PFUNBEG$: CheckForMatchall()
759 $1LINER$: Matches search pattern to spec data
763 /*================================================$SKIP$==*/
767 Boolean CheckForMatchall(
768 __DtXlateSrchData * srchData,
769 const char * matchallString,
770 const char * matchingString)
775 /* test for a match all */
776 if (! ( matchallString[0] == MATCHALL_CHAR
777 && ( matchallString[1] == EOS
778 || sscanf(matchallString+1,"%d", &refNum) == 1) ) )
779 return False; /* RETURN: syntax error or non-matchall */
781 /* matchall occurred; save the matching string if valid ref num */
784 && refNum < XtNumber(srchData->curSpecRefs) )
786 /* Don't store the string if it is just a matchall */
787 /* This allows a replacement ref to be deleted on a match
788 for which there is no replacement value. */
790 if ( matchingString[0] == MATCHALL_CHAR
791 && matchingString[1] == EOS )
793 srchData->curSpecRefs[refNum] = NULL;
794 /* don't add to score for a matchall with no replacement value */
798 /* recall: string not owned by curSpecRefs */
799 srchData->curSpecRefs[refNum] = matchingString;
803 else /* not a value reference; just determine if a plain match */
805 if ( matchingString[0] == MATCHALL_CHAR
806 && matchingString[1] == EOS )
807 score = 1; /* a plain matchall matches a plain matchall */
810 /* if a perfect matchall match, bump the score */
811 srchData->curScore += score;
813 return True; /* RETURN: matchall */
818 /*========================================================*/
819 $PFUNBEG$: CheckSearchPlatformMatchesSpec()
820 $1LINER$: Matches search pattern to spec data
824 /*================================================$SKIP$==*/
828 Boolean CheckSearchPlatformMatchesSpec(
829 __DtXlateSrchData * srchData,
830 XrmQuark specPlatformQuark)
832 /* CheckForMatchall stores away the matching string if of form ?n */
833 if (srchData->platformQuark != NULLQUARK)
835 char * specStr = XrmQuarkToString(specPlatformQuark);
836 /* CheckForMatchall incs score if appropriate */
837 if (CheckForMatchall(srchData,specStr,srchData->platformStr) == True)
838 return True; /* RETURN: platform matches */
840 if (srchData->platformQuark == specPlatformQuark)
842 srchData->curScore += 2; /* perfect match better than matchall match */
843 return True; /* RETURN: platform matches */
845 return False; /* RETURN: platform doesnt match */
850 /*========================================================*/
851 $PFUNBEG$: CheckSearchVerMatchesSpec()
852 $1LINER$: Matches search pattern to spec data
856 /*================================================$SKIP$==*/
860 Boolean CheckSearchVerMatchesSpec(
861 __DtXlateSrchData * srchData,
862 XrmQuark specVersionQuark)
864 const char * numStr = XrmQuarkToString(specVersionQuark);
866 int upperBnd = INT_MAX;
869 if ( srchData->version == MATCHALL_VER
870 || CheckForMatchall(srchData,numStr,srchData->verStr) == True )
871 return True; /* RETURN; matchall specified */
873 /*** sscanf()-based parsing ***/
874 /* note that the (score=x) is an assignment, not a compare */
875 if ( (score=1) && sscanf(numStr,"%d-%d", &lowerBnd, &upperBnd) != 2
876 && (score=1) && sscanf(numStr,"%d+", &lowerBnd) != 1
877 && (score=2) && sscanf(numStr,"%d", &lowerBnd) != 1 )
878 return False; /* RETURN: syntax error */
880 if ( lowerBnd > srchData->version || upperBnd < srchData->version )
881 return False; /* RETURN: version doesnt match */
883 srchData->curScore += score;
884 return True; /* RETURN: version matches */
890 /*========================================================*/
891 $PFUNBEG$: CheckSearchOperMatchesSpec()
892 $1LINER$: Matches search pattern to spec data
895 srchData: state of the search
896 specOperationQuark: quark for the operation specification string
898 True: if srchData->operation is found in specOperation string
899 or the specOperation string is a match all
901 /*================================================$SKIP$==*/
905 Boolean CheckSearchOperMatchesSpec(
906 __DtXlateSrchData * srchData,
907 XrmQuark specOperationQuark)
909 const char * opStr = XrmQuarkToString(specOperationQuark);
912 const char * remainingOps;
914 if ( srchData->operStr == NULL
915 || CheckForMatchall(srchData,opStr,srchData->operStr) == True
916 || CheckForMatchall(srchData,srchData->operStr,opStr) == True )
917 return True; /* RETURN; matchall specified */
919 /* quark compare search */
920 if ( specOperationQuark == srchData->operQuark )
923 /*** strstr-based search ***/
924 hitLen = srchData->operStrLen;
925 remainingOps = opStr;
928 /* look for operation in remainingOps */
929 hit = strstr(remainingOps,srchData->operStr);
930 /* see if the hit is on a complete token */
932 && (hit == remainingOps || *(hit-1) == OPER_SEPARATOR)
933 && (hit[hitLen] == EOS || hit[hitLen] == OPER_SEPARATOR) )
936 srchData->curScore += 2; /*perfect match better than a matchall match*/
937 return True; /* RETURN: operation matches */
939 } while(hit != NULL && *(remainingOps = hit+1) != EOS);
941 return False; /* RETURN: no match on operation */
947 /*========================================================*/
948 $PFUNBEG$: CheckSearchDirOpToStdMatchesSpec()
949 $1LINER$: Matches search pattern to spec data
953 /*================================================$SKIP$==*/
957 Boolean CheckSearchDirOpToStdMatchesSpec(
958 __DtXlateSrchData * srchData,
959 XrmQuark specDirectionQuark)
962 __DtXlateType type = __DtXLATE_TYPE_NONE;
964 if (specDirectionQuark == srchData->inhibitQuark)
965 return False; /* RETURN: no match */
967 /* Note that the type and score expressions are assignments */
968 if (! ( ( (type=__DtXLATE_TYPE_REGEX)
969 && (specDirectionQuark == srchData->lessThanQuark))
970 || ( (type=__DtXLATE_TYPE_PURE)
972 && (specDirectionQuark == srchData->equalsToQuark))
973 || ( (type=__DtXLATE_TYPE_CONTAINS)
975 && (specDirectionQuark == srchData->containsQuark)) ) )
976 return False; /* RETURN: no match */
978 srchData->curScore += score;
979 srchData->curTransType = type;
980 return True; /* RETURN: direction matches */
985 /*========================================================*/
986 $PFUNBEG$: CheckSearchDirStdToOpMatchesSpec()
987 $1LINER$: Matches search pattern to spec data
991 /*================================================$SKIP$==*/
995 Boolean CheckSearchDirStdToOpMatchesSpec(
996 __DtXlateSrchData * srchData,
997 XrmQuark specDirectionQuark)
1000 __DtXlateType type = __DtXLATE_TYPE_NONE;
1002 if (specDirectionQuark == srchData->inhibitQuark)
1003 return False; /* RETURN: no match */
1005 /* Note that the type and score expressions are assignments */
1006 if (! ( ( (type=__DtXLATE_TYPE_REGEX)
1007 && (specDirectionQuark == srchData->moreThanQuark))
1008 || ( (type=__DtXLATE_TYPE_PURE)
1010 && (specDirectionQuark == srchData->equalsToQuark))
1011 || ( (type=__DtXLATE_TYPE_CONTAINS)
1013 && (specDirectionQuark == srchData->containsQuark)) ) )
1014 return False; /* RETURN: no match */
1016 srchData->curScore += score;
1017 srchData->curTransType = type;
1018 return True; /* RETURN: direction matches */
1024 /*========================================================*/
1025 $PFUNBEG$: CheckSearchStdValueMatchesSpec()
1026 $1LINER$: Matches search pattern to spec data
1030 /*================================================$SKIP$==*/
1034 Boolean CheckSearchStdValueMatchesSpec(
1035 __DtXlateSrchData * srchData,
1036 XrmQuark * specStdValueQuarks)
1040 XrmQuark * patQuarks;
1042 /* walk through all available quarks */
1043 for ( patQuarks = srchData->stdValueQuarks;
1044 *specStdValueQuarks != NULLQUARK && *patQuarks != NULLQUARK;
1045 specStdValueQuarks++, patQuarks++ )
1047 char * specStr = XrmQuarkToString(*specStdValueQuarks);
1048 char * patStr = XrmQuarkToString(*patQuarks);
1049 if ( CheckForMatchall(srchData,specStr,patStr) == True
1050 || CheckForMatchall(srchData,patStr,specStr) == True )
1051 continue; /* no score for a matchall */
1053 /* is not exact match, match fails */
1054 /* be case insensitive when comparing standard values */
1055 if ( *patQuarks != *specStdValueQuarks
1056 && strCaseiCmp(specStr,patStr) == False )
1057 return False; /* RETURN: no match */
1059 /* one more match--increase score, go to next */
1063 /* find out how many stdValue fields were left unmatched */
1064 for ( unmatched = 0;
1065 *specStdValueQuarks != NULLQUARK;
1066 specStdValueQuarks++ )
1069 /* Score is combo of the number matched - the number unmatched
1070 and not counting the number matchalls that coincided with
1071 the search pattern. This technique allows the spec for
1072 val1 to be at "better" match than the one for val2, and
1073 val2 to be a better match than val3, and val3 to be a better
1075 .a.std : val1 querypattern = a.std
1076 .?.std : val2 querypattern = a.std
1077 .?1.std : \\1val3 querypattern = a.std
1078 .a.std : val4 querypattern = ?.std
1079 .?.std : val5 querypattern = ?.std
1080 .?1.std : \\1val6 querypattern = ?.std
1082 .a.std.? : val4 querypattern = a.std
1083 .?.std.? : val5 querypattern = a.std
1084 .?.std.?1 : \\1val5 querypattern = a.std
1085 .?1.std.? : \\1val5 querypattern = a.std
1086 .?1.std.?2 : \\1\\2val5 querypattern = a.std
1087 .a.std.? : val4 querypattern = a.std.b
1088 .?.std.? : val5 querypattern = a.std.b
1089 .?.std.?1 : \\1val5 querypattern = a.std.b
1090 .?1.std.? : \\1val5 querypattern = a.std.b
1091 .?1.std.?2 : \\1\\2val5 querypattern = a.std.b
1093 srchData->curScore += score + MAXSTDQUARKS - unmatched;
1095 return True; /* RETURN: direction matches */
1101 /*========================================================*/
1102 $PFUNBEG$: CheckSearchOpValueMatchesSpec()
1103 $1LINER$: Matches search pattern to spec data
1107 /*================================================$SKIP$==*/
1111 Boolean CheckSearchOpValueMatchesSpec(
1112 __DtXlateSrchData * srchData,
1113 const char * specOpValue)
1115 char opValBuf[MAXRHSSIZE]; /* max supported RHS size */
1116 char * pOpValBuf = opValBuf; /* need this for StripMeta... call */
1118 Boolean matches = False;
1120 /* copy value to mutable memory */
1121 strncpy(opValBuf,specOpValue,sizeof(opValBuf));
1122 opValBuf[sizeof(opValBuf)-1] = EOS;
1123 opValLen = strlen(opValBuf);
1125 /* depending on the translation type of the spec, do a
1126 regexex match of the spec value pattern to the search
1127 value or do a pure match */
1128 if (srchData->curTransType == __DtXLATE_TYPE_REGEX)
1133 /* True: leave escape char in place */
1134 StripMetaAndReplaceEscSubex(&pOpValBuf,True,NULL);
1136 /* we need to use regexex to pattern match */
1137 /* and we need to save of the reference value matches */
1138 if ( (ex = compile(opValBuf,NULL,NULL)) != NULL
1139 && advance(srchData->opValue,ex) != 0)
1142 int subExCnt = nbra; /* Sun global for advance() */
1143 matches = True; /* if got this far */
1145 /* need due to bug in advance()--operation doesn't meet documentation */
1146 if (NULL == loc1) loc1=(char *)srchData->opValue;
1148 /* inc score by the size of the match after
1149 scaling for the maximum possible match size */
1150 matchSize = loc2 - loc1; /*loc[12] are Sun globals for advance()*/
1151 if (matchSize < 0 || matchSize >= sizeof(opValBuf)) matchSize = 0;
1153 /* NOTE: this scoring code should be identical in the
1154 Sun-specific and non-Sun code blocks */
1155 if (matchSize == strlen(srchData->opValue))
1157 /* if the matchSize is the length of srchData->opValue,
1158 then we have a complete match. In this case, use the
1159 specificity of the pattern to pick the best match */
1160 /* NOTE: opValLen is a crude measure of specificity.
1161 A better measure would be to count the number of
1162 literals/ranges that matched exactly. When doing this,
1163 a perfect match without regex syntax should rank higher
1164 than a perfect match with regex syntax. This is one
1165 area where the current algorithm breaks. For example:
1166 opValue=23, pat1=23, pat2=[0-9]3.
1167 Both patterns match and pat1 is a better match,
1168 but not with the current length-based algorithm. */
1169 /* NOTE: this formula does not advance the score
1170 to sizeof(opValBuf) for a perfect match. Other match
1171 formulas use sizeof(opValBuf) as the max value
1172 to indicate a perfect match. */
1173 srchData->curScore += matchSize + opValLen;
1177 /* if its not a complete match, inc score by match size */
1178 srchData->curScore += matchSize;
1181 /* put sub expression matching stuff in srchData->curSubEx */
1182 for( ; nbra > 0; nbra-- )
1184 srchData->curSubEx[nbra].rm_so = braslist[nbra-1] - loc1;
1185 srchData->curSubEx[nbra].rm_eo = braelist[nbra-1] - loc1;
1192 /* True: leave escape char in place */
1193 StripMetaAndReplaceEscSubex(&pOpValBuf,True,NULL);
1195 /* we need to use regexex to pattern match */
1196 /* and we need to save of the reference value matches */
1197 if ( regcomp(&re,opValBuf,0) == 0
1198 && regexec(&re,srchData->opValue,
1199 XtNumber(srchData->curSubEx),srchData->curSubEx,0) == 0)
1202 matches = True; /* if got this far */
1204 /* inc score by the size of the match after
1205 scaling for the maximum possible match size */
1206 matchSize = srchData->curSubEx[0].rm_eo -
1207 srchData->curSubEx[0].rm_so;
1209 /* NOTE: this scoring code should be identical in the
1210 Sun-specific and non-Sun code blocks */
1211 if (matchSize == strlen(srchData->opValue))
1213 /* if the matchSize is the length of srchData->opValue,
1214 then we have a complete match. In this case, use the
1215 specificity of the pattern to pick the best match */
1216 /* NOTE: opValLen is a crude measure of specificity.
1217 A better measure would be to count the number of
1218 literals/ranges that matched exactly. When doing this,
1219 a perfect match without regex syntax should rank higher
1220 than a perfect match with regex syntax. This is one
1221 area where the current algorithm breaks. For example:
1222 opValue=23, pat1=23, pat2=[0-9]3.
1223 Both patterns match and pat1 is a better match,
1224 but not with the current length-based algorithm. */
1225 /* NOTE: this formula does not advance the score
1226 to sizeof(opValBuf) for a perfect match. Other match
1227 formulas use sizeof(opValBuf) as the max value
1228 to indicate a perfect match. */
1229 srchData->curScore += matchSize + opValLen;
1233 /* if its not a complete match, inc score by match size */
1234 srchData->curScore += matchSize;
1237 /* sub expression matching stuff already in srchData->curSubEx */
1242 else /* (srchData->curTransType == __DtXLATE_TYPE_PURE || __DtXLATE_TYPE_CONTAINS */
1244 char * opValueInBuf;
1246 /* False: strip escape char as well */
1247 StripMetaAndReplaceEscSubex(&pOpValBuf,False,NULL);
1248 matches = (strcmp(srchData->opValue,opValBuf) == 0);
1250 /* if matches, inc score to show a perfect match (max poss value) */
1251 if (matches) srchData->curScore += sizeof(opValBuf);
1253 /* don't test for contains if a perfect match or a pure match spec */
1254 if (matches || srchData->curTransType == __DtXLATE_TYPE_PURE)
1255 return matches; /* RETURN */
1257 /* (srchData->curTransType == __DtXLATE_TYPE_CONTAINS) */
1258 /* is opValue contained in opValBuf? */
1259 /* is opValBuf contained in opValue? */
1260 opValueInBuf = NULL;
1261 matches = (opValBuf[0] != EOS && srchData->opValue[0] != EOS)
1262 && ((opValueInBuf=strstr(opValBuf,srchData->opValue)) != NULL
1263 || strstr(srchData->opValue,opValBuf) != NULL);
1265 /* if matches, inc score to show a contains match */
1268 if (opValueInBuf) srchData->curScore += strlen(srchData->opValue);
1269 else srchData->curScore += strlen(opValBuf);
1279 /*========================================================*/
1280 $PFUNBEG$: FindStdToOpMatchCB()
1281 $1LINER$: Matches std value of entry to search pattern; gets op value
1285 /*================================================$SKIP$==*/
1289 Bool FindStdToOpMatchCB(
1290 XrmDatabase * database,
1291 XrmBindingList bindings,
1292 XrmQuarkList quarks,
1293 XrmRepresentation * type,
1295 XPointer client_data)
1297 __DtXlateSrchData * srchData = (__DtXlateSrchData *) client_data;
1299 /* always begin scoring from 0 and replacement values at NULL */
1300 srchData->curScore = 0;
1301 memset(srchData->curSpecRefs,0, sizeof(srchData->curSpecRefs));
1304 fprintf(stderr,"FindStdToOpMatch: "); PrintDbEntry(quarks,value);
1307 /* check for a match */
1308 if ( CheckSearchPlatformMatchesSpec(srchData,
1309 quarks[PLATFORM_QUARK]) == False)
1310 return False; /* continue enumeration */
1313 fprintf(stderr,"platform matches\n");
1316 if ( CheckSearchVerMatchesSpec(srchData,
1317 quarks[VERSION_QUARK]) == False)
1318 return False; /* continue enumeration */
1321 fprintf(stderr,"ver matches\n");
1324 if ( CheckSearchOperMatchesSpec(srchData,
1325 quarks[OPERS_QUARK]) == False)
1326 return False; /* continue enumeration */
1329 fprintf(stderr,"oper matches\n");
1332 if ( CheckSearchDirStdToOpMatchesSpec(srchData,
1333 quarks[DIRECTION_QUARK]) == False)
1334 return False; /* continue enumeration */
1337 fprintf(stderr,"kind matches\n");
1340 /* now check for std value match and, if it is
1341 the best match so far, record the value */
1342 if ( CheckSearchStdValueMatchesSpec(srchData,
1343 &quarks[FIRSTSTD_QUARK]) == False )
1345 if (srchData->db->debugMode)
1347 fprintf(stderr,"mismatch ");
1348 PrintDbEntry(quarks,value);
1351 return False; /* continue enumeration */
1355 fprintf(stderr,"std value matches\n");
1358 if (srchData->db->debugMode)
1360 fprintf(stderr,"match (%d) ",srchData->curScore);
1361 PrintDbEntry(quarks,value);
1364 /* we have a match! (we made it through all match checks) */
1365 /* is it better than or same as any earlier match? */
1366 if ( srchData->curScore >= srchData->bestScore )
1368 /* recall that all strings are owned by Xrm==>no need to free them */
1369 srchData->bestScore = srchData->curScore;
1370 srchData->bestTransType = srchData->curTransType;
1371 memcpy(srchData->bestSpecRefs,srchData->curSpecRefs,
1372 sizeof(srchData->bestSpecRefs)); /* no array assignment in C */
1373 srchData->opValue = value->addr;
1376 return False; /* continue enumeration */
1381 /*========================================================*/
1382 $PFUNBEG$: FindOpToStdMatchCB()
1383 $1LINER$: Matches op value of entry to search pattern; gets std value
1387 /*================================================$SKIP$==*/
1391 Bool FindOpToStdMatchCB(
1392 XrmDatabase * database,
1393 XrmBindingList bindings,
1394 XrmQuarkList quarks,
1395 XrmRepresentation * type,
1397 XPointer client_data)
1399 __DtXlateSrchData * srchData = (__DtXlateSrchData *) client_data;
1401 /* always begin scoring from 0 and subexpression indices at -1 */
1402 srchData->curScore = 0;
1403 memset(srchData->curSubEx,-1, sizeof(srchData->curSubEx));
1406 fprintf(stderr,"FindOpToStdMatch: "); PrintDbEntry(quarks,value);
1409 /* check for a match */
1410 if ( CheckSearchPlatformMatchesSpec(srchData,
1411 quarks[PLATFORM_QUARK]) == False)
1412 return False; /* continue enumeration */
1415 fprintf(stderr,"platform matches\n");
1418 if ( CheckSearchVerMatchesSpec(srchData,
1419 quarks[VERSION_QUARK]) == False)
1420 return False; /* continue enumeration */
1423 fprintf(stderr,"ver matches\n");
1426 if ( CheckSearchOperMatchesSpec(srchData,
1427 quarks[OPERS_QUARK]) == False)
1428 return False; /* continue enumeration */
1431 fprintf(stderr,"oper matches\n");
1434 if ( CheckSearchDirOpToStdMatchesSpec(srchData,
1435 quarks[DIRECTION_QUARK]) == False)
1436 return False; /* continue enumeration */
1439 fprintf(stderr,"kind matches\n");
1442 /* now check for op value match and, if it is
1443 the best match so far, record the std value */
1444 if ( CheckSearchOpValueMatchesSpec(srchData,
1445 value->addr) == False )
1447 if (srchData->db->debugMode)
1449 fprintf(stderr,"mismatch ");
1450 PrintDbEntry(quarks,value);
1453 return False; /* continue enumeration */
1457 fprintf(stderr,"op value matches\n");
1460 if (srchData->db->debugMode)
1462 fprintf(stderr,"match (%d) ",srchData->curScore);
1463 PrintDbEntry(quarks,value);
1466 /* we have a match! (we made it through all match checks) */
1467 /* is it better than or same as any earlier match? */
1468 if ( srchData->curScore >= srchData->bestScore )
1472 /* recall that all strings are owned by Xrm==>no need to free them */
1473 srchData->bestScore = srchData->curScore;
1474 srchData->bestTransType = srchData->curTransType;
1475 memcpy(srchData->bestSubEx,srchData->curSubEx,
1476 sizeof(srchData->bestSubEx)); /* no array assignment in C */
1477 /* store off the std value of the best match */
1478 stdQ = srchData->stdValueQuarks;
1479 curQ = &quarks[FIRSTSTD_QUARK];
1480 while ( (*stdQ = *curQ) != NULLQUARK ) stdQ++, curQ++;
1483 return False; /* continue enumeration */
1488 /*========================================================*/
1489 $PFUNBEG$: DoCommonSrchDataPrep
1490 $1LINER$: Prep srchData to search for a pattern
1494 /*================================================$SKIP$==*/
1497 void DoCommonSrchDataPrep(
1498 __DtXlateSrchData * srchData,
1500 const char * platform,
1502 const char * operation)
1504 int verNum = version; /* for lint */
1506 /* zero the search data */
1507 memset(srchData,0,sizeof(__DtXlateSrchData));
1512 /* build filter list for enumerating the db */
1513 if (verNum < MATCHALL_VER) verNum = MATCHALL_VER;
1514 srchData->platformStr = platform;
1515 srchData->platformQuark = (platform?XrmStringToQuark(platform):NULLQUARK);
1516 srchData->version = verNum;
1517 sprintf(srchData->verStr,"%d",verNum);
1518 srchData->operStr = operation;
1519 srchData->operStrLen = strlen(operation);
1520 srchData->operQuark = (operation ? XrmStringToQuark(operation) : NULLQUARK);
1521 srchData->lessThanQuark = XrmStringToQuark(LESSTHAN_STR);
1522 srchData->equalsToQuark = XrmStringToQuark(EQUALS_STR);
1523 srchData->containsQuark = XrmStringToQuark(CONTAINS_STR);
1524 srchData->moreThanQuark = XrmStringToQuark(MORETHAN_STR);
1525 srchData->inhibitQuark = XrmStringToQuark(INHIBIT_STR);
1528 /*========================================================*/
1529 /*=============== Public Xlate routines ==================*/
1530 /*========================================================*/
1535 /*========================================================*/
1536 $FUNBEG$: _DtXlateOpenDb()
1537 $1LINER$: Open a translation database
1539 Opens a translation resource database and returns a
1540 reference to it in ret_db.
1542 Initializes the _DtXlateDb object to ready for use.
1543 If an error occurs, _DtXlateDb is set to NULL.
1546 0: no error occurred
1547 -1: if ret_db is NULL
1548 if XrmGetFileDatabase() failed on databaseName
1549 if malloc fails to alloc a db structure
1550 /*================================================$SKIP$==*/
1554 const char * databaseName,
1555 _DtXlateDb * ret_db)
1558 __DtXlateDbRec * dbRec = NULL;
1561 if(NULL == ret_db) return -1; /* RETURN */
1564 /* Do NOT check for whether *ret_db is already
1565 a valid db; this is none of our affair. */
1567 /* get an absolute path for the file */
1568 path = ExpandPath(databaseName);
1570 if (NULL == path) return -1; /* RETURN */
1572 xrmDb = XrmGetFileDatabase(path);
1573 if (NULL == xrmDb) { free(path); return -1; } /* RETURN */
1575 /* alloc a db ref */
1576 dbRec = (__DtXlateDbRec *) calloc(1,sizeof(__DtXlateDbRec));
1579 XrmDestroyDatabase(xrmDb);
1581 return -1; /* RETURN */
1584 /* and populate it */
1585 dbRec->xrmDb = xrmDb;
1586 dbRec->initGuard = INIT_OCCURRED;
1588 /* check for debug mode */
1589 SetDebugModeState(dbRec);
1591 if (dbRec->debugMode)
1592 fprintf(stderr,"_DtXlateOpenDb: opened: %s; new db: %p\n",path, (void *)dbRec);
1596 return 0; /* RETURN */
1600 /*========================================================*/
1601 $FUNBEG$: _DtXlateOpenAndMergeDbs()
1602 $1LINER$: Opens a translation database and merges with earlier dbs
1604 Opens a translation resource database and returns a
1605 reference to it in ret_db.
1607 Initializes the _DtXlateDb object to ready for use.
1610 0: no error occurred
1611 -1: if io_db is NULL
1612 if XrmGetFileDatabase() failed on databaseName
1613 /*================================================$SKIP$==*/
1616 int _DtXlateOpenAndMergeDbs(
1617 const char * databaseName,
1624 if(NULL == io_db) return -1; /* RETURN */
1626 /* if a db has not yet been opened */
1628 || (*io_db)->initGuard != INIT_OCCURRED
1629 || (*io_db)->xrmDb == NULL)
1631 ret = _DtXlateOpenDb(databaseName,io_db); /* RETURN */
1632 if ( (*io_db) && (*io_db)->debugMode)
1633 fprintf(stderr,"_DtXlateOpenAndMergeDb: "
1634 "used _DtXlateOpenDb to open first file\n");
1635 return ret; /* RETURN */
1638 if ( (*io_db) && (*io_db)->debugMode)
1639 fprintf(stderr,"_DtXlateOpenAndMergeDb: "
1640 "target file: %s; existing db: %p\n",databaseName, (void *) *io_db);
1642 /* a db has been opened, let's merge with it */
1644 /* get an absolute path for the file */
1645 path = ExpandPath(databaseName);
1647 if (NULL == path) goto Failed; /* RETURN */
1649 xrmDb = XrmGetFileDatabase(path);
1650 if (NULL == xrmDb) goto Failed; /* RETURN */
1652 /* merge and destroy xrmDb for me */
1653 XrmMergeDatabases(xrmDb,&(*io_db)->xrmDb);
1655 /* check for debug mode */
1656 SetDebugModeState(*io_db);
1658 if ((*io_db)->debugMode)
1659 fprintf(stderr,"_DtXlateOpenAndMergeDb: "
1660 "opened: %s; merged db: %p\n",path, (void *) *io_db);
1663 return 0; /* RETURN */
1666 if ( (*io_db) && (*io_db)->debugMode)
1667 fprintf(stderr,"_DtXlateOpenAndMergeDb: open failed; file: %s\n",
1668 (path ? path : (databaseName ? databaseName : "NULL") ) );
1669 if (path) free(path);
1670 return -1; /* RETURN */
1674 /*========================================================*/
1675 $FUNBEG$: _DtXlateMergeDbs()
1676 $1LINER$: Merges two open dbs into one and closes the merged-in db.
1678 Merges two databases into one and closes the merged db.
1680 The io_dbToMerge database must be a valid translation database.
1681 The io_dbToMerge database is merged into the io_mergeIntoDb.
1682 The io_mergeIntoDb may either be invalid or valid. If invalid,
1683 the io_dbToMerge database is simply moved over to io_mergeIntoDb.
1684 If io_mergeIntoDb is valid, the entries in the io_dbToMerge
1685 database are merged into it and take precedence over entries in the
1686 io_mergeIntoDb, and the io_dbToMerge database is closed.
1688 io_dbToMerge: database to merge into io_mergeIntoDb
1689 io_mergeIntoDb: database to hold merged result
1691 0: no error occurred
1692 -1: if io_dbToMerge or io_mergeIntoDb is NULL
1693 if *io_dbToMerge is NULL or uninitialized
1694 /*================================================$SKIP$==*/
1697 int _DtXlateMergeDbs(
1698 _DtXlateDb * io_dbToMerge,
1699 _DtXlateDb * io_mergeIntoDb)
1703 if( NULL == io_mergeIntoDb
1704 || NULL == io_dbToMerge
1705 || NULL == *io_dbToMerge
1706 || (*io_dbToMerge)->initGuard != INIT_OCCURRED
1707 || (*io_dbToMerge)->xrmDb == NULL)
1708 return -1; /* RETURN */
1710 /* check for debug mode */
1711 if ( ((*io_mergeIntoDb) && (*io_mergeIntoDb)->debugMode)
1712 || (*io_dbToMerge)->debugMode)
1713 fprintf(stderr,"_DtXlateMergeDbs: "
1714 "mergeIntoDb: %p; dbToMerge: %p\n", (void *) *io_mergeIntoDb, (void *) *io_dbToMerge);
1716 /* if db_mergeIntoDb has not yet been opened */
1717 if( NULL == *io_mergeIntoDb
1718 || (*io_mergeIntoDb)->initGuard != INIT_OCCURRED
1719 || (*io_mergeIntoDb)->xrmDb == NULL)
1721 /* just move dbToMerge into mergeIntoDb */
1722 *io_mergeIntoDb = *io_dbToMerge;
1723 DeleteDbMem(io_dbToMerge);
1725 return 0; /* RETURN */
1728 /* merge and destroy io_dbToMerge->xrmDb for me */
1729 XrmMergeDatabases((*io_dbToMerge)->xrmDb,&(*io_mergeIntoDb)->xrmDb);
1730 DeleteDbMem(io_dbToMerge);
1732 /* check for debug mode */
1733 SetDebugModeState(*io_mergeIntoDb);
1735 if ((*io_mergeIntoDb)->debugMode)
1736 fprintf(stderr,"merged db: %p\n", (void *) *io_mergeIntoDb);
1742 /*========================================================*/
1743 $FUNBEG$: _DtXlateOpenAllDbs()
1744 $1LINER$: Open and merge all locale translation databases that can be found
1746 DtXlateOpenAllDbs() locates all translation databases
1747 present in the search paths directories.
1749 searchPaths: ':' separated list of directories
1750 databaseName: name of the database file in those directories
1751 ret_db: the reference to the open database is stored here
1753 0: at least one database was opened
1754 -1: no database was opened
1755 /*================================================$SKIP$==*/
1758 int _DtXlateOpenAllDbs(
1759 const char * searchPaths,
1760 const char * databaseName,
1761 _DtXlateDb * ret_db)
1763 const char * workStart = searchPaths;
1764 const char * separator = NULL;
1765 char dbFile[MAXPATHLEN+1];
1766 int ret = ~0; /* all bits set */
1768 /* cycle through the paths, opening each one */
1772 const char * slash = NULL;
1776 /* isolate the next part of the path */
1777 _DtMBStrchr (workStart, PATH_SEPARATOR, -1, &separator);
1778 if (NULL == separator) _DtMBStrchr (workStart, EOS, -1, &separator);
1779 if (NULL == separator) break; /* BREAK */
1780 workLen = separator - workStart; /* dont include +1 for EOS */
1782 /* copy over the path component */
1783 strncpy(dbFile,workStart,workLen);
1784 workStart = separator + 1;
1786 /* add a slash to end of path component, if needed */
1787 *(dbFile+workLen) = EOS; /* add an EOS for _DtMBStrrchr to find */
1788 _DtMBStrrchr(dbFile,DIR_SLASH,-1,&slash);
1789 if (slash != dbFile+workLen-1) /* is slash last char of path? */
1791 *(dbFile+workLen) = DIR_SLASH;
1795 /* append the filename and EOS */
1796 strcpy(dbFile+workLen,databaseName);
1798 /*printf("Working on: %s\n", dbFile); **DBG*/
1800 /* open and merge the database with previously opened dbs */
1801 /* by ANDing, we determine whether at least one call returned 0 */
1802 ret &= _DtXlateOpenAndMergeDbs(dbFile,ret_db);
1804 } while ( *separator != EOS );
1806 if (*ret_db && (*ret_db)->debugMode)
1807 fprintf(stderr,"_DtXlateOpenAllDbs: completed\n"
1808 " srchpaths: %s; db file: %s\n",searchPaths,databaseName);
1810 return (ret == 0 ? 0 : -1); /* ret != 0 ==> no db was opened */
1815 /*========================================================*/
1816 $FUNBEG$: _DtXlateCloseDb()
1817 $1LINER$: Close an open translation database
1819 _DtXlafteCloseDb() releases all memory associated with
1820 the translation database. Further use of the database
1824 0: database was valid and has been closed
1825 -1: invalid database pointer
1826 /*================================================$SKIP$==*/
1829 int _DtXlateCloseDb(
1832 __DtXlateDbRec * dbRec;
1835 || NULL == (dbRec = *io_db) /* dbRec assigned */
1836 || dbRec->initGuard != INIT_OCCURRED)
1837 return -1; /* RETURN */
1839 XrmDestroyDatabase(dbRec->xrmDb);
1841 if (dbRec->debugMode) fprintf(stderr,"_DtXlateCloseDb: %p\n", (void *) dbRec);
1843 /* zero out object mem and free it */
1851 /*========================================================*/
1852 $FUNBEG$: _DbXlateStdToOpValue()
1853 $1LINER$: Translates a standardized spec to an operation-specific value
1855 Looks up the best translation of the standard value for an
1856 operation and places a pointer to the translation string
1857 at the location pointed to by ret_opValue.
1859 The translated string was allocated using malloc() and
1860 must be freed when no longer needed.
1862 If ret_opValue is NULL, the function merely verifies that
1863 a valid translation exists.
1865 db: a translation database
1866 platform: the platform string (see _DtXlateGetXlateEnv())
1867 version: the version number (see _DtXlateGetXlateEnv())
1868 operation: the operation of interest, e.g. "setlocale"
1869 stdValue: the standard value pattern
1870 ret_opValue: location where ptr to translated string is stored
1871 ret_reserved: reserved for future use
1873 0: translation found
1874 -1: invalid database (NULL ptr, not opened)
1875 no operation was specified
1876 query failed to find a match
1877 /*================================================$SKIP$==*/
1880 int _DtXlateStdToOpValue(
1882 const char * platform,
1884 const char * operation,
1885 const char * stdValue,
1886 char * * ret_opValue,
1887 void * ret_reserved)
1889 __DtXlateSrchData srchData;
1890 XrmQuark empty = NULLQUARK;
1893 || db->initGuard != INIT_OCCURRED
1894 || NULL == operation
1895 || operation[0] == EOS)
1896 return -1; /* RETURN error */
1898 /* prep srch data for search */
1899 DoCommonSrchDataPrep(&srchData,db,platform,version,operation);
1901 /* handle a rare case */
1902 if (NULL == stdValue)
1904 if (db->debugMode) fprintf(stderr,"_DtXlateStdToOpValue: NULL std value\n");
1905 if (ret_opValue) *ret_opValue = NULL;
1906 return -1; /* RETURN error */
1909 /* build std value list for use during comparison */
1910 srchData.stdValueQuarks[0] = NULLQUARK;
1911 if (NULL != stdValue && stdValue[0] != EOS)
1912 XrmStringToQuarkList(stdValue,srchData.stdValueQuarks);
1915 fprintf(stderr,"_DtXlateStdToOpValue: %s.%d.%s.%s: <op>\n",
1916 platform,version,operation,stdValue);
1918 /* scan through this Db looking for matches and put in search */
1919 XrmEnumerateDatabase(db->xrmDb,&empty,&empty,
1920 XrmEnumAllLevels, FindStdToOpMatchCB, (XPointer) &srchData);
1922 if ( srchData.opValue != NULL
1923 && srchData.bestTransType != __DtXLATE_TYPE_INHIBIT )
1927 if (ret_opValue == NULL)
1929 if (db->debugMode) fprintf(stderr,"translation exists\n");
1930 return 0; /* RETURN: translation exists */
1933 /* alloc the string to return */
1934 opValue = strdup(srchData.opValue);
1936 if (db->debugMode) fprintf(stderr,"raw opval:%s\n",opValue);
1938 /* do quote and escape removal and ref replacement in the opValue */
1939 if ( srchData.bestTransType == __DtXLATE_TYPE_REGEX )
1940 StripMetaAndReplaceEscSubex(&opValue,False,srchData.bestSpecRefs);
1942 StripMetaAndReplaceEscSubex(&opValue,False,NULL);
1944 if (db->debugMode) fprintf(stderr,"op value:%s\n",opValue);
1946 *ret_opValue = opValue;
1947 return 0; /* RETURN: search successful */
1949 return -1; /* RETURN: search failed */
1954 /*========================================================*/
1955 $FUNBEG$: _DbXlateOpToStdValue()
1956 $1LINER$: Translates an operation-specific value to a standardized one
1958 Looks up the best translation of the operation value for an
1959 operation and places a pointer to the standard string
1960 at the location pointed to by ret_stdValue.
1962 The standard string was allocated using malloc() and
1963 must be freed when no longer needed.
1965 If ret_stdValue is NULL, the function merely verifies that
1966 a valid translation exists.
1968 db: a translation database
1969 platform: the platform string (see _DtXlateGetXlateEnv())
1970 version: the version number (see _DtXlateGetXlateEnv())
1971 operation: the operation of interest, e.g. "setlocale"
1972 opValue: the operation-specific value pattern
1973 ret_stdValue: location where ptr to standard string is stored
1974 ret_reserved: reserved for future use
1976 0: translation found
1977 -1: invalid database (NULL ptr, not opened)
1978 no operation was specified
1979 query failed to find a match
1980 /*================================================$SKIP$==*/
1983 int _DtXlateOpToStdValue(
1985 const char * platform,
1987 const char * operation,
1988 const char * opValue,
1989 char * * ret_stdValue,
1990 void * ret_reserved)
1992 __DtXlateSrchData srchData;
1993 XrmQuark empty = NULLQUARK;
1994 char lhs[MAXLHSSIZE];
1997 || db->initGuard != INIT_OCCURRED
1998 || NULL == operation
1999 || operation[0] == EOS)
2000 return -1; /* RETURN error */
2002 /* prep srch data for search */
2003 DoCommonSrchDataPrep(&srchData,db,platform,version,operation);
2005 /* after check on value, store op value for use during comparison */
2006 /* not meaningful to check for a NULL value */
2007 if (NULL == opValue)
2009 if (db->debugMode) fprintf(stderr,"_DtXlateOpToStdValue: NULL op value\n");
2010 if (ret_stdValue) *ret_stdValue = NULL;
2011 return -1; /* RETURN error */
2013 srchData.opValue = opValue;
2016 fprintf(stderr,"_DtXlateOpToStdValue: %s.%d.%s.<std>: %s\n",
2017 platform,version,operation,opValue);
2019 /* scan through this Db looking for matches and put in search */
2020 XrmEnumerateDatabase(db->xrmDb,&empty,&empty,
2021 XrmEnumAllLevels, FindOpToStdMatchCB, (XPointer) &srchData);
2023 if ( srchData.stdValueQuarks[0] != NULLQUARK
2024 && srchData.bestTransType != __DtXLATE_TYPE_INHIBIT )
2027 char * stdValue = lhs;
2028 int stdValueLen = 0;
2030 if (ret_stdValue == NULL)
2032 if (db->debugMode) fprintf(stderr,"translation exists\n");
2033 return 0; /* RETURN: translation exists */
2036 /* make a STDVALUE_SEPARATOR separated string out of the std data */
2037 for ( stdQ = srchData.stdValueQuarks;
2041 const char * str = XrmQuarkToString(*stdQ);
2043 if (NULL == str || str[0] == EOS) continue;
2045 strLen = strlen(str);
2046 if (stdValue != lhs)
2047 {*stdValue++ = STDVALUE_SEPARATOR; stdValueLen++; }
2048 if ((stdValueLen + strLen) > sizeof(lhs) )
2049 strLen = sizeof(lhs)-stdValueLen;
2050 strncpy(stdValue,str,strLen);
2051 stdValueLen += strLen;
2056 if (db->debugMode) fprintf(stderr,"raw stdval:%s\n",lhs);
2058 /* do quote and escape removal and ref replacement in the stdValue */
2059 stdValue = strdup(lhs); /* reset stdValue ptr */
2060 if ( srchData.bestTransType == __DtXLATE_TYPE_REGEX )
2061 ReplaceMatchallSubex(&stdValue,srchData.bestSubEx,srchData.opValue);
2063 if (db->debugMode) fprintf(stderr,"std value:%s\n",stdValue);
2065 *ret_stdValue = stdValue;
2066 return 0; /* RETURN: search successful */
2068 return -1; /* RETURN: search failed */
2074 /*========================================================*/
2075 $FUNBEG$: _DtXlateGetXlateEnv()
2076 $1LINER$: Get the DtXlate compilation and execution environments.
2078 _DtXlateGetXlateEnv() recovers the identity of the application
2079 current platform, the version value of the application
2080 execution environment, and the version value of the operating
2081 system version for which DtXlateGetXlateEnv() was
2082 compiled. These values can be used in formulating queries,
2083 especially for the _DtXlateStdToOpValue() query.
2085 The technique used by this routine is as follows. Using
2086 uname(2), the routine retrieves the sysname, release, and version
2087 strings. The sysname is used as the platform name. The
2088 release and version strings are concatenated in that order
2089 and as treated below as the <op-rel-ver>. An OpToStd translation
2090 looks for a match to
2091 <sysname>.?.version.<.<std-version>: <op-rel-ver>
2093 <sysname>.?.version.=.<std-version>: <op-rel-ver>
2095 If no match is found, the next fallback position is to
2096 get the specification with the same sysname and the highest
2097 std-version integer value. If no specifications exist for
2098 that sysname, then sysname is set to the empty string and
2101 ret_AppExecEnvPlatform should point to a character array at least
2102 _DtPLATFORM_MAX_LEN characters long. The sysname is copied to it.
2104 ret_AppExecEnvVersion is given the integer value of the
2105 std-version recovered from the translation.
2107 ret_XlateCompiledForOSVersion is given the integer value
2108 determined by using the OSMajorVersion and OSMinorVersion
2109 constants defined by the build environment of _DtXlate as follows:
2112 #define STR(V) _STR(V)
2113 sprintf(buf,"%s%s%s", STR(OSMAJORVERSION),
2114 nl_langinfo(RADIXCHAR), STR(OSMAJORVERSION));
2115 verNum = (int) (100.0 * atof(buf));
2118 OSMAJORVERSION & OSMINORVERSION are compile-time constants
2119 that must be defined as part of the build environment.
2120 It is assumed that these constants are of the form:
2123 #define OSMAJORVERSION 5
2124 #define OSMINORVERSION 3
2126 530 = (int) 100.0 * atof("5.3");
2129 #define OSMAJORVERSION 8
2130 #define OSMINORVERSION 09
2132 809 = (int) 100.0 * atof("8.09");
2134 Note that it may be necessary for the application to determine
2135 the version number of an operation in some platform-specific
2136 and operation-specific manner, for example using a library
2137 version value. In many cases, however, the O.S. version value
2138 for which _DtXlate was compiled will be sufficient
2139 when identifying version numbers for standard development
2140 environment libraries, such as libc.
2144 xlateStd2Op(_DtXlateDb db,Boolean runtimeOp, char * operation,char * stdVal)
2146 char platform[_DtPLATFORM_MAX_LEN];
2148 char * opVal = NULL;
2152 ret=_DtXlateGetXlateEnv(db,platform,&version,NULL);
2154 ret=_DtXlateGetXlateEnv(db,platform,NULL,&version);
2156 _DtXlateStdToOpValue(db,platform,version,operation,stdVal,&opVal,NULL);
2157 return opVal; /* will be NULL if error occurred */
2161 ret_AppExecEnvPlatform: pts to a string at least _DtPLATFORM_MAX_LEN long
2162 that will hold the string uname(2) returns for sysname
2163 ret_AppExecEnvVersion: pts to an integer that will receive the platform
2164 standardized version number, as determined by
2165 a translation on uname(2) release+version.
2166 ret_XlateCompiledForOSVersion: pts to an integer that will receive the
2167 operating system version for which _DtXlate was
2168 compiled using OSMajorVersion * 100 + OSMinorVersion
2169 Any of the arguments may be NULL.
2171 0: if no error occurred
2172 -1: if no translation was possible to get the AppExecEnvVersion
2173 /*================================================$SKIP$==*/
2176 int _DtXlateGetXlateEnv(
2178 char * ret_AppExecEnvPlatform,
2179 int * ret_AppExecEnvVersion,
2180 int * ret_XlateCompiledForOSVersion)
2182 struct utsname names;
2184 char * platform = "NULL";
2188 /* get host specifics */
2191 /* first get execution host name */
2192 if (ret_AppExecEnvPlatform)
2194 strncpy(ret_AppExecEnvPlatform,names.sysname,_DtPLATFORM_MAX_LEN-1);
2195 ret_AppExecEnvPlatform[_DtPLATFORM_MAX_LEN-1] = EOS;
2196 platform=ret_AppExecEnvPlatform;
2199 /* then look up version number of execution host */
2200 if (ret_AppExecEnvVersion)
2202 #if defined(sun) || defined(_AIX) || defined(linux) || defined(CSRG_BASED)
2203 char version[SYS_NMLN+SYS_NMLN+2];
2205 char version[UTSLEN+UTSLEN+2];
2207 char * stdVer = NULL;
2208 int verNum = MATCHALL_VER;
2210 /* cat release version and do a translation on it to a std value */
2211 /* then convert the std value to a integer */
2212 strcpy(version,names.release);
2213 strcat(version,names.version);
2214 ret = _DtXlateOpToStdValue(db,names.sysname,0,
2215 _DtXLATE_OPER_VERSION,version,&stdVer,NULL);
2218 if (sscanf(stdVer,"%d",&verNum) != 1) verNum = MATCHALL_VER;;
2221 *ret_AppExecEnvVersion = verNum;
2225 /* then look up version number of execution host */
2226 if (ret_XlateCompiledForOSVersion)
2228 char buf[MAXINTSTRSIZE];
2231 #define STR(V) _STR(V)
2233 /*===========================
2234 OSMAJORVERSION & OSMINORVERSION are compile-time constants
2235 that must be defined as part of the build environment.
2236 It is assumed that these constants are of the form:
2239 #define OSMAJORVERSION 5
2240 #define OSMINORVERSION 3
2242 530 = (int) (100.0 * atof("5.3"));
2245 #define OSMAJORVERSION 8
2246 #define OSMINORVERSION 09
2248 809 = (int) (100.0 * atof("8.09"));
2249 ===========================*/
2251 #if !defined(OSMAJORVERSION) || !defined(OSMINORVERSION) || OSMAJORVERSION == 0
2252 #error OSMAJORVERSION and/or OSMINORVERSION not defined
2255 #if defined(linux) || defined(CSRG_BASED)
2256 sprintf(buf,"%s%s%s", STR(OSMAJORVERSION),
2257 nl_langinfo('.'), STR(OSMINORVERSION));
2259 sprintf(buf,"%s%s%s", STR(OSMAJORVERSION),
2260 nl_langinfo(RADIXCHAR), STR(OSMINORVERSION));
2263 *ret_XlateCompiledForOSVersion = (int) (100.0 * atof(buf));
2264 compver = *ret_XlateCompiledForOSVersion;
2268 fprintf(stderr,"_DtXlateGetXlateEnv: "
2269 "Platform: %s; Execution Ver: %d; Compiled Ver: %d\n",
2270 platform,execver,compver);
2276 /*========================================================*/
2277 /*================ Introductory Info =====================*/
2278 /*========================================================*/
2281 /*========================================================*/
2282 $INTROBEG$: _DtXlate family
2283 $1LINER$: API to translate any value to a standard value and back again
2285 _DtXlate is a collection of routines that allow translation
2286 between platform, version, and operation specific values
2287 into standard values and back again. Translation is
2288 based on the contents of database files specified using
2289 Xrm-style resources. The semantics of the translation
2290 are a combination of standard semantics for specifying
2291 platform, version, operation, and translation type, and
2292 caller-specific semantics for the standard value format
2293 and operation values.
2295 The API contains routines to process translation databases
2298 _DtXlateOpenDb() opens a particular translation database
2299 _DtXlateOpenAndMergeDb() opens a particular database and
2300 merges it with an already opened one, overriding any
2301 repeated specifications.
2302 _DtXlateOpenAllDbs() opens all occurances of a translation
2303 database found in a search path and cumulatively merges
2304 the contents, allowing for the override of existing
2305 specifications as well as the addition of new ones.
2306 _DtXlateCloseDb() closes an open database
2307 _DtXlateOpToStdValue() translates an platform, version,
2308 and operation specific value into a standard value.
2309 _DtXlateStdToOpValue() translates a standard value into
2310 a platform, version, and operation specific value.
2311 /*=$END$================================================*/
2315 /*========================================================*/
2316 $INTROBEG$: Design and Implementation Considerations
2317 $1LINER$: Factors influencing design and implementation
2319 The syntax of the translation specification table is designed
2320 to be compatible with Xrm resource specifications. This
2321 allows Xrm to be used to load, parse, and merge the databases
2322 for processing. This also causes the specifications to be
2323 case-sensitive, as case is preserved by Xrm and is used when
2326 However, due to the semantics of translation specifications
2327 and limitations of Xrm, XrmGetResource() queries generally
2328 will not be useful. Rather, a pattern matching API is provided
2329 that implements the query capability used for the translations.
2330 The initial implementation will use XrmEnumerateDatabase().
2332 Using Xrm leads to an in-memory approach to translation, meaning
2333 that all the resources files are parsed and loaded into memory
2334 as the first step of a translation. A line-at-a-time approach,
2335 that process one line at a time directly from the file in a
2336 grep- or awk-like manner, is likely more memory-efficient.
2338 Note that the line-at-a-time approach does not avoid parsing
2339 all the specification files, as the API supports inheritence
2340 and override of specifications. Hence, to ensure the correct
2341 value, the entire file set must be processed. Note also that
2342 in a situation where translations will be repeatedly performed,
2343 the Xrm in-memory approach may be more time-efficient, as the
2344 files need only be parsed once, and then are utilized repeatedly.
2346 Because of time constraints, a line-at-a-time approach will not
2347 be used for the first implementation, as Xrm provides all the
2348 necessary parsing, filtering, and symbol hashing routines
2349 for free. Given the likely large size of the tables and their
2350 infrequent use, a line-at-a-time approach is likely the better
2353 /*=$END$================================================*/
2358 /*========================================================*/
2359 $INTROBEG$: translation BNF syntax and semantics
2360 $1LINER$: _DtXlate translation specification syntax and semantics
2362 BNF Syntax of Translation Specification
2363 =======================================
2365 <specfile> ::= (<xlatespec> | <comment> | <cr>)*
2366 <xlatespec> ::= <platform>.<version>.<operations>.<transtype>
2367 .<stdvalue>:<opvalue> (<comment>|<cr>)
2368 <platform> ::= <identifier> | <matchall>
2369 <version> ::= <number> [+ | (- <number>)] | <matchall>
2370 <operations> ::= <identifier> [',' <identifier>]* | <matchall>
2371 <transtype> ::= '<' | '=' | '~' | '>' | '0'
2372 <stdvalue> ::= <identifier> [.<identifier>]*
2373 <langterr> ::= <identifier> | <matchall>
2374 <codeset> ::= <identifier> | <matchall>
2375 <modifier> ::= <identifier> | <matchall>
2376 <opvalue> ::= (<vischars>|<metachar>)+ | '"'(<anychar>|<metachar>)+'"'
2378 <matchall> ::= '?'[<number>]
2380 <comment> ::= '!' [^<cr>]* <cr>
2382 <identifier> ::= [-_a-ZA-Z0-9]
2383 <vischar> ::= any non-whitespace character; meta and regular
2384 expression chars must be escaped with "\\"
2385 <anychar> ::= any printable character; meta and regular
2386 expression chars must be escaped with "\\"
2387 <metachar> ::= '!' | '"' | <backslash> | <valex> | <regex>
2388 <valex> ::= <backslash><number>
2389 <regex> ::= see regexp(5)
2390 <backslash> ::= the backslash character (\).
2392 Semantics of the Translation Specification
2393 ==========================================
2395 <specfile> : a file containing zero or more translation specifications
2398 <xlatespec> : a translation specification defines a fully qualified
2399 string value which may be recovered by query pattern matching the
2400 specification. The qualifiers identify the semantics of the usage
2401 of the value, allowing queries to be meaningful. The entire xlatespec
2402 must be on one line of the file.
2404 <platform> : a CDE-standardized identifier for an operating system
2405 platform. The platform need not be supported by CDE, but CDE must
2406 have standardized an identifier for the platform in order for it to
2407 be used. For example, candidate platform identifiers are "HP-UX",
2408 "AIX", "SunOS", "Solaris", "SCO", etc. These identifiers are the
2409 values returned by uname(2):utsname.sysname and uname(1) -s, and
2410 I propose CDE standardize on using these values.
2412 The identifier string and matching constant value must be added to
2413 the source code of the translation routine in order for it to be
2414 recognized. This allows control over the platform registry
2415 and enables automatic generation of the platform on the execution
2416 host through the use of #ifdef <PLATFORM_CONST> in the source code.
2418 <version> : a platform-specific numeric value or range of numberic
2419 values that allows the value to be qualified to a particular version
2420 and release (version + release = version) or range of versions and
2421 releases of the platform. The version numbers must be integral and
2422 suitable for numeric comparison. The '+' can be used to specify an
2423 open upwards bound, as in 900+. The '- <number>' can be used to
2424 specify an upper bound, as in 900-999. If no range is specified,
2425 the version number must match exactly to the query pattern and/or
2426 execution environment.
2428 Platforms may not directly provide version numbers in a numeric
2429 format suitable for use when comparing with a translation
2430 specification. As part of the translation API source code,
2431 conversion routines must be supplied that translate the platform-
2432 specific values, such as those provided by uname(2), into a
2433 translation specification-compliant format suitable for comparison
2434 to <version>. Understanding the conversion routines operation
2435 will be necessary to ensure correct translation specifications.
2437 <operations> : a CDE-standardized identifier for the operation(s) to
2438 which the value applies. The operation(s) need not be supported by every
2439 platform, but CDE must have standardized an identifier for the operation
2440 in order for it to be used. More than one identifier may be included by
2441 concatenating them using the ',' separator, eg. "iconv1,iconv3".
2443 <transtype> : The <transtype> field records the direction of
2444 translation that the specification supports: '<', '=', '~', '>', '0'.
2445 Use '<' if the <opvalue> contains a regular expression; the
2446 specification may only be used to match an operation value in
2447 a _DtLcxXlateOpToStd() translation. Use '>' if the <opvalue>
2448 contains value replacement expressions using values from
2449 the <stdvalue> strings; the specification may only be used by a
2450 _DtLcxXlateStdToOp() translation. Use '=' if the <opvalue>
2451 is a pure string that may be used for either OpToStd() or
2452 StdToOp() translations, and the specification op-value must exactly
2453 match the op-value of the translation request. use '~' if the
2454 <opvalue> is a pure string that may be used for either OpToStd() or
2455 StdToOp() translations, and the specifation op-value must be
2456 a string within the op-value of the translation request.
2457 Use the '0' translation to represent that this particular
2458 translation should result in an error, that is should not result
2461 Translations are two-way operations: from a host- and
2462 operation-specific value to standardized value, and back again.
2463 In many cases, a straight string value for string value translation
2466 But often, more sophisticated pattern matching and value generation
2467 mechanisms are useful to keep the table size small and as general
2468 as possible. In these cases, wildcard and regular expression
2469 operators are useful. Unfortunately, these specifications are not
2470 bi-direction. That is, the pattern matching string can be used
2471 to match against a pattern, but not to generate a result string.
2472 For example, the vi expression s/he*lo/hello/ matches "hello"
2473 as well as "hey look out below", but the reverse direction of
2474 "hello"->"he*lo" will not work.
2476 <stdvalue> : a sequence of one or more '.'-separated CDE-standardizd
2477 identifiers or matchall characters. This represents the canonical
2478 string used as a standard representation of a semantic value that
2479 may vary in different situations.
2481 <opvalue> : a string that has different uses depending on the
2482 value of <transtype>. If transtype is '<', the string is used
2483 as a regular expression to match the opValue in _DtLcxXlateOpToStd()
2484 requests. If the transtype is '>', the string is used as a
2485 replacement expression to generate a opValue in _DtLcxXlateStdToOp().
2486 If transtype is '=' or '~', the string is used as a straight string to
2487 both match for the OpToStd translation and as a value for
2488 the StdToOp translation.
2490 If the opvalue contains whitespace, the opvalue must be enclosed in
2491 double quote characters. If the opvalue contains any meta characters
2492 that should not be treated as meta characters, they must be escaped by
2493 two preceding backslashs.Lack of an opvalue is not an error, but will
2494 be ignored during matches and return an empty string in a StdToOp
2495 translation; to specify that a given translation does not exist, the
2496 '0' translation type should be used or the specification should not
2499 <comment> : a comment begins on an empty line with an unescaped !
2500 and continues to the end of the line.
2502 <matchall> : The matchall character is a universal quantifier, meaning
2503 that it symbolizes all possible values of the field where it is used.
2504 The matchall character may occur only in the qualifers side of
2505 a translation specification. Traditionally, the matchall character
2506 has been '*', but because of the semantics of Xrm, if the '*' is used
2507 as the matchall, Xrm does not restrict enumeration as needed.
2509 The matchall character may be followed by a number when the <transtype>
2510 is '>'. When this occurs, the string that matches the matchall
2511 character may be referenced in the <opvalue> by using the sequence
2512 \<number>, as in "\1". The occurance is replaced with the matched
2514 /*=$END$================================================*/
2518 /*========================================================*/
2519 $INTROBEG$: translation specification examples
2520 $1LINER$: examples of _DtXlate translation specifications
2523 !! These are examples of bi-directional straight translations
2524 HP-UX.900-999.setlocale.=.en_US.hp-roman8: american
2525 HP-UX.900-999.setlocale.=.en_US.iso88591: american.iso88591
2526 HP-UX.900-999.setlocale.=.nl_BE.hp-roman8.fold: dutch@fold
2527 HP-UX.900-999.setlocale.=.nl_BE.hp-roman8.nofold: dutch@nofold
2529 !! These are examples of OpToStd translations utilizing regular
2530 !! expression patterns to match the search value.
2531 HP-UX.?.version.<.900: "A\\.09\\..*" !! any HPUX 9.x version
2532 HP-UX.?.version.<.807: "A\\.08\\.07.*"
2533 HP-UX.?.version.<.800: "A\\.08\\..*"
2534 AIX.?.version.<.320: "2 3"
2535 AIX.?.version.<.300: "[0-9] 3"
2536 SunOS.?.version.<.530: "5\\.3.*"
2537 SunOS.?.version.<.500: "5\\..*"
2539 !! These are examples of StdToOp translations utilizing matchall
2540 !! specifiers in the std value to match the search value.
2541 HP-UX.900+.iconv1.>.?.iso88596: arabic8
2542 HP-UX.900+.iconv1.>.?.iso88597: greek8
2543 HP-UX.900+.iconv1.>.?.hp-kana8: kana8
2544 HP-UX.900+.iconv1.>.?.hp-roman8: roman8
2546 !! The following examples use value replacement as part of their
2547 !! specifications. Using this can lead to much sparser tables, but
2548 !! it depends on op-specific and std values sharing the same strings.
2549 HP-UX.900-999.setlocale.<.nl_BE.hp-roman8.?1: [dD][uU][tT][cC][hH]@\\(.*\\)
2550 !HP-UX.900-999.setlocale.<.nl_BE.hp-roman8.?1: dutch@\\(.*\\)
2551 HP-UX.1000+.setlocale.>.?1.hp-roman8: \\1.roman8 !! all non-modif cases
2552 HP-UX.1000+.setlocale.>.?1.hp-roman8.?2: \\1.roman8@\\2 !! all modif cases
2554 /*=$END$================================================*/
2559 /*========================================================*/
2560 $INTROBEG$: _DtXlate example usage
2561 $1LINER$: Examples of how to _DtXlate
2563 #include <XlationSvc.h>
2566 _DtXlateDb db = NULL;
2568 char plat[_DtPLATFORM_MAX_LEN];
2574 #define OPER_YOUROP "myop"
2576 env = getenv("MYPATH");
2577 if (env == NULL) env = ∅
2579 ret = _DtXlateOpenAllDbs(env,"myfile.xlt",&db);
2581 ret = _DtXlateGetXlateEnv(db,plat,&execver,&compver);
2582 printf("Platform: %s\nExec Ver: %d\nComp Ver: %d\n",
2583 plat,execver,compver);
2585 ret = _DtXlateStdToOpValue(db,plat,compver,OPER_YOUROP,
2586 str="en_US.hp-roman8",&val,NULL);
2587 if (ret==0) printf("setlocale(%s) xlation=%s\n", str, val);
2588 else printf("no xlation\n", val);
2590 ret = _DtXlateOpToStdValue(db,plat,execver,OPER_YOUROP,
2591 str="american",&val,NULL);
2592 if (ret==0) printf("setlocale(%s) xlation=%s\n", str, val);
2593 else printf("no xlation\n", val);
2595 ret = _DtXlateCloseDb(&db);
2597 /*=$END$================================================*/