2001-05-23 15:26:42 +02:00
|
|
|
/*
|
2007-02-11 10:04:54 +01:00
|
|
|
* PROGRAM: JRD Message Facility
|
|
|
|
* MODULE: build_file.epp
|
2001-05-23 15:26:42 +02:00
|
|
|
* 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-16 03:50:01 +01:00
|
|
|
*
|
|
|
|
* 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-02-16 03:50:01 +01:00
|
|
|
*
|
2002-10-31 06:06:02 +01:00
|
|
|
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
|
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2004-04-29 00:36:29 +02:00
|
|
|
#include <stdio.h>
|
2004-03-22 16:13:05 +01:00
|
|
|
#include "../jrd/common.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2003-11-08 17:40:17 +01:00
|
|
|
#include "../jrd/ibase.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/common.h"
|
|
|
|
#include "../jrd/msg.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
const int max_levels = 4;
|
|
|
|
typedef msgnod* msgnod_ptr_array[max_levels];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-03-17 13:06:48 +01:00
|
|
|
DATABASE DB = "msg.fdb";
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
static void ascii_str_to_upper(TEXT*);
|
2008-03-16 14:38:58 +01:00
|
|
|
static char* copy_terminate(char* dest, const char* src, size_t bufsize);
|
2003-11-05 10:02:33 +01:00
|
|
|
static USHORT do_msgs(const TEXT*, const TEXT*, bool);
|
|
|
|
static void propagate(msgnod**, msgnod**, ULONG, ULONG);
|
|
|
|
static SLONG write_bucket(const msgnod*, USHORT);
|
|
|
|
static void sanitize(TEXT*);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
static SLONG global_file_position;
|
|
|
|
static int global_file;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-04-23 03:44:05 +02:00
|
|
|
/* keep the LOCALE_PAT names in sync with file_params.h */
|
2003-11-05 10:02:33 +01:00
|
|
|
// CVC: It's #define MSG_FILE_LANG "intl/%.8s.msg"
|
|
|
|
// in jrd/file_params.h, it seems we are already out of sync!
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-09-04 11:12:46 +02:00
|
|
|
#ifdef WIN_NT
|
2003-11-16 13:57:23 +01:00
|
|
|
#include <io.h> // open, lseek, write, close
|
2003-11-05 10:02:33 +01:00
|
|
|
const char path_separator = '\\';
|
2004-05-07 00:11:24 +02:00
|
|
|
#else
|
2003-11-05 10:02:33 +01:00
|
|
|
const char path_separator = '/';
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
2006-06-10 04:21:31 +02:00
|
|
|
const char* const locale_pattern = "%.10s.msg";
|
2004-05-07 00:11:24 +02:00
|
|
|
const char* const FILENAME = "firebird.msg";
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#ifndef WIN_NT
|
|
|
|
#include <sys/file.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef O_RDWR
|
|
|
|
#include <fcntl.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef O_BINARY
|
2004-05-07 09:19:48 +02:00
|
|
|
#define O_BINARY 0
|
2001-05-23 15:26:42 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
int CLIB_ROUTINE main( int argc, char** argv)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* m a i n
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Top level routine.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-11-05 10:02:33 +01:00
|
|
|
TEXT db_file[MAXPATHLEN], filename[MAXPATHLEN], pathbuffer[MAXPATHLEN];
|
2001-05-23 15:26:42 +02:00
|
|
|
BASED ON LOCALES.LOCALE this_locale;
|
|
|
|
|
2003-03-17 13:06:48 +01:00
|
|
|
strcpy(db_file, "msg.fdb");
|
2001-05-23 15:26:42 +02:00
|
|
|
strcpy(filename, FILENAME);
|
2003-11-05 10:02:33 +01:00
|
|
|
TEXT* pathname = NULL;
|
|
|
|
TEXT* locale = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
bool sw_warning = false;
|
|
|
|
const TEXT* const* const end_args = argv + argc;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2009-01-18 12:36:08 +01:00
|
|
|
for (++argv; argv < end_args;)
|
|
|
|
{
|
2003-11-05 10:02:33 +01:00
|
|
|
const TEXT* p = *argv++;
|
|
|
|
bool sw_bad = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (*p != '-')
|
2003-08-29 02:37:25 +02:00
|
|
|
sw_bad = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
else
|
2003-11-05 10:02:33 +01:00
|
|
|
{
|
2009-01-18 12:36:08 +01:00
|
|
|
switch (UPPER(p[1]))
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
case 'D':
|
2008-03-16 14:38:58 +01:00
|
|
|
if (argv >= end_args)
|
|
|
|
sw_bad = true;
|
|
|
|
else
|
|
|
|
copy_terminate(db_file, *argv++, MAXPATHLEN);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'F':
|
2008-03-16 14:38:58 +01:00
|
|
|
if (argv >= end_args)
|
|
|
|
sw_bad = true;
|
|
|
|
else
|
|
|
|
copy_terminate(filename, *argv++, MAXPATHLEN);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'P':
|
2008-03-16 14:38:58 +01:00
|
|
|
if (argv >= end_args)
|
|
|
|
sw_bad = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
copy_terminate(pathbuffer, *argv++, MAXPATHLEN);
|
|
|
|
pathname = pathbuffer;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'L':
|
2008-03-16 14:38:58 +01:00
|
|
|
if (argv >= end_args)
|
|
|
|
sw_bad = true;
|
|
|
|
else
|
|
|
|
locale = *argv++;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'W':
|
2003-11-05 10:02:33 +01:00
|
|
|
sw_warning = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-08-29 02:37:25 +02:00
|
|
|
sw_bad = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-11-05 10:02:33 +01:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
if (sw_bad) {
|
2004-04-29 00:36:29 +02:00
|
|
|
printf("Invalid option \"%s\". Valid options are:\n", p);
|
|
|
|
printf("\t-D\tDatabase name\n");
|
|
|
|
printf("\t-F\tMessage file name\n");
|
|
|
|
printf("\t-P\tMessage file path (should end with '/')\n");
|
|
|
|
printf("\t-L\tLocale name\n");
|
|
|
|
printf("\t-W\tVerbose warning messages\n");
|
2001-05-23 15:26:42 +02:00
|
|
|
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) {
|
2004-10-04 06:59:43 +02:00
|
|
|
const size_t len = strlen(pathname);
|
2003-11-05 10:02:33 +01:00
|
|
|
//fb_assert(len + 1 < MAXPATHLEN);
|
|
|
|
if (pathname[len - 1] != path_separator) {
|
|
|
|
pathname[len] = path_separator;
|
2001-05-23 15:26:42 +02:00
|
|
|
pathname[len + 1] = 0;
|
|
|
|
}
|
|
|
|
}
|
2008-12-21 00:50:22 +01:00
|
|
|
|
2008-03-16 14:38:58 +01:00
|
|
|
const size_t separator_pos = pathname ? strlen(pathname) : 0;
|
2008-12-21 00:50:22 +01:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* check for the locale option */
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
if (!locale) { // no locale given: do the regular US msgs
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!pathname)
|
2003-11-05 10:02:33 +01:00
|
|
|
do_msgs(filename, NULL, false);
|
2001-05-23 15:26:42 +02:00
|
|
|
else {
|
2003-11-05 10:02:33 +01:00
|
|
|
//fb_assert(strlen(pathname) + strlen(filename) < MAXPATHLEN);
|
2001-05-23 15:26:42 +02:00
|
|
|
strcat(pathname, filename);
|
2003-11-05 10:02:33 +01:00
|
|
|
do_msgs(pathname, NULL, false);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2003-11-05 10:02:33 +01:00
|
|
|
bool got_one = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR FIRST 1 L IN LOCALES WITH L.LOCALE = locale
|
2003-11-05 10:02:33 +01:00
|
|
|
got_one = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR;
|
2003-11-05 10:02:33 +01:00
|
|
|
if (got_one) { // do only 1 locale
|
2001-05-23 15:26:42 +02:00
|
|
|
strcpy(this_locale, locale);
|
|
|
|
sanitize(locale);
|
|
|
|
if (pathname) {
|
2003-11-05 10:02:33 +01:00
|
|
|
sprintf(filename, locale_pattern, locale);
|
2001-05-23 15:26:42 +02:00
|
|
|
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")) {
|
2003-11-05 10:02:33 +01:00
|
|
|
FOR LC IN LOCALES // do all locales except piglatin
|
2004-08-23 11:07:40 +02:00
|
|
|
WITH LC.LOCALE != 'pg_PG' AND LC.LOCALE != 'piglatin';
|
2001-05-23 15:26:42 +02:00
|
|
|
locale = LC.LOCALE;
|
|
|
|
strcpy(this_locale, LC.LOCALE);
|
2004-04-29 00:36:29 +02:00
|
|
|
printf("build_file: building locale %s", this_locale);
|
2001-05-23 15:26:42 +02:00
|
|
|
sanitize(locale);
|
2003-11-05 10:02:33 +01:00
|
|
|
sprintf(filename, locale_pattern, locale);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (pathname) {
|
|
|
|
strcat(pathname, filename);
|
2004-04-29 00:36:29 +02:00
|
|
|
printf(" to file %s\n", pathname);
|
2001-05-23 15:26:42 +02:00
|
|
|
do_msgs(pathname, this_locale, sw_warning);
|
2008-03-16 14:38:58 +01:00
|
|
|
pathname[separator_pos] = 0; // for the next iteration.
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else {
|
2004-04-29 00:36:29 +02:00
|
|
|
printf(" to file %s\n", filename);
|
2001-05-23 15:26:42 +02:00
|
|
|
do_msgs(filename, this_locale, sw_warning);
|
|
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
}
|
|
|
|
else {
|
2004-04-29 00:36:29 +02:00
|
|
|
printf("build_file: Unknown locale: %s\n", locale);
|
|
|
|
printf("Valid options are:\n");
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR LO IN LOCALES
|
2004-04-29 00:36:29 +02:00
|
|
|
printf("\t%s\n", LO.LOCALE);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR;
|
2004-04-29 00:36:29 +02:00
|
|
|
printf("\tall\n");
|
2004-09-26 03:46:31 +02:00
|
|
|
|
|
|
|
COMMIT;
|
|
|
|
FINISH DB;
|
|
|
|
exit(FINI_ERROR);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
COMMIT;
|
|
|
|
FINISH;
|
|
|
|
|
2003-08-22 15:09:09 +02:00
|
|
|
return(FINI_OK);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
static void ascii_str_to_upper( TEXT* s)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-16 14:38:58 +01:00
|
|
|
static char* copy_terminate(char* dest, const char* src, size_t bufsize)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c o p y _ t e r m i n a t e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Do the same as strncpy but ensure the null terminator is written.
|
|
|
|
* To avoid putting here #include "../common/utils_proto.h"
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (!bufsize) // Was it a joke?
|
|
|
|
return dest;
|
|
|
|
|
|
|
|
--bufsize;
|
|
|
|
strncpy(dest, src, bufsize);
|
|
|
|
dest[bufsize] = 0;
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
static USHORT do_msgs( const TEXT* filename, const TEXT* locale, bool sw_warning)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d o _ m s g s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Build the message file
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
// Divy up memory among various buffers
|
|
|
|
// Memory leaking until the program finishes?
|
2004-10-04 06:59:43 +02:00
|
|
|
msgrec* leaf_node = (msgrec*) gds__alloc((SLONG) MSG_BUCKET);
|
2003-11-05 10:02:33 +01:00
|
|
|
msgrec* const leaf = leaf_node;
|
|
|
|
const TEXT* const end_leaf = (TEXT*) leaf + MSG_BUCKET;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
// Open output file
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
global_file = open(filename, O_WRONLY | O_CREAT | O_BINARY, 0666);
|
|
|
|
if (global_file == -1) {
|
2004-04-29 00:36:29 +02:00
|
|
|
printf("Can't open %s\n", filename);
|
2001-05-23 15:26:42 +02:00
|
|
|
return FINI_ERROR;
|
|
|
|
}
|
2003-11-05 10:02:33 +01:00
|
|
|
global_file_position = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
// Format and write header
|
2009-04-03 12:07:55 +02:00
|
|
|
isc_msghdr header;
|
2001-05-23 15:26:42 +02:00
|
|
|
header.msghdr_major_version = MSG_MAJOR_VERSION;
|
|
|
|
header.msghdr_minor_version = MSG_MINOR_VERSION;
|
|
|
|
header.msghdr_bucket_size = MSG_BUCKET;
|
2003-11-05 10:02:33 +01:00
|
|
|
// CVC: Since this is an unused field that holds garbage in the *.msg file,
|
|
|
|
// we'll initialize it to the date the FB project was registered with SF.
|
|
|
|
header.msghdr_origin = 20000730; // 2000-07-30
|
|
|
|
write_bucket((msgnod*) &header, sizeof(header));
|
|
|
|
|
|
|
|
// Write out messages building B-tree
|
2008-12-21 00:50:22 +01:00
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
int warning_counter = 0;
|
|
|
|
USHORT n = 0;
|
|
|
|
ULONG position = 0, prior_code = 0;
|
|
|
|
TEXT msg_text[256];
|
|
|
|
msgnod_ptr_array buckets, nodes;
|
|
|
|
nodes[0] = NULL;
|
|
|
|
size_t len = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR X IN MESSAGES SORTED BY X.CODE
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
// pre-load with US English message - just in case we don't
|
|
|
|
// have a translation available.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
strcpy(msg_text, X.TEXT);
|
2003-11-05 10:02:33 +01:00
|
|
|
len = strlen(msg_text);
|
|
|
|
if (locale) { // want translated output
|
|
|
|
// Overwrite English message with translation, if we find one
|
|
|
|
int found_one = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR Y IN TRANSMSGS WITH Y.FAC_CODE = X.FAC_CODE
|
|
|
|
AND Y.NUMBER = X.NUMBER
|
|
|
|
AND Y.LOCALE = locale
|
2004-08-23 11:07:40 +02:00
|
|
|
AND Y.TEXT NOT MISSING AND Y.TEXT != ' ';
|
2001-05-23 15:26:42 +02:00
|
|
|
strcpy(msg_text, Y.TEXT);
|
2003-11-05 10:02:33 +01:00
|
|
|
len = strlen(msg_text);
|
2001-05-23 15:26:42 +02:00
|
|
|
found_one++;
|
|
|
|
END_FOR;
|
|
|
|
if (!found_one && sw_warning)
|
2004-04-29 00:36:29 +02:00
|
|
|
printf
|
2004-08-26 19:54:19 +02:00
|
|
|
("build_file: Warning - no %s translation of msg# %"QUADFORMAT"d\n",
|
2001-05-23 15:26:42 +02:00
|
|
|
locale, X.CODE);
|
|
|
|
if (found_one > 1 && sw_warning)
|
2004-04-29 00:36:29 +02:00
|
|
|
printf
|
2004-08-26 19:54:19 +02:00
|
|
|
("build_file: Warning - multiple %s translations of msg# %"QUADFORMAT"d\n",
|
2001-05-23 15:26:42 +02:00
|
|
|
locale, X.CODE);
|
|
|
|
if (found_one != 1)
|
|
|
|
warning_counter++;
|
|
|
|
}
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
if (leaf_node->msgrec_text + len >= end_leaf) {
|
|
|
|
position = write_bucket((msgnod*) leaf, n);
|
|
|
|
propagate(buckets, nodes, prior_code, position);
|
2001-05-23 15:26:42 +02:00
|
|
|
leaf_node = leaf;
|
|
|
|
}
|
2007-03-10 10:33:08 +01:00
|
|
|
leaf_node->msgrec_code = prior_code = MSG_NUMBER(X.FAC_CODE, X.NUMBER);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
leaf_node->msgrec_length = len;
|
2008-03-16 14:38:58 +01:00
|
|
|
// Let's not store trash in flags.
|
|
|
|
leaf_node->msgrec_flags = X.FLAGS.NULL ? 0 : X.FLAGS;
|
2007-03-10 10:33:08 +01:00
|
|
|
//n = OFFSETA(MSGREC, msgrec_text) + len; // useless? See assignment below.
|
2003-11-05 10:02:33 +01:00
|
|
|
TEXT* p = leaf_node->msgrec_text;
|
2007-03-10 10:33:08 +01:00
|
|
|
memcpy(p, msg_text, len);
|
|
|
|
n = p + len - (SCHAR*) leaf; // For the next iteration.
|
2001-05-23 15:26:42 +02:00
|
|
|
leaf_node = NEXT_LEAF(leaf_node);
|
|
|
|
END_FOR;
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
// Write a high water mark on leaf node
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
if (leaf_node->msgrec_text + len >= end_leaf) {
|
2001-05-23 15:26:42 +02:00
|
|
|
n = (SCHAR *) leaf_node - (SCHAR *) leaf;
|
2003-11-05 10:02:33 +01:00
|
|
|
position = write_bucket((msgnod*) leaf, n);
|
|
|
|
propagate(buckets, nodes, prior_code, position);
|
2001-05-23 15:26:42 +02:00
|
|
|
leaf_node = leaf;
|
|
|
|
}
|
|
|
|
|
2008-11-28 19:49:07 +01:00
|
|
|
leaf_node->msgrec_code = ~0;
|
2001-05-23 15:26:42 +02:00
|
|
|
leaf_node->msgrec_length = 0;
|
|
|
|
leaf_node->msgrec_flags = 0;
|
|
|
|
n = (SCHAR *) leaf_node - (SCHAR *) leaf;
|
2003-11-05 10:02:33 +01:00
|
|
|
position = write_bucket((msgnod*) leaf, n);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
// Finish off upper levels of tree
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
header.msghdr_levels = 1;
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
for (msgnod** ptr = nodes, **ptr2 = buckets; *ptr; ptr++, ptr2++) {
|
|
|
|
msgnod* node = *ptr;
|
2008-11-28 19:49:07 +01:00
|
|
|
node->msgnod_code = ~0;
|
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 */
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
lseek(global_file, LSEEK_OFFSET_CAST 0, 0);
|
|
|
|
write(global_file, &header, sizeof(header));
|
|
|
|
close(global_file);
|
|
|
|
global_file = -1;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (warning_counter)
|
2004-04-29 00:36:29 +02:00
|
|
|
printf("build_file: %d messages lack translations in locale %s\n",
|
2001-05-23 15:26:42 +02:00
|
|
|
warning_counter, locale);
|
2002-06-29 10:34:14 +02:00
|
|
|
|
|
|
|
return FINI_OK;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-01 19:21:36 +02:00
|
|
|
static void propagate(msgnod** buckets,
|
2003-11-05 10:02:33 +01:00
|
|
|
msgnod** nodes, ULONG prior_code, ULONG position)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
2003-11-05 10:02:33 +01:00
|
|
|
* p r o p a g a t e
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
2003-11-05 10:02:33 +01:00
|
|
|
* Propagate a full bucket upward.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
/* Make sure current level has been allocated */
|
|
|
|
|
|
|
|
if (!*nodes) {
|
2003-11-05 10:02:33 +01:00
|
|
|
*nodes = *buckets = (msgnod*) gds__alloc((SLONG) MSG_BUCKET);
|
2001-05-23 15:26:42 +02:00
|
|
|
nodes[1] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Insert into current bucket */
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
msgnod* node = (*nodes)++;
|
2001-05-23 15:26:42 +02:00
|
|
|
node->msgnod_code = prior_code;
|
|
|
|
node->msgnod_seek = position;
|
|
|
|
|
|
|
|
/* Check for full bucket. If not, we're done */
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
const msgnod* const end = (msgnod*) ((SCHAR*) *buckets + MSG_BUCKET);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (*nodes < end)
|
|
|
|
return;
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
/* Bucket is full -- write it out, propagate the split, and re-initialize */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
position = write_bucket(*buckets, MSG_BUCKET);
|
2003-11-05 10:02:33 +01:00
|
|
|
propagate(buckets + 1, nodes + 1, prior_code, position);
|
2001-05-23 15:26:42 +02:00
|
|
|
*nodes = *buckets;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
static SLONG write_bucket( const msgnod* bucket, USHORT length)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* w r i t e _ b u c k e t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Write stuff, return position of stuff written.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-11-05 10:02:33 +01:00
|
|
|
const USHORT padded_length = ROUNDUP(length, sizeof(SLONG));
|
|
|
|
const SLONG position = global_file_position;
|
|
|
|
int n = write(global_file, bucket, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (n == -1) {
|
2004-04-29 00:36:29 +02:00
|
|
|
fprintf(stderr, "IO error on write()\n");
|
2001-05-23 15:26:42 +02:00
|
|
|
exit(FINI_ERROR);
|
|
|
|
}
|
2008-12-21 00:50:22 +01:00
|
|
|
|
2008-03-16 14:38:58 +01:00
|
|
|
const SLONG zero_bytes = 0;
|
2003-11-05 10:02:33 +01:00
|
|
|
n = write(global_file, &zero_bytes, padded_length - length);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (n == -1) {
|
2004-04-29 00:36:29 +02:00
|
|
|
fprintf(stderr, "IO error on write()\n");
|
2001-05-23 15:26:42 +02:00
|
|
|
exit(FINI_ERROR);
|
|
|
|
}
|
2003-11-05 10:02:33 +01:00
|
|
|
global_file_position += padded_length;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
return position;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-05 10:02:33 +01:00
|
|
|
static void sanitize( TEXT* locale)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s a n i t i z e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Clean up a locale to make it acceptable for use in file names
|
2008-03-16 14:38:58 +01:00
|
|
|
* for Windows NT: replace any period with '_'
|
2003-11-05 10:02:33 +01:00
|
|
|
* Keep this in sync with gds.cpp
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
while (*locale) {
|
2008-03-16 14:38:58 +01:00
|
|
|
if (*locale == '.')
|
2001-05-23 15:26:42 +02:00
|
|
|
*locale = '_';
|
|
|
|
locale++;
|
|
|
|
}
|
|
|
|
}
|
2003-11-05 10:02:33 +01:00
|
|
|
|