/* * Motif Tools Library, Version 3.1 * $Id: XmStringCvt.c,v 1.1.1.1 2001/07/18 11:06:03 root Exp $ * * Written by David Flanagan. * Copyright (c) 1992-2001 by David Flanagan. * All Rights Reserved. See the file COPYRIGHT for details. * This is open source software. See the file LICENSE for details. * There is no warranty for this software. See NO_WARRANTY for details. * * $Log: XmStringCvt.c,v $ * Revision 1.1.1.1 2001/07/18 11:06:03 root * Initial checkin. * * Revision 1.2 2001/06/12 16:25:28 andre * *** empty log message *** * * */ #include #include #include #if 0 /* #if XmVersion >= 2000 */ /** * Gary Merrill figured out how XmString parsing works in Motif 2.0, and * how rendition tables and tabs are handled, and wrote this code for * Motif 2.0. David Flanagan tweaked the resulting code a bit. * * The following escape sequences are supported for strings in the * resource files: * * @t tab (relative to a tab list) * @f[tag] font * @b[tag] begin rendition * @e[tag] end rendition * * Keep in mind that renditions override font specifications. * **/ #if NeedFunctionPrototypes static XmIncludeStatus XmtConvertStringEscape(XtPointer *text, XtPointer text_end, XmTextType type, XmStringTag string_tag, XmParseMapping entry, int pattern_length, XmString *str_include, XtPointer call_data) #else static XmIncludeStatus XmtConvertStringEscape(text, text_end, type, string_tag, entry, pattern_length, str_include, call_data) XtPointer *text; XtPointer text_end; XmTextType type; XmStringTag string_tag; XmParseMapping entry; int pattern_length; XmString *str_include; XtPointer call_data; #endif { char *s, *start, *text_ptr, indicator, *tag, tag_buf[3]; XmStringComponentType component_type; /* printf("...> '%s'\n", (char *) *text); */ text_ptr = (char *) *text; start = s = XtNewString(*text); /* s[0] should be '@'. Bump pointer to following char */ s++; if (*s == '@') { /* Sequence is '@@' */ *str_include = XmStringComponentCreate(XmSTRING_COMPONENT_TEXT, 1, s); text_ptr +=2; *text = text_ptr; XtFree(start); return XmINSERT; } switch (*s) { case 't': component_type = XmSTRING_COMPONENT_TAB; break; case 'f': /* * treat @f the same as an unterminated @b. * Using XmSTRING_COMPONENT_TAG doesn't work quite right * with Motif 2.0.0, so we do it this way, which seems * to make as much sense, anyway. */ case 'b': component_type = XmSTRING_COMPONENT_RENDITION_BEGIN; break; case 'e': component_type = XmSTRING_COMPONENT_RENDITION_END; break; default: component_type = XmSTRING_COMPONENT_UNKNOWN; break; } indicator = *s; switch (component_type) { case XmSTRING_COMPONENT_UNKNOWN: if ( indicator == '{' ) XmtWarningMsg("XmtCreateXmString", "badlocale", "'@{' locale indicator may occur only at beginning of string."); XmtWarningMsg("XmtCreateXmString", "unrecognized", "Unrecognized string escape sequence '@%c' will be treated as text.", indicator); s++; *str_include = XmStringComponentCreate(XmSTRING_COMPONENT_TEXT, 2, start); text_ptr += 2; *text = text_ptr; XtFree(start); return XmINSERT; break; case XmSTRING_COMPONENT_TAB: *str_include = XmStringComponentCreate(component_type, 0, NULL); s++; text_ptr += s - start; *text = text_ptr; XtFree(start); return XmINSERT; break; default: /* just drop through */ break; } s++; /* go past the component_type character */ if (*s == '\0') { XmtWarningMsg("XmtCreateXmString", "syntax1", "Improper '@%c' syntax in string being converted.", indicator); XtFree(start); return XmTERMINATE; } /* * Now get the tag in '[ ]', after '(', or immediately * after the component_type indicator. */ switch (*s) { case '[': s = tag = s+1; while (*s && (*s != ']')) s++; if (*s == '\0') { XmtWarningMsg("XmtCreateXmString", "syntax3", "'@%c[%s' is missing ']' in string being converted", indicator, tag); break; } *s = '\0'; /* null terminate the tag string */ s++; break; case '(': if (!*(s+1) || !*(s+2)) { XmtWarningMsg("XmtCreateXmString", "syntax2", "Improper '@%c(' syntax in string being converted.", indicator); XtFree(start); return XmTERMINATE; } tag_buf[0] = *(s+1); tag_buf[1] = *(s+2); tag_buf[2] = '\0'; tag = tag_buf; s += 3; break; default: tag_buf[0] = *s; tag_buf[1] = '\0'; s++; tag = tag_buf; break; } *str_include = XmStringComponentCreate(component_type, strlen(tag), tag); text_ptr += s - start; *text = text_ptr; XtFree(start); return XmINSERT; } #if NeedFunctionPrototypes XmString XmtCreateXmString(StringConst str) #else XmString XmtCreateXmString(str) StringConst str; #endif { static Boolean parse_table_registered = False; static XmParseMapping parse_table[3]; if (!parse_table_registered) { Arg args[4]; int n; n = 0; XtSetArg(args[n], XmNpattern, "\n"); n++; XtSetArg(args[n], XmNpatternType, XmMULTIBYTE_TEXT); n++; XtSetArg(args[n], XmNincludeStatus, XmINSERT); n++; XtSetArg(args[n], XmNsubstitute,XmStringSeparatorCreate());n++; parse_table[0] = XmParseMappingCreate(args, n); n = 0; XtSetArg(args[n], XmNpattern, "\t"); n++; XtSetArg(args[n], XmNpatternType, XmMULTIBYTE_TEXT); n++; XtSetArg(args[n], XmNincludeStatus, XmINSERT); n++; XtSetArg(args[n], XmNsubstitute, XmStringComponentCreate(XmSTRING_COMPONENT_TAB, 0,NULL)); n++; parse_table[1] = XmParseMappingCreate(args, n); n = 0; XtSetArg(args[n], XmNpattern, "@"); n++; XtSetArg(args[n], XmNpatternType, XmMULTIBYTE_TEXT); n++; XtSetArg(args[n], XmNincludeStatus, XmINVOKE); n++; XtSetArg(args[n], XmNinvokeParseProc, XmtConvertStringEscape); n++; parse_table[2] = XmParseMappingCreate(args, n); parse_table_registered = True; } return XmStringParseText((XtPointer) str, NULL, NULL, XmMULTIBYTE_TEXT, parse_table, XtNumber(parse_table), NULL); } #else /* XmVersion < 2000 */ #if NeedFunctionPrototypes static XmString appendstring(String txt, XmString to, int sep, char *charset, int fixup) #else static XmString appendstring(txt, to, sep, charset, fixup) String txt; XmString to; int sep; char *charset; int fixup; #endif { #if 0 XmString s1, s2; char *mtxt = NULL; if (fixup) { wchar_t *s, *t; wchar_t *ws = NULL; int n; n = mbstowcs(NULL, txt, 0); if (n>0) { ws = (wchar_t*)malloc(sizeof(wchar_t)*(n+1)); } if (ws) { mbstowcs(ws, txt, (n+1)); } for(s=t=ws; *s; s++, t++) { *t = *s; if ((*s == L'@') && (*(s+1) == L'@')) s++; } *t = *s; /* copy the terminating '\0' */ n = wcstombs(NULL, ws, 0); if (n > 0) { mtxt = (char*)malloc(sizeof(char)*(n+1)); } if (mtxt) { wcstombs(mtxt, ws, (n+1)); } else { mtxt = strdup(txt); } XtFree((char*)ws); } s1 = XmStringSegmentCreate(mtxt, charset, XmSTRING_DIRECTION_L_TO_R, sep); if (!to) return s1; s2 = XmStringConcat(to, s1); XmStringFree(to); XmStringFree(s1); XtFree(mtxt); return s2; #else XmString s1, s2; char *s, *t; if (fixup) { for(s=t=txt; *s; s++, t++) { *t = *s; if ((*s == '@') && (*(s+1) == '@')) s++; } *t = *s; /* copy the terminating '\0' */ } s1 = XmStringSegmentCreate(txt, charset, XmSTRING_DIRECTION_L_TO_R, sep); if (!to) return s1; s2 = XmStringConcat(to, s1); XmStringFree(to); XmStringFree(s1); return s2; #endif } #if NeedFunctionPrototypes XmString XmtCreateXmString(StringConst str) #else XmString XmtCreateXmString(str) StringConst str; #endif { #if 0 String r, s, t; #ifdef XMSTRING_TO_COMPOUND_TEXT_BUG String charset = XmSTRING_DEFAULT_CHARSET; #else # if XmVersion < 1002 String charset = XmSTRING_DEFAULT_CHARSET; # else String charset = XmFONTLIST_DEFAULT_TAG; # endif #endif char charset_buf[3]; XmString result = NULL; Boolean fixup = False; if (!str) return NULL; else if (!*str) return XmStringSegmentCreate((String)str, charset, XmSTRING_DIRECTION_L_TO_R, False); /* * make a copy of the string so we can frob with it * We keep pointer r so we can free it when done */ r = s = XtNewString(str); for(t = s; *s; s++) { switch(*s) { case '\n': *s = '\0'; /* null terminate the string */ result = appendstring(t, result, True, charset, fixup); fixup = False; t = s+1; break; case '@': if ((*s == '@') && (*(s+1) == '@')) { /* set a flag to strip doubled escapes later */ fixup = True; s++; break; } else if (*(s+1) != 'f') break; /* its a font change, so add the string up to here, if any */ *s = '\0'; /* null terminate the string */ if (s != t) result = appendstring(t, result, False, charset, fixup); fixup = False; /* and now get the new charset */ if (*(s+2) == '\0') break; s+=2; if (*s == '[') { /* read till close ']' */ s = charset = s+1; while (*s && (*s != ']')) s++; if (*s == '\0') break; *s = '\0'; /* null-terminate the charset string */ } else if (*s == '(') { /* charset is next 2 chars */ if (*(s+1)) s++; else break; charset_buf[0] = *s; if (*(s+1)) s++; else break; charset_buf[1] = *s; charset_buf[2] = '\0'; charset = charset_buf; } else if (*s) { /* charset is single current character */ charset_buf[0] = *s; charset_buf[1] = '\0'; charset = charset_buf; } t = s+1; break; } } if (s != t) result = appendstring(t, result, False, charset, fixup); XtFree(r); return result; #else String r, s, t; #ifdef XMSTRING_TO_COMPOUND_TEXT_BUG String charset = XmSTRING_DEFAULT_CHARSET; #else # if XmVersion < 1002 String charset = XmSTRING_DEFAULT_CHARSET; # else String charset = XmFONTLIST_DEFAULT_TAG; # endif #endif char charset_buf[3]; XmString result = NULL; Boolean fixup = False; if (!str) return NULL; else if (!*str) return XmStringSegmentCreate((String)str, charset, XmSTRING_DIRECTION_L_TO_R, False); /* * make a copy of the string so we can frob with it * We keep pointer r so we can free it when done */ r = s = XtNewString(str); for(t = s; *s; s++) { switch(*s) { case '\n': *s = '\0'; /* null terminate the string */ result = appendstring(t, result, True, charset, fixup); fixup = False; t = s+1; break; case '@': if ((*s == '@') && (*(s+1) == '@')) { /* set a flag to strip doubled escapes later */ fixup = True; s++; break; } else if (*(s+1) != 'f') break; /* its a font change, so add the string up to here, if any */ *s = '\0'; /* null terminate the string */ if (s != t) result = appendstring(t, result, False, charset, fixup); fixup = False; /* and now get the new charset */ if (*(s+2) == '\0') break; s+=2; if (*s == '[') { /* read till close ']' */ s = charset = s+1; while (*s && (*s != ']')) s++; if (*s == '\0') break; *s = '\0'; /* null-terminate the charset string */ } else if (*s == '(') { /* charset is next 2 chars */ if (*(s+1)) s++; else break; charset_buf[0] = *s; if (*(s+1)) s++; else break; charset_buf[1] = *s; charset_buf[2] = '\0'; charset = charset_buf; } else if (*s) { /* charset is single current character */ charset_buf[0] = *s; charset_buf[1] = '\0'; charset = charset_buf; } t = s+1; break; } } if (s != t) result = appendstring(t, result, False, charset, fixup); XtFree(r); return result; #endif /* return XmStringCreateLocalized(str); */ } #endif /* XmVersion >= 2000 */ /* ARGSUSED */ #if NeedFunctionPrototypes static XmString XmtCreateLocalizedXmString_(Screen *screen, StringConst str) #else static XmString XmtCreateLocalizedXmString_(screen, str) Screen* screen; StringConst str; #endif { XmString value = NULL; String category, tag, defaultstr; String free_me = NULL; String s = NULL; #if NeedFunctionPrototypes extern String _XmtLocalize(Screen *, StringConst,StringConst,StringConst); #else extern String _XmtLocalize(); #endif if (!str) return NULL; /* printf("==> '%s'\n", str); */ /* if this string has a tag, localize it first */ if ((str[0] == '@') && (str[1] == '{')) { s = XtNewString(str); free_me = s; s += 2; /* printf("=-> '%s'\n", s); */ category = NULL; tag = NULL; defaultstr = s; while(*s) { if (*s == '.' && !category) { *s = '\0'; category = defaultstr; defaultstr = s+1; } if (*s == '.' && !tag) { *s = '\0'; tag = defaultstr; defaultstr = s+1; } if (*s == '}') { *s = '\0'; s++; break; } s++; /* printf("-=> '%s'\n", free_me+2); */ } if (!tag) tag = defaultstr; if (!tag[0]) goto error; if (category && !category[0]) goto error; s = _XmtLocalize(screen, defaultstr, category, tag); } else { s = (String)str; } /* printf("--> '%s'\n", s); */ value = XmtCreateXmString(s); if (!value) goto error; if (free_me) XtFree(free_me); return value; error: if (free_me) XtFree(free_me); return NULL; } /* ARGSUSED */ #if NeedFunctionPrototypes static void FreeConvertedXmString(XtAppContext app, XrmValue *to, XtPointer closure, XrmValue *args, Cardinal *num_args) #else static void FreeConvertedXmString(app, to, closure, args, num_args) XtAppContext app; XrmValue *to; XtPointer closure; XrmValue *args; Cardinal *num_args; #endif { XmStringFree(*((XmString *) to->addr)); } /* ARGSUSED */ #if NeedFunctionPrototypes Boolean XmtConvertStringToXmString(Display *dpy, XrmValue *args, Cardinal *num_args, XrmValue *from, XrmValue *to, XtPointer *converter_data) #else Boolean XmtConvertStringToXmString(dpy, args, num_args, from, to, converter_data) Display *dpy; XrmValue *args; Cardinal *num_args; XrmValue *from; XrmValue *to; XtPointer *converter_data; #endif { String s = (String) from->addr; Screen *screen = *(Screen **)args[0].addr; XmString value; value = XmtCreateLocalizedXmString_(screen, s); if (!value) goto error; done(XmString, value); error: XtDisplayStringConversionWarning(dpy, (String)from->addr, XmRXmString); return False; } /* ARGSUSED */ #if NeedFunctionPrototypes XmString XmtCreateLocalizedXmString(Widget w, StringConst s) #else XmString XmtCreateLocalizedXmString(w, s) Widget w; StringConst s; #endif { return XmtCreateLocalizedXmString_(XtScreen(w), s); } #if NeedFunctionPrototypes void XmtRegisterXmStringConverter(void) #else void XmtRegisterXmStringConverter() #endif { static Boolean registered = False; if (!registered) { XtSetTypeConverter(XtRString, XmRXmString, XmtConvertStringToXmString, (XtConvertArgRec *)screenConvertArg, (Cardinal) 1, XtCacheAll | XtCacheRefCount, FreeConvertedXmString); registered = True; } }