8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-30 19:23:03 +01:00
firebird-mirror/src/msgs/build_file.epp

508 lines
11 KiB
Plaintext
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Message Facility
* MODULE: build_file.e
* DESCRIPTION: Build message file
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "XENIX" port
2002-02-16 04:05:21 +01:00
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "DELTA" port
*
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
*
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/ib_stdio.h"
#include <stdlib.h>
#include <string.h>
#include "../jrd/gds.h"
#include "../jrd/common.h"
#include "../jrd/msg.h"
#include "../jrd/gds_proto.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
2001-05-23 15:26:42 +02:00
#define MAX_LEVELS 4
DATABASE DB = "msg.gdb";
static void ascii_str_to_upper(TEXT *);
static USHORT do_msgs(TEXT *, TEXT *, USHORT);
static void propogate(MSGNOD *, MSGNOD *, ULONG, ULONG);
static SLONG write_bucket(MSGNOD, USHORT);
static void sanitize(TEXT *);
static SLONG file_position;
static int file;
/* keep the LOCALE_PAT names in sync with gds.h */
#ifdef WIN_NT
2001-05-23 15:26:42 +02:00
#include <io.h>
#define FILENAME "firebird.msg"
2001-05-23 15:26:42 +02:00
#define LOCALE_PAT "%.8s.msg"
#define PATH_SEPARATOR '\\'
#endif
#ifndef FILENAME
#define FILENAME "firebird.msg"
2001-05-23 15:26:42 +02:00
#define LOCALE_PAT "%.10s.msg"
#define PATH_SEPARATOR '/'
#endif
#ifdef VMS
#include <file.h>
#else
#include <sys/types.h>
#ifndef WIN_NT
#include <sys/file.h>
#endif
#endif /* VMS */
2001-05-23 15:26:42 +02:00
#ifndef O_RDWR
#include <fcntl.h>
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
int CLIB_ROUTINE main( int argc, char **argv)
{
/**************************************
*
* m a i n
*
**************************************
*
* Functional description
* Top level routine.
*
**************************************/
TEXT *p, **end_args, db_file[256], filename[256],
*pathname, pathbuffer[256], *locale;
USHORT sw_bad;
USHORT sw_warning;
SSHORT len;
BASED ON LOCALES.LOCALE this_locale;
strcpy(db_file, "msg.gdb");
strcpy(filename, FILENAME);
pathname = NULL;
locale = NULL;
sw_warning = 0;
end_args = argv + argc;
for (++argv; argv < end_args;) {
p = *argv++;
sw_bad = FALSE;
if (*p != '-')
sw_bad = TRUE;
else
switch (UPPER(p[1])) {
case 'D':
strcpy(db_file, *argv++);
break;
case 'F':
strcpy(filename, *argv++);
break;
case 'P':
strcpy(pathbuffer, *argv++);
pathname = pathbuffer;
break;
case 'L':
locale = *argv++;
break;
case 'W':
sw_warning++;
break;
default:
sw_bad = TRUE;
}
if (sw_bad) {
ib_printf("Invalid option \"%s\". Valid options are:\n", p);
ib_printf("\t-D\tDatabase name\n");
ib_printf("\t-F\tMessage file name\n");
ib_printf("\t-P\tMessage file path (should end with '/')\n");
ib_printf("\t-L\tLocale name\n");
ib_printf("\t-W\tVerbose warning messages\n");
exit(FINI_ERROR);
}
}
/* Get db_file ready to go */
READY db_file AS DB;
START_TRANSACTION;
/* make sure the path name ends in a '/' */
if (pathname) {
len = strlen(pathname);
if (pathname[len - 1] != PATH_SEPARATOR) {
pathname[len] = PATH_SEPARATOR;
pathname[len + 1] = 0;
}
}
/* check for the locale option */
if (!locale) { /* no locale given: do the regular US msgs */
if (!pathname)
do_msgs(filename, NULL, 0);
else {
strcat(pathname, filename);
do_msgs(pathname, NULL, 0);
}
}
else {
int got_one = 0;
FOR FIRST 1 L IN LOCALES WITH L.LOCALE = locale
got_one = 1;
END_FOR;
if (got_one) { /* do only 1 locale */
strcpy(this_locale, locale);
sanitize(locale);
if (pathname) {
sprintf(filename, LOCALE_PAT, locale);
strcat(pathname, filename);
do_msgs(pathname, this_locale, sw_warning);
}
else
do_msgs(filename, this_locale, sw_warning);
}
else {
strncpy(this_locale, locale, sizeof(this_locale));
ascii_str_to_upper(this_locale);
if (!strcmp(this_locale, "ALL")) {
FOR LC IN LOCALES /* do all locales except piglatin */
WITH LC.LOCALE != "pg_PG" AND LC.LOCALE != "piglatin";
locale = LC.LOCALE;
strcpy(this_locale, LC.LOCALE);
ib_printf("build_file: building locale %s", this_locale);
sanitize(locale);
sprintf(filename, LOCALE_PAT, locale);
if (pathname) {
strcat(pathname, filename);
ib_printf(" to file %s\n", pathname);
do_msgs(pathname, this_locale, sw_warning);
}
else {
ib_printf(" to file %s\n", filename);
do_msgs(filename, this_locale, sw_warning);
}
pathname = NULL;
END_FOR;
}
else {
ib_printf("build_file: Unknown locale: %s\n", locale);
ib_printf("Valid options are:\n");
FOR LO IN LOCALES
ib_printf("\t%s\n", LO.LOCALE);
END_FOR;
ib_printf("\tall\n");
}
COMMIT;
FINISH DB;
exit(FINI_ERROR);
}
}
COMMIT;
FINISH;
exit(FINI_OK);
}
static void ascii_str_to_upper( TEXT * s)
{
/**************************************
*
* a s c i i _ s t r _ t o _ u p p e r
*
**************************************
*
* Functional description
* change the a - z chars in string to upper case
*
**************************************/
while (*s) {
*s >= 'a' && *s <= 'z' ? *s &= 0xDF : *s;
*s++;
}
}
static USHORT do_msgs( TEXT * filename, TEXT * locale, USHORT sw_warning)
{
/**************************************
*
* d o _ m s g s
*
**************************************
*
* Functional description
* Build the message file
*
**************************************/
ISC_MSGHDR header;
2002-12-10 12:53:53 +01:00
TEXT *p, *q, *end_leaf, msg_text[256];
2001-05-23 15:26:42 +02:00
MSGREC leaf_node, leaf;
2002-12-10 12:53:53 +01:00
MSGNOD buckets[MAX_LEVELS], *ptr, *ptr2, nodes[MAX_LEVELS], node;
USHORT l, n;
2001-05-23 15:26:42 +02:00
ULONG position, prior_code;
int warning_counter;
warning_counter = 0;
/* Divy up memory among various buffers */
leaf_node = leaf = (MSGREC) gds__alloc((SLONG) MSG_BUCKET);
end_leaf = (TEXT *) leaf + MSG_BUCKET;
nodes[0] = NULL;
/* Open output file */
if ((file = open(filename, O_WRONLY | O_CREAT | O_BINARY, 0666)) == -1) {
ib_printf("Can't open %s\n", filename);
return FINI_ERROR;
}
file_position = 0;
/* Format and write header */
header.msghdr_major_version = MSG_MAJOR_VERSION;
header.msghdr_minor_version = MSG_MINOR_VERSION;
header.msghdr_bucket_size = MSG_BUCKET;
write_bucket((MSGNOD) &header, sizeof(header));
2001-05-23 15:26:42 +02:00
/* Write out messages building B-tree */
FOR X IN MESSAGES SORTED BY X.CODE
/* pre-load with US English message - just in case we don't
* have a translation available. */
strcpy(msg_text, X.TEXT);
l = strlen(msg_text);
if (locale) { /* want translated output */
/* Overwrite English message with translation, if we find one */
int found_one;
found_one = 0;
FOR Y IN TRANSMSGS WITH Y.FAC_CODE = X.FAC_CODE
AND Y.NUMBER = X.NUMBER
AND Y.LOCALE = locale
AND Y.TEXT NOT MISSING AND Y.TEXT != " ";
strcpy(msg_text, Y.TEXT);
l = strlen(msg_text);
found_one++;
END_FOR;
if (!found_one && sw_warning)
ib_printf
("build_file: Warning - no %s translation of msg# %d\n",
locale, X.CODE);
if (found_one > 1 && sw_warning)
ib_printf
("build_file: Warning - multiple %s translations of msg# %d\n",
locale, X.CODE);
if (found_one != 1)
warning_counter++;
}
if (leaf_node->msgrec_text + l >= end_leaf) {
position = write_bucket((MSGNOD) leaf, n);
2001-05-23 15:26:42 +02:00
propogate(buckets, nodes, prior_code, position);
leaf_node = leaf;
}
leaf_node->msgrec_code = prior_code =
MSG_NUMBER(X.FAC_CODE, X.NUMBER);
leaf_node->msgrec_length = l;
leaf_node->msgrec_flags = X.FLAGS;
n = OFFSETA(MSGREC, msgrec_text) + l;
p = leaf_node->msgrec_text;
if (l) {
q = msg_text;
do
*p++ = *q++;
while (--l);
}
n = p - (SCHAR *) leaf;
leaf_node = NEXT_LEAF(leaf_node);
END_FOR;
/* Write a high water mark on leaf node */
if (leaf_node->msgrec_text + l >= end_leaf) {
n = (SCHAR *) leaf_node - (SCHAR *) leaf;
position = write_bucket((MSGNOD) leaf, n);
2001-05-23 15:26:42 +02:00
propogate(buckets, nodes, prior_code, position);
leaf_node = leaf;
}
2002-09-25 15:08:25 +02:00
leaf_node->msgrec_code = -1UL;
2001-05-23 15:26:42 +02:00
leaf_node->msgrec_length = 0;
leaf_node->msgrec_flags = 0;
n = (SCHAR *) leaf_node - (SCHAR *) leaf;
position = write_bucket((MSGNOD) leaf, n);
2001-05-23 15:26:42 +02:00
/* Finish off upper levels of tree */
header.msghdr_levels = 1;
for (ptr = nodes, ptr2 = buckets; node = *ptr; ptr++, ptr2++) {
2002-09-25 15:08:25 +02:00
node->msgnod_code = -1UL;
2001-05-23 15:26:42 +02:00
node->msgnod_seek = position;
n = (SCHAR *) (node + 1) - (SCHAR *) * ptr2;
position = write_bucket(*ptr2, n);
++header.msghdr_levels;
}
header.msghdr_top_tree = position;
/* Re-write header record and finish */
lseek(file, LSEEK_OFFSET_CAST 0, 0);
2001-05-23 15:26:42 +02:00
write(file, &header, sizeof(header));
close(file);
file = -1;
if (warning_counter)
ib_printf("build_file: %d messages lack translations in locale %s\n",
warning_counter, locale);
2002-06-29 10:34:14 +02:00
return FINI_OK;
2001-05-23 15:26:42 +02:00
}
static void propogate(
MSGNOD * buckets,
MSGNOD * nodes, ULONG prior_code, ULONG position)
{
/**************************************
*
* p r o p o g a t e
*
**************************************
*
* Functional description
* Propogate a full bucket upward.
*
**************************************/
MSGNOD node, end;
/* Make sure current level has been allocated */
if (!*nodes) {
*nodes = *buckets = (MSGNOD) gds__alloc((SLONG) MSG_BUCKET);
nodes[1] = NULL;
}
/* Insert into current bucket */
node = (*nodes)++;
node->msgnod_code = prior_code;
node->msgnod_seek = position;
/* Check for full bucket. If not, we're done */
end = (MSGNOD) ((SCHAR *) * buckets + MSG_BUCKET);
if (*nodes < end)
return;
/* Bucket is full -- write it out, propogate the split, and re-initialize */
position = write_bucket(*buckets, MSG_BUCKET);
propogate(buckets + 1, nodes + 1, prior_code, position);
*nodes = *buckets;
}
static SLONG write_bucket( MSGNOD bucket, USHORT length)
{
/**************************************
*
* w r i t e _ b u c k e t
*
**************************************
*
* Functional description
* Write stuff, return position of stuff written.
*
**************************************/
SLONG position;
int n;
USHORT padded_length;
SLONG zero_bytes = 0;
padded_length = ROUNDUP(length, sizeof(SLONG));
position = file_position;
n = write(file, bucket, length);
if (n == -1) {
ib_fprintf(ib_stderr, "IO error on write()\n");
exit(FINI_ERROR);
}
n = write(file, &zero_bytes, padded_length - length);
if (n == -1) {
ib_fprintf(ib_stderr, "IO error on write()\n");
exit(FINI_ERROR);
}
file_position += padded_length;
return position;
}
static void sanitize( TEXT * locale)
{
/**************************************
*
* s a n i t i z e
*
**************************************
*
* Functional description
* Clean up a locale to make it acceptable for use in file names
* for Windows NT, PC, and mpexl: remove any '.' or '_' for mpexl,
* replace any period with '_' for NT or PC.
* Keep this in sync with gds.c
*
**************************************/
SSHORT ch;
while (*locale) {
ch = *locale;
if (ch == '.')
*locale = '_';
locale++;
}
}