#ifndef NOT_X_ENV
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <X11/Xlib.h>
#include <X11/Xresource.h>
#include "Xlibint.h"
#include "XlcPubI.h"
#else
#define Xmalloc malloc
#define Xrealloc realloc
#define Xfree free
#endif
#ifndef BUFSIZE
#define BUFSIZE 2048
#endif
#ifdef COMMENT
#ifdef BUFSIZE
#undef BUFSIZE
#endif
#define BUFSIZE 6144
#endif
#include <stdio.h>
typedef struct _DatabaseRec {
char *category;
char *name;
char **value;
int value_num;
struct _DatabaseRec *next;
} DatabaseRec, *Database;
typedef enum {
S_NULL,
S_CATEGORY,
S_NAME,
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;
int len;
} TokenTable;
static int f_newline (const char *str, Token token, Database *db);
static int f_comment (const char *str, Token token, Database *db);
static int f_semicolon (const char *str, Token token, Database *db);
static int f_double_quote (const char *str, Token token, Database *db);
static int f_left_brace (const char *str, Token token, Database *db);
static int f_right_brace (const char *str, Token token, Database *db);
static int f_white (const char *str, Token token, Database *db);
static int f_backslash (const char *str, Token token, Database *db);
static int f_numeric (const char *str, Token token, Database *db);
static int f_default (const char *str, Token token, Database *db);
static const TokenTable token_tbl[] = {
{ T_NEWLINE, 1 },
{ T_COMMENT, 1 },
{ T_SEMICOLON, 1 },
{ T_DOUBLE_QUOTE, 1 },
{ T_LEFT_BRACE, 1 },
{ T_RIGHT_BRACE, 1 },
{ T_SPACE, 1 },
{ T_TAB, 1 },
{ T_BACKSLASH, 1 },
{ T_NUMERIC_HEX, 2 },
{ T_NUMERIC_DEC, 2 },
{ T_NUMERIC_OCT, 2 },
{ T_DEFAULT, 1 }
};
#define SYM_CR '\r'
#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;
int bufMaxSize;
char *buf;
} DBParseInfo;
static DBParseInfo parse_info;
static void
init_parse_info (void)
{
static int allocated ;
char *ptr;
int size;
if (!allocated) {
bzero(&parse_info, sizeof(DBParseInfo));
parse_info.buf = (char *)Xmalloc(BUFSIZE);
parse_info.bufMaxSize = BUFSIZE;
allocated = 1;
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) {
if (line->str != NULL) {
Xfree(line->str);
}
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;
#ifdef never
*quoted = 0;
if (*p == SYM_COMMENT) {
int len = strlen(str);
if (p[len - 1] == SYM_NEWLINE || p[len - 1] == SYM_CR) {
*p++ = SYM_NEWLINE;
}
*p = '\0';
}
#else
while (*p) {
if (*p == SYM_DOUBLE_QUOTE) {
if (p == str || p[-1] != SYM_BACKSLASH) {
*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 || p[len-1] == SYM_CR)) {
*p++ = SYM_NEWLINE;
}
*p = '\0';
break;
}
}
++p;
}
#endif
}
static int
read_line(
FILE *fd,
Line *line)
{
char buf[BUFSIZE], *p;
int len;
int quoted = 0;
char *str;
int cur;
str = line->str;
cur = line->cursize = 0;
while ((p = fgets(buf, BUFSIZE, fd)) != NULL) {
++line->seq;
zap_comment(p, "ed);
len = strlen(p);
if (len == 0) {
if (cur > 0) {
break;
}
continue;
}
if (cur + len + 1 > line->maxsize) {
if (! realloc_line(line, line->maxsize + BUFSIZE)) {
return -1;
}
str = line->str;
}
strncpy(str + cur, p, len);
cur += len;
str[cur] = '\0';
#ifdef __UNIXOS2__
if (cur>1) {
if (str[cur-2] == '\r' && str[cur-1] == '\n') {
str[cur-2] = '\n';
str[cur-1] = '\0';
cur--;
}
}
#endif
if (!quoted && cur > 1 && str[cur - 2] == SYM_BACKSLASH &&
(str[cur - 1] == SYM_NEWLINE || str[cur-1] == SYM_CR)) {
cur -= 2;
str[cur] = '\0';
} else if (len < BUFSIZE - 1 || buf[len - 1] == SYM_NEWLINE ||
buf[len - 1] == SYM_CR) {
break;
}
}
if (quoted) {
return -1;
}
return line->cursize = cur;
}
static Token
get_token(
const char *str)
{
switch (*str) {
case SYM_NEWLINE:
case SYM_CR: 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(
const char *str,
char *word)
{
const char *p = str;
char *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;
}
static int
get_quoted_word(
const char *str,
char *word)
{
const char *p = str;
char *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;
goto found;
}
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;
}
return 0;
found:;
*w = '\0';
return p - str;
}
static int
append_value_list (void)
{
char **value_list = parse_info.value;
char *value;
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;
}
if (value_list == (char **)NULL) {
value_list = (char **)Xmalloc(sizeof(char *) * 2);
*value_list = NULL;
} else {
char **prev_list = value_list;
value_list = (char **)
Xrealloc(value_list, sizeof(char *) * (value_num + 2));
if (value_list == NULL) {
Xfree(prev_list);
}
}
if (value_list == (char **)NULL)
goto err2;
value = *value_list;
if (value == NULL) {
value = (char *)Xmalloc(value_len + len + 1);
} else {
char *prev_value = value;
value = (char *)Xrealloc(value, value_len + len + 1);
if (value == NULL) {
Xfree(prev_value);
}
}
if (value == NULL) {
goto err1;
}
if (value != *value_list) {
int i;
ssize_t delta;
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;
err1:
if (value_list) {
Xfree((char **)value_list);
}
if (value) {
Xfree(value);
}
err2:
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 size)
{
int i;
int len = 0;
char *p = name;
for (i = 0; i <= parse_info.nest_depth; ++i) {
len += strlen(parse_info.name[i]) + 1;
}
if (len >= size)
return 0;
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];
if (parse_info.pre_state == S_VALUE) {
if (! append_value_list()) {
goto err;
}
}
if (parse_info.name[parse_info.nest_depth] == NULL) {
goto err;
}
new = (Database)Xmalloc(sizeof(DatabaseRec));
if (new == (Database)NULL) {
goto err;
}
bzero(new, sizeof(DatabaseRec));
new->category = (char *)Xmalloc(strlen(parse_info.category) + 1);
if (new->category == NULL) {
goto err;
}
strcpy(new->category, parse_info.category);
if (! construct_name(name, sizeof(name))) {
goto err;
}
new->name = (char *)Xmalloc(strlen(name) + 1);
if (new->name == NULL) {
goto err;
}
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;
err:
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
static int
check_category_end(
const char *str)
{
const 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(
const char *str,
Token token,
Database *db)
{
switch (parse_info.pre_state) {
case S_NULL:
case S_CATEGORY:
break;
case S_NAME:
return 0;
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(
const char *str,
Token token,
Database *db)
{
const char *p = str;
while (*p != SYM_NEWLINE && *p != SYM_CR && *p != '\0') {
++p;
}
return p - str;
}
static int
f_white(
const char *str,
Token token,
Database *db)
{
const char *p = str;
while (iswhite(*p)) {
++p;
}
return p - str;
}
static int
f_semicolon(
const 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(
const char *str,
Token token,
Database *db)
{
switch (parse_info.pre_state) {
case S_NULL:
case S_CATEGORY:
case S_VALUE:
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;
default:
return 0;
}
return token_tbl[token].len;
}
static int
f_right_brace(
const 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;
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(
const char *str,
Token token,
Database *db)
{
char word[BUFSIZE];
char* wordp;
int len;
if ((len = strlen (str)) < sizeof word)
wordp = word;
else
wordp = Xmalloc (len + 1);
if (wordp == NULL)
return 0;
len = 0;
switch (parse_info.pre_state) {
case S_NULL:
case S_CATEGORY:
goto err;
case S_NAME:
case S_VALUE:
len = get_quoted_word(str, wordp);
if (len < 1)
goto err;
if ((parse_info.bufsize + (int)strlen(wordp) + 1)
>= parse_info.bufMaxSize) {
if (realloc_parse_info(strlen(wordp)+1) == False) {
goto err;
}
}
strcpy(&parse_info.buf[parse_info.bufsize], wordp);
parse_info.bufsize += strlen(wordp);
parse_info.pre_state = S_VALUE;
break;
default:
goto err;
}
if (wordp != word)
Xfree (wordp);
return len;
err:
if (wordp != word)
Xfree (wordp);
return 0;
}
static int
f_backslash(
const char *str,
Token token,
Database *db)
{
return f_default(str, token, db);
}
static int
f_numeric(
const char *str,
Token token,
Database *db)
{
char word[BUFSIZE];
const char *p;
char* wordp;
int len;
int token_len;
if ((len = strlen (str)) < sizeof word)
wordp = word;
else
wordp = Xmalloc (len + 1);
if (wordp == NULL)
return 0;
switch (parse_info.pre_state) {
case S_NULL:
case S_CATEGORY:
goto err;
case S_NAME:
case S_VALUE:
token_len = token_tbl[token].len;
p = str + token_len;
len = get_word(p, wordp);
if (len < 1)
goto err;
if ((parse_info.bufsize + token_len + (int)strlen(wordp) + 1)
>= parse_info.bufMaxSize) {
if (realloc_parse_info(token_len + strlen(wordp) + 1) == False)
goto err;
}
strncpy(&parse_info.buf[parse_info.bufsize], str, token_len);
strcpy(&parse_info.buf[parse_info.bufsize + token_len], wordp);
parse_info.bufsize += token_len + strlen(wordp);
parse_info.pre_state = S_VALUE;
break;
default:
goto err;
}
if (wordp != word)
Xfree (wordp);
return len + token_len;
err:
if (wordp != word)
Xfree (wordp);
return 0;
}
static int
f_default(
const char *str,
Token token,
Database *db)
{
char word[BUFSIZE], *p;
char* wordp;
int len;
if ((len = strlen (str)) < sizeof word)
wordp = word;
else
wordp = Xmalloc (len + 1);
if (wordp == NULL)
return 0;
len = get_word(str, wordp);
if (len < 1)
goto err;
switch (parse_info.pre_state) {
case S_NULL:
if (parse_info.category != NULL)
goto err;
p = (char *)Xmalloc(strlen(wordp) + 1);
if (p == NULL)
goto err;
strcpy(p, wordp);
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)) {
clear_parse_info();
len = strlen(str);
break;
}
}
p = (char *)Xmalloc(strlen(wordp) + 1);
if (p == NULL)
goto err;
strcpy(p, wordp);
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(wordp) + 1)
>= parse_info.bufMaxSize) {
if (realloc_parse_info(strlen(wordp) + 1) == False)
goto err;
}
strcpy(&parse_info.buf[parse_info.bufsize], wordp);
parse_info.bufsize += strlen(wordp);
parse_info.pre_state = S_VALUE;
break;
default:
goto err;
}
if (wordp != word)
Xfree (wordp);
return len;
err:
if (wordp != word)
Xfree (wordp);
return 0;
}
#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 len;
int error = 0;
fd = _XFopenFile(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) {
int (*parse_proc)(const char *str, Token token, Database *db) = NULL;
token = get_token(p);
switch (token_tbl[token].token) {
case T_NEWLINE:
parse_proc = f_newline;
break;
case T_COMMENT:
parse_proc = f_comment;
break;
case T_SEMICOLON:
parse_proc = f_semicolon;
break;
case T_DOUBLE_QUOTE:
parse_proc = f_double_quote;
break;
case T_LEFT_BRACE:
parse_proc = f_left_brace;
break;
case T_RIGHT_BRACE:
parse_proc = f_right_brace;
break;
case T_SPACE:
case T_TAB:
parse_proc = f_white;
break;
case T_BACKSLASH:
parse_proc = f_backslash;
break;
case T_NUMERIC_HEX:
case T_NUMERIC_DEC:
case T_NUMERIC_OCT:
parse_proc = f_numeric;
break;
case T_DEFAULT:
parse_proc = f_default;
break;
}
len = 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;
}
#ifndef NOT_X_ENV
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;
static XlcDatabaseList _db_list = (XlcDatabaseList)NULL;
void
_XlcGetResource(
XLCd lcd,
const char *category,
const char *class,
char ***value,
int *count)
{
XLCdPublicMethodsPart *methods = XLC_PUBLIC_METHODS(lcd);
(*methods->get_resource)(lcd, category, class, value, count);
return;
}
void
_XlcGetLocaleDataBase(
XLCd lcd,
const char *category,
const char *name,
char ***value,
int *count)
{
XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db);
XrmQuark category_q, name_q;
category_q = XrmStringToQuark(category);
name_q = XrmStringToQuark(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;
}
void
_XlcDestroyLocaleDataBase(
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;
}
XPointer
_XlcCreateLocaleDataBase(
XLCd lcd)
{
XlcDatabaseList list, new;
Database p, database = (Database)NULL;
XlcDatabase lc_db = (XlcDatabase)NULL;
XrmQuark name_q;
char *name;
int i, n;
name = _XlcFileName(lcd, "locale");
if (name == NULL)
return (XPointer)NULL;
#ifndef __UNIXOS2__
name_q = XrmStringToQuark(name);
#else
name_q = XrmStringToQuark((char*)__XOS2RedirRoot(name));
#endif
for (list = _db_list; list; list = list->next) {
if (name_q == list->name_q) {
list->ref_count++;
Xfree (name);
return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)list->lc_db;
}
}
database = CreateDatabase(name);
if (database == (Database)NULL) {
Xfree (name);
return (XPointer)NULL;
}
n = CountDatabase(database);
lc_db = (XlcDatabase)Xmalloc(sizeof(XlcDatabaseRec) * (n + 1));
if (lc_db == (XlcDatabase)NULL)
goto err;
bzero(lc_db, sizeof(XlcDatabaseRec) * (n + 1));
for (p = database, i = 0; p && i < n; p = p->next, ++i) {
lc_db[i].category_q = XrmStringToQuark(p->category);
lc_db[i].name_q = XrmStringToQuark(p->name);
lc_db[i].db = p;
}
new = (XlcDatabaseList)Xmalloc(sizeof(XlcDatabaseListRec));
if (new == (XlcDatabaseList)NULL) {
goto err;
}
new->name_q = name_q;
new->lc_db = lc_db;
new->database = database;
new->ref_count = 1;
new->next = _db_list;
_db_list = new;
Xfree (name);
return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)lc_db;
err:
DestroyDatabase(database);
if (lc_db != (XlcDatabase)NULL) {
Xfree((char *)lc_db);
}
Xfree (name);
return (XPointer)NULL;
}
#endif