/********************************************************************** * Locale.c,v 3.9VMS 1995/09/25 11:21 wilkinson * * Paul Lindner, University of Minnesota DCS * * Copyright 1994 by the Regents of the University of Minnesota * see the file "Copyright" in the distribution for conditions of use. ********************************************************************** * MODULE: Locale.c * These routines make using the international messages facilities easier. * * This interface could be applied to methods other than X/Open coding * (VMS etc..) ********************************************************************** * Locale.c,v * Revision 3.9VMS 1995/09/25 11:21 wilkinson * Use __VMS instead of VMS as trigger for VMS items; handle initial server * usage of ?locale() functions for VMS. * * Revision 3.9 1994/12/05 22:44:42 lindner * Added VMS code from F. Macrides for specifying the default language * via the GOPHERMSGS_DEFAULT definition in conf.h, for when a series of * languages have been made available by setting the DCL logical * LC_MESSAGES to the * wildcard. * * Added code for specifying the device where shared images of message * files will be found, via the GOPHERMSGS_DEV definition in conf.h. * * Blocked potential ACCVIO's for VMSers who misunderstand how to set up * the messaging and do it wrong. * * Revision 3.8 1994/11/24 08:10:20 lindner * sundry compiler fixes * * Revision 3.7 1994/11/17 06:34:00 lindner * Fixes for VMS internationalization * * Revision 3.6 1994/08/19 16:27:51 lindner * Alan's mega-patch for Locale stuff * * Revision 3.5 1994/07/25 14:00:35 lindner * Add std comments * */ #include "Locale.h" #ifdef GINTERNATIONAL #include "Stdlib.h" #include "String.h" #include "DAarray.h" #include "STRstring.h" #include "fileio.h" #include nl_catd Gcatd = (nl_catd) -1; #ifdef NO_XPGCAT /** if we're not using the X/Open message catalogs, we have to keep track of the locale **/ String *msgLocale = NULL; #endif /* NO_XPGCAT */ /*************** DynArray of messages ***************/ typedef DynArray GtxtArray; GtxtArray *GtxtMsgs = (GtxtArray *) NULL; #define GtxtNew STRnew #define GtxtInit STRinit #define GtxtCopy STRcpy #define GtxtDestroy STRdestroy /*************** Public interfaces ***************/ char * Gtxt (defaultString, msgNumber) char *defaultString; int msgNumber; { String *msgString; if ( (Gcatd == (nl_catd) -1) ) return defaultString; if ( GtxtMsgs != NULL ) { if (DAgetNumitems(GtxtMsgs) < msgNumber) { DAgrow(GtxtMsgs, msgNumber); } msgString = (String *) DAgetEntry(GtxtMsgs, msgNumber - 1); #ifndef NO_XPGCAT if (STRlen(msgString) == 0) { STRset(msgString, catgets(Gcatd, NL_SETD, msgNumber, defaultString)); } #endif if (STRget(msgString) != NULL) return (STRget(msgString)); } #ifdef NO_XPGCAT return defaultString; #else return (catgets(Gcatd, NL_SETD, msgNumber, defaultString)); #endif } #ifdef flags #undef flags #endif nl_catd Gtxtopen (catname, flags) char *catname; int flags; /* not used */ { #ifdef NO_XPGCAT FileIO *fio = NULL; char quotechar = '\0'; char inputline[1024]; #endif /*NO_XPGCAT*/ if (GtxtMsgs != NULL) { DAdestroy(GtxtMsgs); } #ifdef NO_XPGCAT if (strchr(catname,'/') != NULL) { /* file path name */ fio = FIOopenUFS(catname, O_RDONLY, 0); } else if ( (msgLocale != NULL) && (STRlen(msgLocale) > 0) ) { sprintf(inputline, "%s/%s.msg", LOCALEDIR, STRget(msgLocale)); fio = FIOopenUFS(inputline, O_RDONLY, 0); } if (fio != NULL) { GtxtMsgs = (GtxtArray *) DAnew(10, GtxtNew, GtxtInit, GtxtDestroy, GtxtCopy); if (GtxtMsgs == NULL) { FIOclose(fio); Gcatd = -1; return Gcatd; } while (FIOreadline(fio, inputline, sizeof(inputline))) { if (*inputline == '$') { if (strncmp(inputline + 1, "quote ", 6)==0) quotechar = *(inputline + 7); } else if (isdigit(*inputline)) { char *cp, *cp2; int msgNumber; msgNumber = atoi(inputline); if (msgNumber != 0) { if (quotechar != '\0') { cp = strchr(inputline, quotechar); if (cp != NULL) { cp2 = cp++; do { cp2 = strchr(cp2 + 1, quotechar); } while ((cp2 != NULL) && (*(cp2-1) == '\\')); if (cp2 != NULL) *cp2 = '\0'; } } else { cp = inputline; while (isdigit(*cp)) cp++; cp++; /* skip exactly one char after number */ cp2 = cp + strlen(cp); if (*cp2 == '\n') /* strip trailing return */ *cp2 = '\0'; } if (cp != NULL) { if (DAgetNumitems(GtxtMsgs) < msgNumber) { DAgrow(GtxtMsgs, msgNumber); } STRset((String *) DAgetEntry(GtxtMsgs, msgNumber - 1), cp); } } } } FIOclose(fio); Gcatd = 1; /* random positive number */ } else Gcatd = -1; #else Gcatd = catopen(catname, flags); if (Gcatd != (nl_catd) -1) { GtxtMsgs = (GtxtArray *) DAnew(10, GtxtNew, GtxtInit, GtxtDestroy, GtxtCopy); } #endif /* NO_XPGCAT */ return Gcatd; } #ifndef __VMS char * Gtxtlocale(type, str) int type; char *str; { #ifdef NO_XPGCAT # ifdef LC_MESSAGES if ( (type == LC_ALL) || (type == LC_MESSAGES) ) { # else if (type == LC_ALL) { # endif if (*str == '\0') { /* load from LC_MESSAGES or LANG env var */ char *cp; cp = getenv("LC_MESSAGES"); if (cp == NULL) cp = getenv("LANG"); if (cp != NULL) { if (msgLocale == NULL) msgLocale = STRnew(); STRset(msgLocale, str); } } else { if (msgLocale == NULL) msgLocale = STRnew(); STRset(msgLocale, str); } } #endif /* NO_XPGCAT */ #ifndef NO_LOCALE return (setlocale(type,str)); #else if (msgLocale == NULL) return NULL; else return STRget(msgLocale); #endif /* NO_LOCALE */ } #else /* VMS */ #include "[-]conf.h" #include "GDgopherDir.h" #include "GSgopherObj.h" #include #include int GTXT_facility=0; char *GTXT_language; #ifndef GOPHERMSGS_DEFAULT #define GOPHERMSGS_DEFAULT "- none -" #endif /* GOPHERMSGS_DEFAULT */ #ifndef GOPHERMSGS_DEV #define GOPHERMSGS_DEV "GopherP_Dir:.EXE" #endif /* GOPHERMSGS_DEV */ #ifndef VMS_SERVER extern GopherDirObj *setlocale_LangDir; #endif /* ** Emulate catgets() by securing a VMS message */ char * catgets(junk1, junk2, code, msg_default) int junk1; int junk2; int code; char *msg_default; { struct dsc$descriptor_s buf_; static char buf[512]; int i; int x; /* Reconfigure code as VMS error condition */ code = (GTXT_facility<<16) + (code << 3) + 3; code |= 0x08008000; buf_.dsc$b_dtype = DSC$K_DTYPE_T; buf_.dsc$b_class = DSC$K_CLASS_S; buf_.dsc$a_pointer = buf; buf_.dsc$w_length = sizeof(buf); memset(buf,'\0',sizeof(buf)); i = 0; x = SYS$GETMSG(code, &i, &buf_, 1, 0); if ((x & 1) && (x != SS$_MSGNOTFND)) { buf[i] = '\0'; return(buf); } return(msg_default); } /* ** Emulate catopen() by locating and activating a VMS message file */ nl_catd catopen(char *filespec, int junk) { struct dsc$descriptor_s filespec_; struct dsc$descriptor_s symbol_; unsigned long value; int status; $DESCRIPTOR(image_,GOPHERMSGS_DEV); char *file; char *cp; filespec_.dsc$b_dtype = symbol_.dsc$b_dtype = DSC$K_DTYPE_T; filespec_.dsc$b_class = symbol_.dsc$b_class = DSC$K_CLASS_S; if ((cp=strstr(filespec, "GOPHER_MSG")) == NULL) return(SS$_IVLOGNAM); file = (char *)malloc(sizeof(char)*(strlen(cp)+1)); strcpy(file,cp); GTXT_language = strstr(file,"_MSG") + strlen("_MSG"); cp = strrchr(GTXT_language,'.'); if (cp) *cp = '\0'; symbol_.dsc$a_pointer = (char *)malloc(sizeof(char)*(strlen("GOPHER_LANG") +1+strlen(GTXT_language))); strcpy(symbol_.dsc$a_pointer,"GOPHER_LANG"); strcat(symbol_.dsc$a_pointer,GTXT_language); symbol_.dsc$w_length = strlen(symbol_.dsc$a_pointer); filespec_.dsc$a_pointer = file; filespec_.dsc$w_length = strlen(filespec_.dsc$a_pointer); status = LIB$FIND_IMAGE_SYMBOL(&filespec_,&symbol_,&value,&image_); free(symbol_.dsc$a_pointer); free(file); if (status == SS$_NORMAL) { GTXT_facility = value; return( (nl_catd) 1); } else return ( (nl_catd) -1 ); } /* ** This procedure secures the LC_MESSAGES logical or symbol or SYS$LANGUAGE ** system logical and inserts it into the GopherP_Dir:gopher_msg_%s.exe ** filespec. If not defined, "*" is inserted, triggering a wildcard search ** of message files. The filespec is then searched for, and for each ** matching filespec found, the message number 222 is retrieved and inserted ** into a menu list. If no menu list entries are retrieved, Gtxt() is ** disabled, causing the default message to be returned. If only one menu ** list entry is retrieved, the message file it came from is chosen as the ** process level message file and Gtxt() is enabled to read it. If more ** than one menu list entry is retrieved, the menu is offered to the user, ** and the choice they make is set as the process level message file and ** Gtxt() is enabled to read it. */ #include #include void rsetlocale(int facility) { Gcatd = (nl_catd) 1; GTXT_facility = facility; if (GtxtMsgs != NULL) DAdestroy(GtxtMsgs); GtxtMsgs = (GtxtArray *) DAnew(10, GtxtNew, GtxtInit, GtxtDestroy, GtxtCopy); } #ifndef VMS_SERVER void setlocale(char *x, char *y) { int status; int defaultLang = -1; char fname[256], *cp; char command[256]; char iso_language[33]; GopherObj *tmpgs = NULL; static struct dsc$descriptor_s language_ = {0,DSC$K_DTYPE_T, DSC$K_CLASS_S,0}; static struct FAB wild_fab; static struct NAM wild_nam; static char fullname[256]; static char expanded[256]; static char result[256]; iso_language[0] = '\0'; if (getenv("LC_MESSAGES") != NULL) strcpy(iso_language,getenv("LC_MESSAGES")); else { /* Test SYS$LANGUAGE using LIB$GET_USERS_LANGUAGE() */ language_.dsc$w_length = sizeof(iso_language)-1; language_.dsc$a_pointer = iso_language; if (SS$_NORMAL == (status = LIB$GET_USERS_LANGUAGE(&language_))) iso_language[language_.dsc$w_length] = '\0'; else iso_language[0] = '\0'; } while (iso_language[0] != '\0' && iso_language[strlen(iso_language)-1] == ' ') iso_language[strlen(iso_language)-1] = '\0'; if (iso_language[0] == '\0') strcpy(iso_language,"*"); if ((cp=strchr(GOPHERMSGS_DEV, ':')) != NULL) { strcpy(fname, GOPHERMSGS_DEV); sprintf(cp=strchr(fname, ':'), ":gopher_msg_%s.exe", iso_language); } else { sprintf(fname, "GopherP_Dir:gopher_msg_%s.exe", iso_language); } /* Scan for fname; on a hit, activate the image and get menu message */ wild_fab = cc$rms_fab; wild_nam = cc$rms_nam; wild_fab.fab$b_fac = FAB$M_GET; wild_fab.fab$l_fop = FAB$V_NAM; wild_fab.fab$l_nam = &wild_nam; wild_fab.fab$l_dna = fname; wild_fab.fab$b_dns = strlen(wild_fab.fab$l_dna); wild_nam.nam$l_esa = expanded; wild_nam.nam$l_rsa = result; wild_nam.nam$b_ess = wild_nam.nam$b_rss = 255; wild_fab.fab$l_fna = fullname; wild_fab.fab$b_fns = fullname[0] = expanded[0] = result[0] = 0; if ((status = SYS$PARSE(&wild_fab)) != RMS$_NORMAL) return; /* The while loop will hang if wild_fab is invalid */ Gcatd = (nl_catd) 1; /* Always try to get the msg here. */ while (status!=RMS$_NMF && status!=RMS$_FNF) { if ((( status = SYS$SEARCH(&wild_fab)) &1) != 1) continue; result[wild_nam.nam$b_rsl] = '\0'; if ((nl_catd)1 != catopen(result,0)) continue; strcpy(command,Gtxt("",232)); if (strlen(command)) { /* An available language */ if (setlocale_LangDir == NULL) { setlocale_LangDir = GDnew(32); /* 1st language */ GDsetTitle(setlocale_LangDir,""); } tmpgs = GSnew(); /* Store language menu item */ GSsetTitle(tmpgs, command); strcpy(command+1,result); GSsetType(tmpgs, command[0] = A_LANGUAGE); GSsetPath(tmpgs, command); GSsetHost(tmpgs,"0.0.0.0"); GSsetPort(tmpgs,GTXT_facility); GDaddGS(setlocale_LangDir, tmpgs); GSdestroy(tmpgs); if (strcmp(GTXT_language+1,GOPHERMSGS_DEFAULT)==0) { defaultLang = GDgetNumitems(setlocale_LangDir) - 1; } } } Gcatd = (nl_catd) -1; /* By default, never bother trying a message file */ if (setlocale_LangDir) { /* We have one or more available languages */ if (GDgetNumitems(setlocale_LangDir)==1) { status = 0; /* Only one choice */ rsetlocale(GSgetPort(GDgetEntry(setlocale_LangDir,0))); GDdestroy(setlocale_LangDir); setlocale_LangDir = NULL; } else if (defaultLang != -1) /* No choice for now. */ rsetlocale(GSgetPort(GDgetEntry(setlocale_LangDir,defaultLang))); else { /* Two or more choices. */ status = setlocale_screen(); rsetlocale(GSgetPort(GDgetEntry(setlocale_LangDir,status))); } } } #else /* Really chopped down setlocale() for server usage on OpenVMS specialized parameters, too: setlocale(support_directory,lang); This allows us to pass the directory where the GopherD.exe file resides (by passing the pname pulled off the command line) and the default language (specified in the configuration file or by default in the user environment variable LC_MESSAGES). */ void setlocale(char *x, char *y) { int status; char fname[256]; strcpy(fname, x); strcat(fname,"gopherd_msg"); if (y) if (strlen(y)) { strcat(fname,"_"); strcat(fname,y); } strcat(fname,".exe"); if ((nl_catd)1 != catopen(fname,0)) Gcatd = (nl_catd) -1; /* By default, never bother trying a message file */ rsetlocale(GTXT_facility); } #endif void Gtxtlocale(a,b) char *a, *b; { setlocale(a,b); } #endif #endif /* GINTERNATIONAL */ .