/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* lcDB.c 1.3 - Fujitsu source for CDEnext 96/02/29 18:02:53 */ /* $XConsortium: _fallcDB.c /main/1 1996/04/08 15:16:07 cde-fuj $ */ /* * * Copyright IBM Corporation 1993 * * All Rights Reserved * * License to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation, and that the name of IBM not be * used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING * ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS, AND * NONINFRINGEMENT OF THIRD PARTY RIGHTS, IN NO EVENT SHALL * IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * */ #include "syncx.h" #include #include "_fallibint.h" #include "_fallcPubI.h" /* specifying NOT_X_ENV allows users to just use the database parsing routine. */ /* For UDC/VW */ #ifndef BUFSIZE #define BUFSIZE 2048 #endif #ifdef COMMENT #ifdef BUFSIZE #undef BUFSIZE #endif #define BUFSIZE 6144 /* 2048*3 */ #endif #include typedef struct _DatabaseRec { char *category; char *name; char **value; int value_num; struct _DatabaseRec *next; } DatabaseRec, *Database; typedef enum { S_NULL, /* outside category */ S_CATEGORY, /* inside category */ S_NAME, /* has name, expecting values */ S_VALUE } ParseState; typedef enum { T_NEWLINE, T_COMMENT, T_SEMICOLON, T_DOUBLE_QUOTE, T_LEFT_BRACE, T_RIGHT_BRACE, T_SPACE, T_TAB, T_BACKSLASH, T_NUMERIC_HEX, T_NUMERIC_DEC, T_NUMERIC_OCT, T_DEFAULT } Token; typedef struct { Token token; /* token id */ char *name; /* token sequence */ int len; /* length of token sequence */ int (*parse_proc)(); /* parsing procedure */ } TokenTable; static int f_newline(); static int f_comment(); static int f_semicolon(); static int f_double_quote(); static int f_left_brace(); static int f_right_brace(); static int f_white(); static int f_backslash(); static int f_numeric(); static int f_default(); static TokenTable token_tbl[] = { { T_NEWLINE, "\n", 1, f_newline }, { T_COMMENT, "#", 1, f_comment }, { T_SEMICOLON, ";", 1, f_semicolon }, { T_DOUBLE_QUOTE, "\"", 1, f_double_quote }, { T_LEFT_BRACE, "{", 1, f_left_brace }, { T_RIGHT_BRACE, "}", 1, f_right_brace }, { T_SPACE, " ", 1, f_white }, { T_TAB, "\t", 1, f_white }, { T_BACKSLASH, "\\", 1, f_backslash }, { T_NUMERIC_HEX, "\\x", 2, f_numeric }, { T_NUMERIC_DEC, "\\d", 2, f_numeric }, { T_NUMERIC_OCT, "\\o", 2, f_numeric }, { T_DEFAULT, " ", 1, f_default }, /* any character */ 0 }; #define SYM_NEWLINE '\n' #define SYM_COMMENT '#' #define SYM_SEMICOLON ';' #define SYM_DOUBLE_QUOTE '"' #define SYM_LEFT_BRACE '{' #define SYM_RIGHT_BRACE '}' #define SYM_SPACE ' ' #define SYM_TAB '\t' #define SYM_BACKSLASH '\\' /************************************************************************/ #define MAX_NAME_NEST 64 typedef struct { ParseState pre_state; char *category; char *name[MAX_NAME_NEST]; int nest_depth; char **value; int value_len; int value_num; int bufsize; /* bufMaxSize >= bufsize >= 0 */ int bufMaxSize; /* default : BUFSIZE */ char *buf; } DBParseInfo; static DBParseInfo parse_info; static void init_parse_info(void) { static int first = 1; char *ptr; int size; if(first == 1){ bzero(&parse_info, sizeof(DBParseInfo)); parse_info.buf = (char *)Xmalloc(BUFSIZE); parse_info.bufMaxSize = BUFSIZE; first = 0; return ; } ptr = parse_info.buf; size = parse_info.bufMaxSize; bzero(&parse_info, sizeof(DBParseInfo)); parse_info.buf = ptr; parse_info.bufMaxSize = size; } static void clear_parse_info(void) { int i; char *ptr; int size; parse_info.pre_state = S_NULL; if(parse_info.category != NULL){ Xfree(parse_info.category); } for(i = 0; i <= parse_info.nest_depth; ++i){ if(parse_info.name[i]){ Xfree(parse_info.name[i]); } } if(parse_info.value){ if(*parse_info.value){ Xfree(*parse_info.value); } Xfree((char *)parse_info.value); } ptr = parse_info.buf; size = parse_info.bufMaxSize; bzero(&parse_info, sizeof(DBParseInfo)); parse_info.buf = ptr; parse_info.bufMaxSize = size; } static Bool realloc_parse_info(int len) { char *p; parse_info.bufMaxSize = BUFSIZE * ((parse_info.bufsize + len)/BUFSIZE + 1); p = (char *)Xrealloc(parse_info.buf, parse_info.bufMaxSize); if(p == NULL){ return(False); } parse_info.buf = p; return(True); } /************************************************************************/ typedef struct _Line { char *str; int cursize; int maxsize; int seq; } Line; static void free_line(Line *line) { if(line->str != NULL){ Xfree(line->str); } bzero(line, sizeof(Line)); } static int realloc_line(Line *line, int size) { char *str = line->str; if(str != NULL){ str = (char *)Xrealloc(str, size); }else{ str = (char *)Xmalloc(size); } if(str == NULL){ /* malloc error */ bzero(line, sizeof(Line)); return 0; } line->str = str; line->maxsize = size; return 1; } #define iswhite(ch) ((ch) == SYM_SPACE || (ch) == SYM_TAB) static void zap_comment(char *str, int *quoted) { char *p = str; while(*p){ if(*p == SYM_DOUBLE_QUOTE){ if(p == str || p[-1] != SYM_BACKSLASH){ /* unescaped double quote changes quoted state. */ *quoted = *quoted ? 0 : 1; } } if(*p == SYM_COMMENT && !*quoted){ int pos = p - str; if(pos == 0 || iswhite(p[-1]) && (pos == 1 || p[-2] != SYM_BACKSLASH)){ int len = strlen(p); if(len > 0 && p[len - 1] == SYM_NEWLINE){ /* newline is the identifier for finding end of value. therefore, it should not be removed. */ *p++ = SYM_NEWLINE; } *p = '\0'; break; } } ++p; } } static int read_line(FILE *fd, Line *line) { char buf[BUFSIZE], *p; int len; int quoted = 0; /* quoted by double quote? */ char *str; int cur; str = line->str; cur = line->cursize = 0; while((p = fgets(buf, BUFSIZE, fd)) != NULL){ ++line->seq; zap_comment(p, "ed); /* remove comment line */ len = strlen(p); if(len == 0){ if(cur > 0){ break; } continue; } if(cur + len + 1 > line->maxsize){ /* need to reallocate buffer. */ if(! realloc_line(line, line->maxsize + BUFSIZE)){ return -1; /* realloc error. */ } str = line->str; } strncpy(str + cur, p, len); cur += len; str[cur] = '\0'; if(!quoted){ if(cur > 1 && str[cur - 2] == SYM_BACKSLASH && str[cur - 1] == SYM_NEWLINE){ /* the line is ended backslash followed by newline. need to concatinate the next line. */ cur -= 2; str[cur] = '\0'; }else{ break; } } } if(quoted){ /* error. still in quoted state. */ return -1; } return line->cursize = cur; } /************************************************************************/ static Token get_token(char *str) { switch(*str){ case SYM_NEWLINE: return T_NEWLINE; case SYM_COMMENT: return T_COMMENT; case SYM_SEMICOLON: return T_SEMICOLON; case SYM_DOUBLE_QUOTE: return T_DOUBLE_QUOTE; case SYM_LEFT_BRACE: return T_LEFT_BRACE; case SYM_RIGHT_BRACE: return T_RIGHT_BRACE; case SYM_SPACE: return T_SPACE; case SYM_TAB: return T_TAB; case SYM_BACKSLASH: switch(str[1]){ case 'x': return T_NUMERIC_HEX; case 'd': return T_NUMERIC_DEC; case 'o': return T_NUMERIC_OCT; } return T_BACKSLASH; default: return T_DEFAULT; } } static int get_word(char *str, char *word) { char *p = str, *w = word; Token token; int token_len; while(*p != '\0'){ token = get_token(p); token_len = token_tbl[token].len; if(token == T_BACKSLASH){ p += token_len; if(*p == '\0'){ break; } token = get_token(p); token_len = token_tbl[token].len; }else if(token != T_COMMENT && token != T_DEFAULT){ break; } strncpy(w, p, token_len); p += token_len; w += token_len; } *w = '\0'; return p - str; /* return number of scanned chars */ } static int get_quoted_word(char *str, char *word) { char *p = str, *w = word; Token token; int token_len; if(*p == SYM_DOUBLE_QUOTE){ ++p; } while(*p != '\0'){ token = get_token(p); token_len = token_tbl[token].len; if(token == T_DOUBLE_QUOTE){ p += token_len; *w = '\0'; return p - str; } if(token == T_BACKSLASH){ p += token_len; if(*p == '\0'){ break; } token = get_token(p); token_len = token_tbl[token].len; } strncpy(w, p, token_len); p += token_len; w += token_len; } /* error. cannot detect next double quote */ return 0; } /************************************************************************/ static int append_value_list(void) { char **value_list = parse_info.value; char *value = NULL; int value_num = parse_info.value_num; int value_len = parse_info.value_len; char *str = parse_info.buf; int len = parse_info.bufsize; char *p; if(len < 1){ return 1; /* return with no error */ } if(value_list == (char **)NULL){ value_list = (char **)Xmalloc(sizeof(char *) * 2); *value_list = NULL; }else{ value_list = (char **) Xrealloc(value_list, sizeof(char *) * (value_num + 2)); } if(value_list == (char **)NULL){ goto err; } value = *value_list; if(value == NULL){ value = (char *)Xmalloc(value_len + len + 1); }else{ value = (char *)Xrealloc(value, value_len + len + 1); } if(value == NULL){ goto err; } if(value != *value_list){ int delta, i; delta = value - *value_list; *value_list = value; for(i = 1; i < value_num; ++i){ value_list[i] += delta; } } value_list[value_num] = p = &value[value_len]; value_list[value_num + 1] = NULL; strncpy(p, str, len); p[len] = 0; parse_info.value = value_list; parse_info.value_num = value_num + 1; parse_info.value_len = value_len + len + 1; parse_info.bufsize = 0; return 1; err: if(value_list){ Xfree((char **)value_list); } Xfree(value); parse_info.value = (char **)NULL; parse_info.value_num = 0; parse_info.value_len = 0; parse_info.bufsize = 0; return 0; } static int construct_name(char *name) { int i, len = 0; char *p = name; for(i = 0; i <= parse_info.nest_depth; ++i){ len += strlen(parse_info.name[i]) + 1; } strcpy(p, parse_info.name[0]); p += strlen(parse_info.name[0]); for(i = 1; i <= parse_info.nest_depth; ++i){ *p++ = '.'; strcpy(p, parse_info.name[i]); p += strlen(parse_info.name[i]); } return *name != '\0'; } static int store_to_database(Database *db) { Database new = (Database)NULL; char name[BUFSIZE]; while(1){ if(parse_info.pre_state == S_VALUE){ if(! append_value_list()){ break; } } if(parse_info.name[parse_info.nest_depth] == NULL){ break; } new = (Database)Xmalloc(sizeof(DatabaseRec)); if(new == (Database)NULL){ break; } bzero(new, sizeof(DatabaseRec)); new->category = (char *)Xmalloc(strlen(parse_info.category) + 1); if(new->category == NULL){ break; } strcpy(new->category, parse_info.category); if(! construct_name(name)){ break; } new->name = (char *)Xmalloc(strlen(name) + 1); if(new->name == NULL){ break; } strcpy(new->name, name); new->next = *db; new->value = parse_info.value; new->value_num = parse_info.value_num; *db = new; Xfree(parse_info.name[parse_info.nest_depth]); parse_info.name[parse_info.nest_depth] = NULL; parse_info.value = (char **)NULL; parse_info.value_num = 0; parse_info.value_len = 0; return 1; } if(new){ if(new->category){ Xfree(new->category); } if(new->name){ Xfree(new->name); } Xfree(new); } if(parse_info.value){ if(*parse_info.value){ Xfree(*parse_info.value); } Xfree((char **)parse_info.value); parse_info.value = (char **)NULL; parse_info.value_num = 0; parse_info.value_len = 0; } return 0; } #define END_MARK "END" #define END_MARK_LEN 3 /*strlen(END_MARK)*/ static int check_category_end(char *str) { char *p; int len; p = str; if(strncmp(p, END_MARK, END_MARK_LEN)){ return 0; } p += END_MARK_LEN; while(iswhite(*p)){ ++p; } len = strlen(parse_info.category); if(strncmp(p, parse_info.category, len)){ return 0; } p += len; return p - str; } /************************************************************************/ static int f_newline(char *str, Token token, Database *db) { switch(parse_info.pre_state){ case S_NULL: case S_CATEGORY: break; case S_NAME: return 0; /* no value */ case S_VALUE: if(!store_to_database(db)){ return 0; } parse_info.pre_state = S_CATEGORY; break; default: return 0; } return token_tbl[token].len; } static int f_comment(char *str, Token token, Database *db) { /* NOTE: comment is already handled in read_line(), so this function is not necessary. */ char *p = str; while(*p != SYM_NEWLINE && *p != '\0'){ ++p; /* zap to the end of line */ } return p - str; } static int f_white(char *str, Token token, Database *db) { char *p = str; while(iswhite(*p)){ ++p; } return p - str; } static int f_semicolon(char *str, Token token, Database *db) { switch(parse_info.pre_state){ case S_NULL: case S_CATEGORY: case S_NAME: return 0; case S_VALUE: if(! append_value_list()){ return 0; } parse_info.pre_state = S_VALUE; break; default: return 0; } return token_tbl[token].len; } static int f_left_brace(char *str, Token token, Database *db) { switch(parse_info.pre_state){ case S_NULL: case S_CATEGORY: return 0; case S_NAME: if(parse_info.name[parse_info.nest_depth] == NULL || parse_info.nest_depth + 1 > MAX_NAME_NEST){ return 0; } ++parse_info.nest_depth; parse_info.pre_state = S_CATEGORY; break; case S_VALUE: default: return 0; } return token_tbl[token].len; } static int f_right_brace(char *str, Token token, Database *db) { if(parse_info.nest_depth < 1){ return 0; } switch(parse_info.pre_state){ case S_NULL: case S_NAME: return 0; case S_VALUE: if(! store_to_database(db)){ return 0; } /* fall into next case */ case S_CATEGORY: if(parse_info.name[parse_info.nest_depth] != NULL){ Xfree(parse_info.name[parse_info.nest_depth]); parse_info.name[parse_info.nest_depth] = NULL; } --parse_info.nest_depth; parse_info.pre_state = S_CATEGORY; break; default: return 0; } return token_tbl[token].len; } static int f_double_quote(char *str, Token token, Database *db) { char word[BUFSIZE]; int len = 0; switch(parse_info.pre_state){ case S_NULL: case S_CATEGORY: return 0; case S_NAME: case S_VALUE: len = get_quoted_word(str, word); if(len < 1){ return 0; } if( (parse_info.bufsize + (int)strlen(word) +1) >= parse_info.bufMaxSize){ if(realloc_parse_info(strlen(word) +1) == False){ return 0; } } strcpy(&parse_info.buf[parse_info.bufsize], word); parse_info.bufsize += strlen(word); parse_info.pre_state = S_VALUE; break; default: return 0; } return len; /* including length of token */ } static int f_backslash(char *str, Token token, Database *db) { return f_default(str, token, db); } static int f_numeric(char *str, Token token, Database *db) { char word[BUFSIZE], *p; int len; int token_len; switch(parse_info.pre_state){ case S_NULL: case S_CATEGORY: return 0; case S_NAME: case S_VALUE: token_len = token_tbl[token].len; p = str + token_len; len = get_word(p, word); if(len < 1){ return 0; } if( (parse_info.bufsize + token_len + (int)strlen(word) +1) >= parse_info.bufMaxSize){ if(realloc_parse_info(token_len + strlen(word) +1) == False){ return 0; } } strncpy(&parse_info.buf[parse_info.bufsize], str, token_len); strcpy(&parse_info.buf[parse_info.bufsize + token_len], word); parse_info.bufsize += token_len + strlen(word); parse_info.pre_state = S_VALUE; break; default: return 0; } return len + token_len; } static int f_default(char *str, Token token, Database *db) { char word[BUFSIZE], *p; int len; len = get_word(str, word); if(len < 1){ return 0; } switch(parse_info.pre_state){ case S_NULL: if(parse_info.category != NULL){ return 0; } p = (char *)Xmalloc(strlen(word) + 1); if(p == NULL){ return 0; } strcpy(p, word); parse_info.category = p; parse_info.pre_state = S_CATEGORY; break; case S_CATEGORY: if(parse_info.nest_depth == 0){ if(check_category_end(str)){ /* end of category is detected. clear context and zap to end of this line */ clear_parse_info(); len = strlen(str); break; } } p = (char *)Xmalloc(strlen(word) + 1); if(p == NULL){ return 0; } strcpy(p, word); if(parse_info.name[parse_info.nest_depth] != NULL){ Xfree(parse_info.name[parse_info.nest_depth]); } parse_info.name[parse_info.nest_depth] = p; parse_info.pre_state = S_NAME; break; case S_NAME: case S_VALUE: if( (parse_info.bufsize + (int)strlen(word) +1 ) >= parse_info.bufMaxSize){ if(realloc_parse_info(strlen(word) +1) == False){ return 0; } } strcpy(&parse_info.buf[parse_info.bufsize], word); parse_info.bufsize += strlen(word); parse_info.pre_state = S_VALUE; break; default: return 0; } return len; } /************************************************************************/ #ifdef DEBUG static void PrintDatabase(Database db) { Database p = db; int i = 0, j; printf("***\n*** BEGIN Database\n***\n"); while(p){ printf("%3d: ", i++); printf("%s, %s, ", p->category, p->name); printf("\t[%d: ", p->value_num); for(j = 0; j < p->value_num; ++j){ printf("%s, ", p->value[j]); } printf("]\n"); p = p->next; } printf("***\n*** END Database\n***\n"); } #endif static void DestroyDatabase(Database db) { Database p = db; while(p){ if(p->category != NULL){ Xfree(p->category); } if(p->name != NULL){ Xfree(p->name); } if(p->value != (char **)NULL){ if(*p->value != NULL){ Xfree(*p->value); } Xfree((char *)p->value); } db = p->next; Xfree((char *)p); p = db; } } static int CountDatabase(Database db) { Database p = db; int cnt = 0; while(p){ ++cnt; p = p->next; } return cnt; } static Database CreateDatabase(char *dbfile) { Database db = (Database)NULL; FILE *fd; Line line; char *p; Token token; int token_len; int len; int error = 0; fd = fopen(dbfile, "r"); if(fd == (FILE *)NULL){ return NULL; } bzero(&line, sizeof(Line)); init_parse_info(); do { int rc = read_line(fd, &line); if(rc < 0){ error = 1; break; }else if(rc == 0){ break; } p = line.str; while(*p){ token = get_token(p); len = (*token_tbl[token].parse_proc)(p, token, &db); if(len < 1){ error = 1; break; } p += len; } } while (!error); if(parse_info.pre_state != S_NULL){ clear_parse_info(); error = 1; } if(error){ #ifdef DEBUG fprintf(stderr, "database format error at line %d.\n", line.seq); #endif DestroyDatabase(db); db = (Database)NULL; } fclose(fd); free_line(&line); #ifdef DEBUG PrintDatabase(db); #endif return db; } /************************************************************************/ /* locale framework functions */ typedef struct _XlcDatabaseRec { XrmQuark category_q; XrmQuark name_q; Database db; struct _XlcDatabaseRec *next; } XlcDatabaseRec, *XlcDatabase; typedef struct _XlcDatabaseListRec { XrmQuark name_q; XlcDatabase lc_db; Database database; int ref_count; struct _XlcDatabaseListRec *next; } XlcDatabaseListRec, *XlcDatabaseList; /* database cache list (per file) */ static XlcDatabaseList _db_list = (XlcDatabaseList)NULL; /************************************************************************/ /* _fallcGetResource(lcd, category, class, value, count) */ /*----------------------------------------------------------------------*/ /* This function retrieves XLocale database information. */ /************************************************************************/ void _fallcGetResource( XLCd lcd, char *category, char *class, char ***value, int *count) { XLCdPublicMethodsPart *methods = XLC_PUBLIC_METHODS(lcd); (*methods->get_resource)(lcd, category, class, value, count); return; } /************************************************************************/ /* _fallcGetLocaleDataBase(lcd, category, class, value, count) */ /*----------------------------------------------------------------------*/ /* This function retrieves XLocale database information. */ /************************************************************************/ void _fallcGetLocaleDataBase( XLCd lcd, char *category, char *name, char ***value, int *count) { XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db); XrmQuark category_q, name_q; category_q = falrmStringToQuark(category); name_q = falrmStringToQuark(name); for(; lc_db->db; ++lc_db){ if(category_q == lc_db->category_q && name_q == lc_db->name_q){ *value = lc_db->db->value; *count = lc_db->db->value_num; return; } } *value = (char **)NULL; *count = 0; } /************************************************************************/ /* _fallcDestroyLocaleDataBase(lcd) */ /*----------------------------------------------------------------------*/ /* This function destroy the XLocale Database that bound to the */ /* specified lcd. If the XLocale Database is referred from some */ /* other lcd, this function just decreases reference count of */ /* the database. If no locale refers the database, this function */ /* remove it from the cache list and free work area. */ /************************************************************************/ void _fallcDestroyLocaleDataBase(XLCd lcd) { XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db); XlcDatabaseList p, prev; for(p = _db_list, prev = (XlcDatabaseList)NULL; p; prev = p, p = p->next){ if(p->lc_db == lc_db){ if((-- p->ref_count) < 1){ if(p->lc_db != (XlcDatabase)NULL){ Xfree((char *)p->lc_db); } DestroyDatabase(p->database); if(prev == (XlcDatabaseList)NULL){ _db_list = p->next; }else{ prev->next = p->next; } Xfree((char*)p); } break; } } XLC_PUBLIC(lcd, xlocale_db) = (XPointer)NULL; } /************************************************************************/ /* _fallcCreateLocaleDataBase(lcd) */ /*----------------------------------------------------------------------*/ /* This function create an XLocale database which correspond to */ /* the specified XLCd. */ /************************************************************************/ XPointer _fallcCreateLocaleDataBase(XLCd lcd) { XlcDatabaseList list, new; Database p, database = (Database)NULL; XlcDatabase lc_db = (XlcDatabase)NULL; XrmQuark name_q; char pathname[256], *name; int i, n; name = _fallcFileName(lcd, "locale"); if(name == NULL){ return (XPointer)NULL; } strcpy(pathname, name); Xfree(name); name_q = falrmStringToQuark(pathname); for(list = _db_list; list; list = list->next){ if(name_q == list->name_q){ list->ref_count++; return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)list->lc_db; } } database = CreateDatabase(pathname); if(database == (Database)NULL){ return (XPointer)NULL; } n = CountDatabase(database); lc_db = (XlcDatabase)Xmalloc(sizeof(XlcDatabaseRec) * (n + 1)); if(lc_db == (XlcDatabase)NULL){ DestroyDatabase(database); if(lc_db != (XlcDatabase)NULL){ Xfree((char *)lc_db); } return (XPointer)NULL; } bzero(lc_db, sizeof(XlcDatabaseRec) * (n + 1)); for(p = database, i = 0; p && i < n; p = p->next, ++i){ lc_db[i].category_q = falrmStringToQuark(p->category); lc_db[i].name_q = falrmStringToQuark(p->name); lc_db[i].db = p; } new = (XlcDatabaseList)Xmalloc(sizeof(XlcDatabaseListRec)); if(new == (XlcDatabaseList)NULL){ DestroyDatabase(database); if(lc_db != (XlcDatabase)NULL){ Xfree((char *)lc_db); } return (XPointer)NULL; } new->name_q = name_q; new->lc_db = lc_db; new->database = database; new->ref_count = 1; new->next = _db_list; _db_list = new; return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)lc_db; }