~stewart/drizzle/embedded-innodb-create-select-transaction-arrgh

« back to all changes in this revision

Viewing changes to extra/comp_err.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2004 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
/*
 
17
  Written by Anjuta Widenius
 
18
*/
 
19
 
 
20
/*
 
21
  Creates one include file and multiple language-error message files from one
 
22
  multi-language text file.
 
23
*/
 
24
 
 
25
#include <my_global.h>
 
26
#include <m_ctype.h>
 
27
#include <my_sys.h>
 
28
#include <m_string.h>
 
29
#include <my_getopt.h>
 
30
#include <assert.h>
 
31
#include <my_dir.h>
 
32
 
 
33
#define MAX_ROWS  1000
 
34
#define HEADER_LENGTH 32                /* Length of header in errmsg.sys */
 
35
#define DEFAULT_CHARSET_DIR "../sql/share/charsets"
 
36
#define ER_PREFIX "ER_"
 
37
#define WARN_PREFIX "WARN_"
 
38
static char *OUTFILE= (char*) "errmsg.sys";
 
39
static char *HEADERFILE= (char*) "mysqld_error.h";
 
40
static char *NAMEFILE= (char*) "mysqld_ername.h";
 
41
static char *STATEFILE= (char*) "sql_state.h";
 
42
static char *TXTFILE= (char*) "../sql/share/errmsg.txt";
 
43
static char *DATADIRECTORY= (char*) "../sql/share/";
 
44
#ifndef DBUG_OFF
 
45
static char *default_dbug_option= (char*) "d:t:O,/tmp/comp_err.trace";
 
46
#endif
 
47
 
 
48
/* Header for errmsg.sys files */
 
49
uchar file_head[]= { 254, 254, 2, 1 };
 
50
/* Store positions to each error message row to store in errmsg.sys header */
 
51
uint file_pos[MAX_ROWS];
 
52
 
 
53
const char *empty_string= "";                   /* For empty states */
 
54
/*
 
55
  Default values for command line options. See getopt structure for definitions
 
56
  for these.
 
57
*/
 
58
 
 
59
const char *default_language= "eng";
 
60
int er_offset= 1000;
 
61
my_bool info_flag= 0;
 
62
 
 
63
/* Storage of one error message row (for one language) */
 
64
 
 
65
struct message
 
66
{
 
67
  char *lang_short_name;
 
68
  char *text;
 
69
};
 
70
 
 
71
 
 
72
/* Storage for languages and charsets (from start of error text file) */
 
73
 
 
74
struct languages
 
75
{
 
76
  char *lang_long_name;                         /* full name of the language */
 
77
  char *lang_short_name;                        /* abbreviation of the lang. */
 
78
  char *charset;                                /* Character set name */
 
79
  struct languages *next_lang;                  /* Pointer to next language */
 
80
};
 
81
 
 
82
 
 
83
/* Name, code and  texts (for all lang) for one error message */
 
84
 
 
85
struct errors
 
86
{
 
87
  const char *er_name;                  /* Name of the error (ER_HASHCK) */
 
88
  int d_code;                           /* Error code number */
 
89
  const char *sql_code1;                /* sql state */
 
90
  const char *sql_code2;                /* ODBC state */
 
91
  struct errors *next_error;            /* Pointer to next error */
 
92
  DYNAMIC_ARRAY msg;                    /* All language texts for this error */
 
93
};
 
94
 
 
95
 
 
96
static struct my_option my_long_options[]=
 
97
{
 
98
#ifdef DBUG_OFF
 
99
  {"debug", '#', "This is a non-debug version. Catch this and exit",
 
100
   0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
101
#else
 
102
  {"debug", '#', "Output debug log", (uchar**) & default_dbug_option,
 
103
   (uchar**) & default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
104
#endif
 
105
  {"debug-info", 'T', "Print some debug info at exit.", (uchar**) & info_flag,
 
106
   (uchar**) & info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
107
  {"help", '?', "Displays this help and exits.", 0, 0, 0, GET_NO_ARG,
 
108
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
109
  {"version", 'V', "Prints version", 0, 0, 0, GET_NO_ARG,
 
110
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
111
  {"charset", 'C', "Charset dir", (uchar**) & charsets_dir,
 
112
   (uchar**) & charsets_dir,
 
113
   0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
114
  {"in_file", 'F', "Input file", (uchar**) & TXTFILE, (uchar**) & TXTFILE,
 
115
   0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
116
  {"out_dir", 'D', "Output base directory", (uchar**) & DATADIRECTORY,
 
117
   (uchar**) & DATADIRECTORY,
 
118
   0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
119
  {"out_file", 'O', "Output filename (errmsg.sys)", (uchar**) & OUTFILE,
 
120
   (uchar**) & OUTFILE, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
121
  {"header_file", 'H', "mysqld_error.h file ", (uchar**) & HEADERFILE,
 
122
   (uchar**) & HEADERFILE, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
123
  {"name_file", 'N', "mysqld_ername.h file ", (uchar**) & NAMEFILE,
 
124
   (uchar**) & NAMEFILE, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
125
  {"state_file", 'S', "sql_state.h file", (uchar**) & STATEFILE,
 
126
   (uchar**) & STATEFILE, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
127
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
128
};
 
129
 
 
130
 
 
131
static struct languages *parse_charset_string(char *str);
 
132
static struct errors *parse_error_string(char *ptr, int er_count);
 
133
static struct message *parse_message_string(struct message *new_message,
 
134
                                            char *str);
 
135
static struct message *find_message(struct errors *err, const char *lang,
 
136
                                    my_bool no_default);
 
137
static int check_message_format(struct errors *err,
 
138
                                const char* mess);
 
139
static int parse_input_file(const char *file_name, struct errors **top_error,
 
140
                            struct languages **top_language);
 
141
static int get_options(int *argc, char ***argv);
 
142
static void print_version(void);
 
143
static void usage(void);
 
144
static my_bool get_one_option(int optid, const struct my_option *opt,
 
145
                              char *argument);
 
146
static char *parse_text_line(char *pos);
 
147
static int copy_rows(FILE * to, char *row, int row_nr, long start_pos);
 
148
static char *parse_default_language(char *str);
 
149
static uint parse_error_offset(char *str);
 
150
 
 
151
static char *skip_delimiters(char *str);
 
152
static char *get_word(char **str);
 
153
static char *find_end_of_word(char *str);
 
154
static void clean_up(struct languages *lang_head, struct errors *error_head);
 
155
static int create_header_files(struct errors *error_head);
 
156
static int create_sys_files(struct languages *lang_head,
 
157
                            struct errors *error_head, uint row_count);
 
158
 
 
159
 
 
160
int main(int argc, char *argv[])
 
161
{
 
162
  MY_INIT(argv[0]);
 
163
  {
 
164
    uint row_count;
 
165
    struct errors *error_head;
 
166
    struct languages *lang_head;
 
167
    DBUG_ENTER("main");
 
168
 
 
169
    charsets_dir= DEFAULT_CHARSET_DIR;
 
170
    my_umask_dir= 0777;
 
171
    if (get_options(&argc, &argv))
 
172
      DBUG_RETURN(1);
 
173
    if (!(row_count= parse_input_file(TXTFILE, &error_head, &lang_head)))
 
174
    {
 
175
      fprintf(stderr, "Failed to parse input file %s\n", TXTFILE);
 
176
      DBUG_RETURN(1);
 
177
    }
 
178
    if (lang_head == NULL || error_head == NULL)
 
179
    {
 
180
      fprintf(stderr, "Failed to parse input file %s\n", TXTFILE);
 
181
      DBUG_RETURN(1);
 
182
    }
 
183
 
 
184
    if (create_header_files(error_head))
 
185
    {
 
186
      fprintf(stderr, "Failed to create header files\n");
 
187
      DBUG_RETURN(1);
 
188
    }
 
189
    if (create_sys_files(lang_head, error_head, row_count))
 
190
    {
 
191
      fprintf(stderr, "Failed to create sys files\n");
 
192
      DBUG_RETURN(1);
 
193
    }
 
194
    clean_up(lang_head, error_head);
 
195
    DBUG_LEAVE;                 /* Can't use dbug after my_end() */
 
196
    my_end(info_flag ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
 
197
    return 0;
 
198
  }
 
199
}
 
200
 
 
201
 
 
202
static int create_header_files(struct errors *error_head)
 
203
{
 
204
  uint er_last;
 
205
  FILE *er_definef, *sql_statef, *er_namef;
 
206
  struct errors *tmp_error;
 
207
  DBUG_ENTER("create_header_files");
 
208
 
 
209
  if (!(er_definef= my_fopen(HEADERFILE, O_WRONLY, MYF(MY_WME))))
 
210
  {
 
211
    DBUG_RETURN(1);
 
212
  }
 
213
  if (!(sql_statef= my_fopen(STATEFILE, O_WRONLY, MYF(MY_WME))))
 
214
  {
 
215
    my_fclose(er_definef, MYF(0));
 
216
    DBUG_RETURN(1);
 
217
  }
 
218
  if (!(er_namef= my_fopen(NAMEFILE, O_WRONLY, MYF(MY_WME))))
 
219
  {
 
220
    my_fclose(er_definef, MYF(0));
 
221
    my_fclose(sql_statef, MYF(0));
 
222
    DBUG_RETURN(1);
 
223
  }
 
224
 
 
225
  fprintf(er_definef, "/* Autogenerated file, please don't edit */\n\n");
 
226
  fprintf(sql_statef, "/* Autogenerated file, please don't edit */\n\n");
 
227
  fprintf(er_namef, "/* Autogenerated file, please don't edit */\n\n");
 
228
 
 
229
  fprintf(er_definef, "#define ER_ERROR_FIRST %d\n", error_head->d_code);
 
230
 
 
231
  for (tmp_error= error_head; tmp_error; tmp_error= tmp_error->next_error)
 
232
  {
 
233
    /*
 
234
       generating mysqld_error.h
 
235
       fprintf() will automatically add \r on windows
 
236
    */
 
237
    fprintf(er_definef, "#define %s %d\n", tmp_error->er_name,
 
238
            tmp_error->d_code);
 
239
    er_last= tmp_error->d_code;
 
240
 
 
241
    /* generating sql_state.h file */
 
242
    if (tmp_error->sql_code1[0] || tmp_error->sql_code2[0])
 
243
      fprintf(sql_statef,
 
244
              "{ %-40s,\"%s\", \"%s\" },\n", tmp_error->er_name,
 
245
              tmp_error->sql_code1, tmp_error->sql_code2);
 
246
    /*generating er_name file */
 
247
    fprintf(er_namef, "{ \"%s\", %d },\n", tmp_error->er_name,
 
248
            tmp_error->d_code);
 
249
 
 
250
  }
 
251
  /* finishing off with mysqld_error.h */
 
252
  fprintf(er_definef, "#define ER_ERROR_LAST %d\n", er_last);
 
253
  my_fclose(er_definef, MYF(0));
 
254
  my_fclose(sql_statef, MYF(0));
 
255
  my_fclose(er_namef, MYF(0));
 
256
  DBUG_RETURN(0);
 
257
}
 
258
 
 
259
 
 
260
static int create_sys_files(struct languages *lang_head,
 
261
                            struct errors *error_head, uint row_count)
 
262
{
 
263
  FILE *to;
 
264
  uint csnum= 0, length, i, row_nr;
 
265
  uchar head[32];
 
266
  char outfile[FN_REFLEN], *outfile_end;
 
267
  long start_pos;
 
268
  struct message *tmp;
 
269
  struct languages *tmp_lang;
 
270
  struct errors *tmp_error;
 
271
 
 
272
  MY_STAT stat_info;
 
273
  DBUG_ENTER("create_sys_files");
 
274
 
 
275
  /*
 
276
     going over all languages and assembling corresponding error messages
 
277
  */
 
278
  for (tmp_lang= lang_head; tmp_lang; tmp_lang= tmp_lang->next_lang)
 
279
  {
 
280
 
 
281
    /* setting charset name */
 
282
    if (!(csnum= get_charset_number(tmp_lang->charset, MY_CS_PRIMARY)))
 
283
    {
 
284
      fprintf(stderr, "Unknown charset '%s' in '%s'\n", tmp_lang->charset,
 
285
              TXTFILE);
 
286
      DBUG_RETURN(1);
 
287
    }
 
288
 
 
289
    outfile_end= strxmov(outfile, DATADIRECTORY, 
 
290
                         tmp_lang->lang_long_name, NullS);
 
291
    if (!my_stat(outfile, &stat_info,MYF(0)))
 
292
    {
 
293
      if (my_mkdir(outfile, 0777,MYF(0)) < 0)
 
294
      {
 
295
        fprintf(stderr, "Can't create output directory for %s\n", 
 
296
                outfile);
 
297
        DBUG_RETURN(1);
 
298
      }
 
299
    }
 
300
 
 
301
    strxmov(outfile_end, FN_ROOTDIR, OUTFILE, NullS);
 
302
 
 
303
    if (!(to= my_fopen(outfile, O_WRONLY | FILE_BINARY, MYF(MY_WME))))
 
304
      DBUG_RETURN(1);
 
305
 
 
306
    /* 2 is for 2 bytes to store row position / error message */
 
307
    start_pos= (long) (HEADER_LENGTH + row_count * 2);
 
308
    fseek(to, start_pos, 0);
 
309
    row_nr= 0;
 
310
    for (tmp_error= error_head; tmp_error; tmp_error= tmp_error->next_error)
 
311
    {
 
312
      /* dealing with messages */
 
313
      tmp= find_message(tmp_error, tmp_lang->lang_short_name, FALSE);
 
314
 
 
315
      if (!tmp)
 
316
      {
 
317
        fprintf(stderr,
 
318
                "Did not find message for %s neither in %s nor in default "
 
319
                "language\n", tmp_error->er_name, tmp_lang->lang_short_name);
 
320
        goto err;
 
321
      }
 
322
      if (copy_rows(to, tmp->text, row_nr, start_pos))
 
323
      {
 
324
        fprintf(stderr, "Failed to copy rows to %s\n", outfile);
 
325
        goto err;
 
326
      }
 
327
      row_nr++;
 
328
    }
 
329
 
 
330
    /* continue with header of the errmsg.sys file */
 
331
    length= ftell(to) - HEADER_LENGTH - row_count * 2;
 
332
    bzero((uchar*) head, HEADER_LENGTH);
 
333
    bmove((uchar *) head, (uchar *) file_head, 4);
 
334
    head[4]= 1;
 
335
    int2store(head + 6, length);
 
336
    int2store(head + 8, row_count);
 
337
    head[30]= csnum;
 
338
 
 
339
    my_fseek(to, 0l, MY_SEEK_SET, MYF(0));
 
340
    if (my_fwrite(to, (uchar*) head, HEADER_LENGTH, MYF(MY_WME | MY_FNABP)))
 
341
      goto err;
 
342
 
 
343
    for (i= 0; i < row_count; i++)
 
344
    {
 
345
      int2store(head, file_pos[i]);
 
346
      if (my_fwrite(to, (uchar*) head, 2, MYF(MY_WME | MY_FNABP)))
 
347
        goto err;
 
348
    }
 
349
    my_fclose(to, MYF(0));
 
350
  }
 
351
  DBUG_RETURN(0);
 
352
 
 
353
err:
 
354
  my_fclose(to, MYF(0));
 
355
  DBUG_RETURN(1);
 
356
}
 
357
 
 
358
 
 
359
static void clean_up(struct languages *lang_head, struct errors *error_head)
 
360
{
 
361
  struct languages *tmp_lang, *next_language;
 
362
  struct errors *tmp_error, *next_error;
 
363
  uint count, i;
 
364
 
 
365
  my_free((uchar*) default_language, MYF(0));
 
366
 
 
367
  for (tmp_lang= lang_head; tmp_lang; tmp_lang= next_language)
 
368
  {
 
369
    next_language= tmp_lang->next_lang;
 
370
    my_free(tmp_lang->lang_short_name, MYF(0));
 
371
    my_free(tmp_lang->lang_long_name, MYF(0));
 
372
    my_free(tmp_lang->charset, MYF(0));
 
373
    my_free((uchar*) tmp_lang, MYF(0));
 
374
  }
 
375
 
 
376
  for (tmp_error= error_head; tmp_error; tmp_error= next_error)
 
377
  {
 
378
    next_error= tmp_error->next_error;
 
379
    count= (tmp_error->msg).elements;
 
380
    for (i= 0; i < count; i++)
 
381
    {
 
382
      struct message *tmp;
 
383
      tmp= dynamic_element(&tmp_error->msg, i, struct message*);
 
384
      my_free((uchar*) tmp->lang_short_name, MYF(0));
 
385
      my_free((uchar*) tmp->text, MYF(0));
 
386
    }
 
387
 
 
388
    delete_dynamic(&tmp_error->msg);
 
389
    if (tmp_error->sql_code1[0])
 
390
      my_free((uchar*) tmp_error->sql_code1, MYF(0));
 
391
    if (tmp_error->sql_code2[0])
 
392
      my_free((uchar*) tmp_error->sql_code2, MYF(0));
 
393
    my_free((uchar*) tmp_error->er_name, MYF(0));
 
394
    my_free((uchar*) tmp_error, MYF(0));
 
395
  }
 
396
}
 
397
 
 
398
 
 
399
static int parse_input_file(const char *file_name, struct errors **top_error,
 
400
                            struct languages **top_lang)
 
401
{
 
402
  FILE *file;
 
403
  char *str, buff[1000];
 
404
  struct errors *current_error= 0, **tail_error= top_error;
 
405
  struct message current_message;
 
406
  int rcount= 0;
 
407
  DBUG_ENTER("parse_input_file");
 
408
 
 
409
  *top_error= 0;
 
410
  *top_lang= 0;
 
411
  if (!(file= my_fopen(file_name, O_RDONLY | O_SHARE, MYF(MY_WME))))
 
412
    DBUG_RETURN(0);
 
413
 
 
414
  while ((str= fgets(buff, sizeof(buff), file)))
 
415
  {
 
416
    if (is_prefix(str, "language"))
 
417
    {
 
418
      if (!(*top_lang= parse_charset_string(str)))
 
419
      {
 
420
        fprintf(stderr, "Failed to parse the charset string!\n");
 
421
        DBUG_RETURN(0);
 
422
      }
 
423
      continue;
 
424
    }
 
425
    if (is_prefix(str, "start-error-number"))
 
426
    {
 
427
      if (!(er_offset= parse_error_offset(str)))
 
428
      {
 
429
        fprintf(stderr, "Failed to parse the error offset string!\n");
 
430
        DBUG_RETURN(0);
 
431
      }
 
432
      continue;
 
433
    }
 
434
    if (is_prefix(str, "default-language"))
 
435
    {
 
436
      if (!(default_language= parse_default_language(str)))
 
437
      {
 
438
        DBUG_PRINT("info", ("default_slang: %s", default_language));
 
439
        fprintf(stderr,
 
440
                "Failed to parse the default language line. Aborting\n");
 
441
        DBUG_RETURN(0);
 
442
      }
 
443
      continue;
 
444
    }
 
445
 
 
446
    if (*str == '\t' || *str == ' ')
 
447
    {
 
448
      /* New error message in another language for previous error */
 
449
      if (!current_error)
 
450
      {
 
451
        fprintf(stderr, "Error in the input file format\n");
 
452
        DBUG_RETURN(0);
 
453
      }
 
454
      if (!parse_message_string(&current_message, str))
 
455
      {
 
456
        fprintf(stderr, "Failed to parse message string for error '%s'",
 
457
                current_error->er_name);
 
458
        DBUG_RETURN(0);
 
459
      }
 
460
      if (find_message(current_error, current_message.lang_short_name, TRUE))
 
461
      {
 
462
        fprintf(stderr, "Duplicate message string for error '%s'"
 
463
                        " in language '%s'\n",
 
464
                current_error->er_name, current_message.lang_short_name);
 
465
        DBUG_RETURN(0);
 
466
      }
 
467
      if (check_message_format(current_error, current_message.text))
 
468
      {
 
469
        fprintf(stderr, "Wrong formatspecifier of error message string"
 
470
                        " for error '%s' in language '%s'\n",
 
471
                current_error->er_name, current_message.lang_short_name);
 
472
        DBUG_RETURN(0);
 
473
      }
 
474
      if (insert_dynamic(&current_error->msg, (uchar *) & current_message))
 
475
        DBUG_RETURN(0);
 
476
      continue;
 
477
    }
 
478
    if (is_prefix(str, ER_PREFIX) || is_prefix(str, WARN_PREFIX))
 
479
    {
 
480
      if (!(current_error= parse_error_string(str, rcount)))
 
481
      {
 
482
        fprintf(stderr, "Failed to parse the error name string\n");
 
483
        DBUG_RETURN(0);
 
484
      }
 
485
      rcount++;                         /* Count number of unique errors */
 
486
 
 
487
      /* add error to the list */
 
488
      *tail_error= current_error;
 
489
      tail_error= &current_error->next_error;
 
490
      continue;
 
491
    }
 
492
    if (*str == '#' || *str == '\n')
 
493
      continue;                                 /* skip comment or empty lines */
 
494
 
 
495
    fprintf(stderr, "Wrong input file format. Stop!\nLine: %s\n", str);
 
496
    DBUG_RETURN(0);
 
497
  }
 
498
  *tail_error= 0;                               /* Mark end of list */
 
499
 
 
500
  my_fclose(file, MYF(0));
 
501
  DBUG_RETURN(rcount);
 
502
}
 
503
 
 
504
 
 
505
static uint parse_error_offset(char *str)
 
506
{
 
507
  char *soffset, *end;
 
508
  int error;
 
509
  uint ioffset;
 
510
 
 
511
  DBUG_ENTER("parse_error_offset");
 
512
  /* skipping the "start-error-number" keyword and spaces after it */
 
513
  str= find_end_of_word(str);
 
514
  str= skip_delimiters(str);
 
515
 
 
516
  if (!*str)
 
517
    DBUG_RETURN(0);     /* Unexpected EOL: No error number after the keyword */
 
518
 
 
519
  /* reading the error offset */
 
520
  if (!(soffset= get_word(&str)))
 
521
    DBUG_RETURN(0);                             /* OOM: Fatal error */
 
522
  DBUG_PRINT("info", ("default_error_offset: %s", soffset));
 
523
 
 
524
  /* skipping space(s) and/or tabs after the error offset */
 
525
  str= skip_delimiters(str);
 
526
  DBUG_PRINT("info", ("str: %s", str));
 
527
  if (*str)
 
528
  {
 
529
    /* The line does not end with the error offset -> error! */
 
530
    fprintf(stderr, "The error offset line does not end with an error offset");
 
531
    DBUG_RETURN(0);
 
532
  }
 
533
  DBUG_PRINT("info", ("str: %s", str));
 
534
 
 
535
  end= 0;
 
536
  ioffset= (uint) my_strtoll10(soffset, &end, &error);
 
537
  my_free((uchar*) soffset, MYF(0));
 
538
  DBUG_RETURN(ioffset);
 
539
}
 
540
 
 
541
 
 
542
/* Parsing of the default language line. e.g. "default-language eng" */
 
543
 
 
544
static char *parse_default_language(char *str)
 
545
{
 
546
  char *slang;
 
547
 
 
548
  DBUG_ENTER("parse_default_language");
 
549
  /* skipping the "default-language" keyword */
 
550
  str= find_end_of_word(str);
 
551
  /* skipping space(s) and/or tabs after the keyword */
 
552
  str= skip_delimiters(str);
 
553
  if (!*str)
 
554
  {
 
555
    fprintf(stderr,
 
556
            "Unexpected EOL: No short language name after the keyword\n");
 
557
    DBUG_RETURN(0);
 
558
  }
 
559
 
 
560
  /* reading the short language tag */
 
561
  if (!(slang= get_word(&str)))
 
562
    DBUG_RETURN(0);                             /* OOM: Fatal error */
 
563
  DBUG_PRINT("info", ("default_slang: %s", slang));
 
564
 
 
565
  str= skip_delimiters(str);
 
566
  DBUG_PRINT("info", ("str: %s", str));
 
567
  if (*str)
 
568
  {
 
569
    fprintf(stderr,
 
570
            "The default language line does not end with short language "
 
571
            "name\n");
 
572
    DBUG_RETURN(0);
 
573
  }
 
574
  DBUG_PRINT("info", ("str: %s", str));
 
575
  DBUG_RETURN(slang);
 
576
}
 
577
 
 
578
 
 
579
/*
 
580
  Find the message in a particular language
 
581
 
 
582
  SYNOPSIS
 
583
    find_message()
 
584
    err             Error to find message for
 
585
    lang            Language of message to find
 
586
    no_default      Don't return default (English) if does not exit
 
587
 
 
588
  RETURN VALUE
 
589
    Returns the message structure if one is found, or NULL if not.
 
590
*/
 
591
static struct message *find_message(struct errors *err, const char *lang,
 
592
                                    my_bool no_default)
 
593
{
 
594
  struct message *tmp, *return_val= 0;
 
595
  uint i, count;
 
596
  DBUG_ENTER("find_message");
 
597
 
 
598
  count= (err->msg).elements;
 
599
  for (i= 0; i < count; i++)
 
600
  {
 
601
    tmp= dynamic_element(&err->msg, i, struct message*);
 
602
 
 
603
    if (!strcmp(tmp->lang_short_name, lang))
 
604
      DBUG_RETURN(tmp);
 
605
    if (!strcmp(tmp->lang_short_name, default_language))
 
606
    {
 
607
      DBUG_ASSERT(tmp->text[0] != 0);
 
608
      return_val= tmp;
 
609
    }
 
610
  }
 
611
  DBUG_RETURN(no_default ? NULL : return_val);
 
612
}
 
613
 
 
614
 
 
615
 
 
616
/*
 
617
  Check message format specifiers against error message for
 
618
  previous language
 
619
 
 
620
  SYNOPSIS
 
621
    checksum_format_specifier()
 
622
    msg            String for which to generate checksum
 
623
                   for the format specifiers
 
624
 
 
625
  RETURN VALUE
 
626
    Returns the checksum for all the characters of the
 
627
    format specifiers
 
628
 
 
629
    Ex.
 
630
     "text '%-64.s' text part 2 %d'"
 
631
            ^^^^^^              ^^
 
632
            characters will be xored to form checksum
 
633
 
 
634
    NOTE:
 
635
      Does not support format specifiers with positional args
 
636
      like "%2$s" but that is not yet supported by my_vsnprintf
 
637
      either.
 
638
*/
 
639
 
 
640
static ha_checksum checksum_format_specifier(const char* msg)
 
641
{
 
642
  ha_checksum chksum= 0;
 
643
  const char* p= msg;
 
644
  const char* start= 0;
 
645
  int num_format_specifiers= 0;
 
646
  while (*p)
 
647
  {
 
648
 
 
649
    if (*p == '%')
 
650
    {
 
651
      start= p+1; /* Entering format specifier */
 
652
      num_format_specifiers++;
 
653
    }
 
654
    else if (start)
 
655
    {
 
656
      switch(*p)
 
657
      {
 
658
      case 'd':
 
659
      case 'u':
 
660
      case 'x':
 
661
      case 's':
 
662
        chksum= my_checksum(chksum, start, p-start);
 
663
        start= 0; /* Not in format specifier anymore */
 
664
        break;
 
665
 
 
666
      default:
 
667
        break;
 
668
      }
 
669
    }
 
670
 
 
671
    p++;
 
672
  }
 
673
 
 
674
  if (start)
 
675
  {
 
676
    /* Still inside a format specifier after end of string */
 
677
 
 
678
    fprintf(stderr, "Still inside formatspecifier after end of string"
 
679
                    " in'%s'\n", msg);
 
680
    DBUG_ASSERT(start==0);
 
681
  }
 
682
 
 
683
  /* Add number of format specifiers to checksum as extra safeguard */
 
684
  chksum+= num_format_specifiers;
 
685
 
 
686
  return chksum;
 
687
}
 
688
 
 
689
 
 
690
/*
 
691
  Check message format specifiers against error message for
 
692
  previous language
 
693
 
 
694
  SYNOPSIS
 
695
    check_message_format()
 
696
    err             Error to check message for
 
697
    mess            Message to check
 
698
 
 
699
  RETURN VALUE
 
700
    Returns 0 if no previous error message or message format is ok
 
701
*/
 
702
static int check_message_format(struct errors *err,
 
703
                                const char* mess)
 
704
{
 
705
  struct message *first;
 
706
  DBUG_ENTER("check_message_format");
 
707
 
 
708
  /*  Get first message(if any) */
 
709
  if ((err->msg).elements == 0)
 
710
    DBUG_RETURN(0); /* No previous message to compare against */
 
711
 
 
712
  first= dynamic_element(&err->msg, 0, struct message*);
 
713
  DBUG_ASSERT(first != NULL);
 
714
 
 
715
  if (checksum_format_specifier(first->text) !=
 
716
      checksum_format_specifier(mess))
 
717
  {
 
718
    /* Check sum of format specifiers failed, they should be equal */
 
719
    DBUG_RETURN(1);
 
720
  }
 
721
  DBUG_RETURN(0);
 
722
}
 
723
 
 
724
 
 
725
/*
 
726
  Skips spaces and or tabs till the beginning of the next word
 
727
  Returns pointer to the beginning of the first character of the word
 
728
*/
 
729
 
 
730
static char *skip_delimiters(char *str)
 
731
{
 
732
  DBUG_ENTER("skip_delimiters");
 
733
  for (;
 
734
       *str == ' ' || *str == ',' || *str == '\t' || *str == '\r' ||
 
735
       *str == '\n' || *str == '='; str++)
 
736
    ;
 
737
  DBUG_RETURN(str);
 
738
}
 
739
 
 
740
 
 
741
/*
 
742
  Skips all characters till meets with space, or tab, or EOL
 
743
*/
 
744
 
 
745
static char *find_end_of_word(char *str)
 
746
{
 
747
  DBUG_ENTER("find_end_of_word");
 
748
  for (;
 
749
       *str != ' ' && *str != '\t' && *str != '\n' && *str != '\r' && *str &&
 
750
       *str != ',' && *str != ';' && *str != '='; str++)
 
751
    ;
 
752
  DBUG_RETURN(str);
 
753
}
 
754
 
 
755
 
 
756
/* Read the word starting from *str */
 
757
 
 
758
static char *get_word(char **str)
 
759
{
 
760
  char *start= *str;
 
761
  DBUG_ENTER("get_word");
 
762
 
 
763
  *str= find_end_of_word(start);
 
764
  DBUG_RETURN(my_strndup(start, (uint) (*str - start),
 
765
                                    MYF(MY_WME | MY_FAE)));
 
766
}
 
767
 
 
768
 
 
769
/*
 
770
  Parsing the string with short_lang - message text. Code - to
 
771
  remember to which error does the text belong
 
772
*/
 
773
 
 
774
static struct message *parse_message_string(struct message *new_message,
 
775
                                            char *str)
 
776
{
 
777
  char *start;
 
778
 
 
779
  DBUG_ENTER("parse_message_string");
 
780
  DBUG_PRINT("enter", ("str: %s", str));
 
781
 
 
782
  /*skip space(s) and/or tabs in the beginning */
 
783
  while (*str == ' ' || *str == '\t' || *str == '\n')
 
784
    str++;
 
785
 
 
786
  if (!*str)
 
787
  {
 
788
    /* It was not a message line, but an empty line. */
 
789
    DBUG_PRINT("info", ("str: %s", str));
 
790
    DBUG_RETURN(0);
 
791
  }
 
792
 
 
793
  /* reading the short lang */
 
794
  start= str;
 
795
  while (*str != ' ' && *str != '\t' && *str)
 
796
    str++;
 
797
  if (!(new_message->lang_short_name=
 
798
        my_strndup(start, (uint) (str - start),
 
799
                              MYF(MY_WME | MY_FAE))))
 
800
    DBUG_RETURN(0);                             /* Fatal error */
 
801
  DBUG_PRINT("info", ("msg_slang: %s", new_message->lang_short_name));
 
802
 
 
803
  /*skip space(s) and/or tabs after the lang */
 
804
  while (*str == ' ' || *str == '\t' || *str == '\n')
 
805
    str++;
 
806
 
 
807
  if (*str != '"')
 
808
  {
 
809
    fprintf(stderr, "Unexpected EOL");
 
810
    DBUG_PRINT("info", ("str: %s", str));
 
811
    DBUG_RETURN(0);
 
812
  }
 
813
 
 
814
  /* reading the text */
 
815
  start= str + 1;
 
816
  str= parse_text_line(start);
 
817
 
 
818
  if (!(new_message->text= my_strndup(start, (uint) (str - start),
 
819
                                                 MYF(MY_WME | MY_FAE))))
 
820
    DBUG_RETURN(0);                             /* Fatal error */
 
821
  DBUG_PRINT("info", ("msg_text: %s", new_message->text));
 
822
 
 
823
  DBUG_RETURN(new_message);
 
824
}
 
825
 
 
826
 
 
827
/*
 
828
  Parsing the string with error name and codes; returns the pointer to
 
829
  the errors struct
 
830
*/
 
831
 
 
832
static struct errors *parse_error_string(char *str, int er_count)
 
833
{
 
834
  struct errors *new_error;
 
835
  char *start;
 
836
  DBUG_ENTER("parse_error_string");
 
837
  DBUG_PRINT("enter", ("str: %s", str));
 
838
 
 
839
  /* create a new element */
 
840
  new_error= (struct errors *) my_malloc(sizeof(*new_error), MYF(MY_WME));
 
841
 
 
842
  if (my_init_dynamic_array(&new_error->msg, sizeof(struct message), 0, 0))
 
843
    DBUG_RETURN(0);                             /* OOM: Fatal error */
 
844
 
 
845
  /* getting the error name */
 
846
  start= str;
 
847
  str= skip_delimiters(str);
 
848
 
 
849
  if (!(new_error->er_name= get_word(&str)))
 
850
    DBUG_RETURN(0);                             /* OOM: Fatal error */
 
851
  DBUG_PRINT("info", ("er_name: %s", new_error->er_name));
 
852
 
 
853
  str= skip_delimiters(str);
 
854
 
 
855
  /* getting the code1 */
 
856
 
 
857
  new_error->d_code= er_offset + er_count;
 
858
  DBUG_PRINT("info", ("d_code: %d", new_error->d_code));
 
859
 
 
860
  str= skip_delimiters(str);
 
861
 
 
862
  /* if we reached EOL => no more codes, but this can happen */
 
863
  if (!*str)
 
864
  {
 
865
    new_error->sql_code1= empty_string;
 
866
    new_error->sql_code2= empty_string;
 
867
    DBUG_PRINT("info", ("str: %s", str));
 
868
    DBUG_RETURN(new_error);
 
869
  }
 
870
 
 
871
  /* getting the sql_code 1 */
 
872
 
 
873
  if (!(new_error->sql_code1= get_word(&str)))
 
874
    DBUG_RETURN(0);                             /* OOM: Fatal error */
 
875
  DBUG_PRINT("info", ("sql_code1: %s", new_error->sql_code1));
 
876
 
 
877
  str= skip_delimiters(str);
 
878
 
 
879
  /* if we reached EOL => no more codes, but this can happen */
 
880
  if (!*str)
 
881
  {
 
882
    new_error->sql_code2= empty_string;
 
883
    DBUG_PRINT("info", ("str: %s", str));
 
884
    DBUG_RETURN(new_error);
 
885
  }
 
886
 
 
887
  /* getting the sql_code 2 */
 
888
  if (!(new_error->sql_code2= get_word(&str)))
 
889
    DBUG_RETURN(0);                             /* OOM: Fatal error */
 
890
  DBUG_PRINT("info", ("sql_code2: %s", new_error->sql_code2));
 
891
 
 
892
  str= skip_delimiters(str);
 
893
  if (*str)
 
894
  {
 
895
    fprintf(stderr, "The error line did not end with sql/odbc code!");
 
896
    DBUG_RETURN(0);
 
897
  }
 
898
 
 
899
  DBUG_RETURN(new_error);
 
900
}
 
901
 
 
902
 
 
903
/* 
 
904
  Parsing the string with full lang name/short lang name/charset;
 
905
  returns pointer to the language structure
 
906
*/
 
907
 
 
908
static struct languages *parse_charset_string(char *str)
 
909
{
 
910
  struct languages *head=0, *new_lang;
 
911
  DBUG_ENTER("parse_charset_string");
 
912
  DBUG_PRINT("enter", ("str: %s", str));
 
913
 
 
914
  /* skip over keyword */
 
915
  str= find_end_of_word(str);
 
916
  if (!*str)
 
917
  {
 
918
    /* unexpected EOL */
 
919
    DBUG_PRINT("info", ("str: %s", str));
 
920
    DBUG_RETURN(0);
 
921
  }
 
922
 
 
923
  str= skip_delimiters(str);
 
924
  if (!(*str != ';' && *str))
 
925
    DBUG_RETURN(0);
 
926
 
 
927
  do
 
928
  {
 
929
    /*creating new element of the linked list */
 
930
    new_lang= (struct languages *) my_malloc(sizeof(*new_lang), MYF(MY_WME));
 
931
    new_lang->next_lang= head;
 
932
    head= new_lang;
 
933
 
 
934
    /* get the full language name */
 
935
 
 
936
    if (!(new_lang->lang_long_name= get_word(&str)))
 
937
      DBUG_RETURN(0);                           /* OOM: Fatal error */
 
938
 
 
939
    DBUG_PRINT("info", ("long_name: %s", new_lang->lang_long_name));
 
940
 
 
941
    /* getting the short name for language */
 
942
    str= skip_delimiters(str);
 
943
    if (!*str)
 
944
      DBUG_RETURN(0);                           /* Error: No space or tab */
 
945
 
 
946
    if (!(new_lang->lang_short_name= get_word(&str)))
 
947
      DBUG_RETURN(0);                           /* OOM: Fatal error */
 
948
    DBUG_PRINT("info", ("short_name: %s", new_lang->lang_short_name));
 
949
 
 
950
    /* getting the charset name */
 
951
    str= skip_delimiters(str);
 
952
    if (!(new_lang->charset= get_word(&str)))
 
953
      DBUG_RETURN(0);                           /* Fatal error */
 
954
    DBUG_PRINT("info", ("charset: %s", new_lang->charset));
 
955
 
 
956
    /* skipping space, tab or "," */
 
957
    str= skip_delimiters(str);
 
958
  }
 
959
  while (*str != ';' && *str);
 
960
 
 
961
  DBUG_PRINT("info", ("long name: %s", new_lang->lang_long_name));
 
962
  DBUG_RETURN(head);
 
963
}
 
964
 
 
965
 
 
966
/* Read options */
 
967
 
 
968
static void print_version(void)
 
969
{
 
970
  DBUG_ENTER("print_version");
 
971
  printf("%s  (Compile errormessage)  Ver %s\n", my_progname, "2.0");
 
972
  DBUG_VOID_RETURN;
 
973
}
 
974
 
 
975
 
 
976
static my_bool
 
977
get_one_option(int optid, const struct my_option *opt __attribute__ ((unused)),
 
978
               char *argument __attribute__ ((unused)))
 
979
{
 
980
  DBUG_ENTER("get_one_option");
 
981
  switch (optid) {
 
982
  case 'V':
 
983
    print_version();
 
984
    exit(0);
 
985
    break;
 
986
  case '?':
 
987
    usage();
 
988
    exit(0);
 
989
    break;
 
990
  case '#':
 
991
    DBUG_PUSH(argument ? argument : default_dbug_option);
 
992
    break;
 
993
  }
 
994
  DBUG_RETURN(0);
 
995
}
 
996
 
 
997
 
 
998
static void usage(void)
 
999
{
 
1000
  DBUG_ENTER("usage");
 
1001
  print_version();
 
1002
  printf("This software comes with ABSOLUTELY NO WARRANTY. "
 
1003
         "This is free software,\n"
 
1004
         "and you are welcome to modify and redistribute it under the GPL license.\n"
 
1005
         "Usage:\n");
 
1006
  my_print_help(my_long_options);
 
1007
  my_print_variables(my_long_options);
 
1008
  DBUG_VOID_RETURN;
 
1009
}
 
1010
 
 
1011
 
 
1012
static int get_options(int *argc, char ***argv)
 
1013
{
 
1014
  int ho_error;
 
1015
  DBUG_ENTER("get_options");
 
1016
 
 
1017
  if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
 
1018
    DBUG_RETURN(ho_error);
 
1019
  DBUG_RETURN(0);
 
1020
}
 
1021
 
 
1022
 
 
1023
/*
 
1024
  Read rows and remember them until row that start with char Converts
 
1025
  row as a C-compiler would convert a textstring
 
1026
*/
 
1027
 
 
1028
static char *parse_text_line(char *pos)
 
1029
{
 
1030
  int i, nr;
 
1031
  char *row= pos;
 
1032
  DBUG_ENTER("parse_text_line");
 
1033
 
 
1034
  while (*pos)
 
1035
  {
 
1036
    if (*pos == '\\')
 
1037
    {
 
1038
      switch (*++pos) {
 
1039
      case '\\':
 
1040
      case '"':
 
1041
        VOID(strmov(pos - 1, pos));
 
1042
        break;
 
1043
      case 'n':
 
1044
        pos[-1]= '\n';
 
1045
        VOID(strmov(pos, pos + 1));
 
1046
        break;
 
1047
      default:
 
1048
        if (*pos >= '0' && *pos < '8')
 
1049
        {
 
1050
          nr= 0;
 
1051
          for (i= 0; i < 3 && (*pos >= '0' && *pos < '8'); i++)
 
1052
            nr= nr * 8 + (*(pos++) - '0');
 
1053
          pos -= i;
 
1054
          pos[-1]= nr;
 
1055
          VOID(strmov(pos, pos + i));
 
1056
        }
 
1057
        else if (*pos)
 
1058
          VOID(strmov(pos - 1, pos));           /* Remove '\' */
 
1059
      }
 
1060
    }
 
1061
    else
 
1062
      pos++;
 
1063
  }
 
1064
  while (pos > row + 1 && *pos != '"')
 
1065
    pos--;
 
1066
  *pos= 0;
 
1067
  DBUG_RETURN(pos);
 
1068
}
 
1069
 
 
1070
 
 
1071
/* Copy rows from memory to file and remember position */
 
1072
 
 
1073
static int copy_rows(FILE *to, char *row, int row_nr, long start_pos)
 
1074
{
 
1075
  DBUG_ENTER("copy_rows");
 
1076
 
 
1077
  file_pos[row_nr]= (int) (ftell(to) - start_pos);
 
1078
  if (fputs(row, to) == EOF || fputc('\0', to) == EOF)
 
1079
  {
 
1080
    fprintf(stderr, "Can't write to outputfile\n");
 
1081
    DBUG_RETURN(1);
 
1082
  }
 
1083
 
 
1084
  DBUG_RETURN(0);
 
1085
}