home *** CD-ROM | disk | FTP | other *** search
/ Mega Top 1 / os2_top1.zip / os2_top1 / APPS / TEKST / GRECODE / CHARSET.C < prev    next >
C/C++ Source or Header  |  1993-12-22  |  14KB  |  561 lines

  1. /* Conversion of files between different charsets and usages.
  2.    Copyright (C) 1990, 1993 Free Software Foundation, Inc.
  3.    Francois Pinard <pinard@iro.umontreal.ca>, 1993.
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful, but
  11.    WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.    General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19.  
  20. #include "recode.h"
  21.  
  22. /* Maximum number of charset values.  */
  23. #define MAX_CHARSETS 200
  24.  
  25. /* Hash table size for charset names.  */
  26. #define HASH_TABLE_SIZE 997
  27.  
  28. /* Maximum number of characters per 10646 symbol.  */
  29. #define MAX_SYMBOL_SIZE 9
  30.  
  31. /* Known character sets.  */
  32.  
  33. struct hash
  34.   {
  35.     const char *name;        /* charset or alias name, or NULL */
  36.     CHARSET *charset;        /* associated charset */
  37.     struct hash *next;        /* next index in table, or NULL */
  38.   };
  39. struct hash hash_table[HASH_TABLE_SIZE];
  40. CHARSET charset_array[MAX_CHARSETS];
  41. int number_of_charsets;
  42.  
  43. /* Array of strings ready for argmatch.  */
  44. static const char **argmatch_array;
  45.  
  46. #include "charset.h"
  47.  
  48. /*--------------------------------------.
  49. | Prepare charsets for initialization.  |
  50. `--------------------------------------*/
  51.  
  52. void
  53. prepare_charset_initialization (void)
  54. {
  55.   int counter;
  56.  
  57.   for (counter = 0; counter < HASH_TABLE_SIZE; counter++)
  58.     {
  59.       hash_table[counter].name = NULL;
  60.       hash_table[counter].next = NULL;
  61.     }
  62.   number_of_charsets = 0;
  63. }
  64.  
  65. /*-----------------------------------------------------------------------.
  66. | Return a newly allocated copy of charset NAME, with upper case letters |
  67. | turned into lower case, and all non alphanumeric discarded.         |
  68. `-----------------------------------------------------------------------*/
  69.  
  70. static char *
  71. cleanup_charset_name (const char *name)
  72. {
  73.   char *result;
  74.   char *out;
  75.   const char *in;
  76.   int character;
  77.  
  78.   result = xmalloc (strlen (name) + 1);
  79.   out = result;
  80.   for (in = name; *in; in++)
  81.     {
  82.       character = *(const unsigned char *) in;
  83.       if ((character >= 'a' && character <= 'z')
  84.       || (character >= '0' && character <= '9'))
  85.     *out++ = character;
  86.       else if (character >= 'A' && character <= 'Z')
  87.     *out++ = character - 'A' + 'a';
  88.     }
  89.   *out = '\0';
  90.   return result;
  91. }
  92.  
  93. /*-----------------------------------.
  94. | Return a hash index for a STRING.  |
  95. `-----------------------------------*/
  96.  
  97. /* The hash function is naive, but sufficient for our purpose.  */
  98.  
  99. static int
  100. hash_string (const char *string)
  101. {
  102.   int value;
  103.  
  104.   value = 0;
  105.   for (; *string; string++)
  106.     value = ((value * 31 + (int) *(const unsigned char *) string)
  107.          % HASH_TABLE_SIZE);
  108.   return value;
  109. }
  110.  
  111. /*--------------------------------------------------------------------------.
  112. | Return the charset from its NAME or alias name.  If it does not already   |
  113. | exist, add a new charset entry and initialize it with a brand new value.  |
  114. `--------------------------------------------------------------------------*/
  115.  
  116. CHARSET *
  117. find_charset (const char *name)
  118. {
  119.   char *hashname;
  120.   struct hash *hash;
  121.   CHARSET *charset;
  122.  
  123.   /* Search the whole hash bucket and return any match.  */
  124.  
  125.   hashname = cleanup_charset_name (name);
  126.   for (hash = hash_table + hash_string (hashname);
  127.        hash->name;
  128.        hash = hash->next)
  129.     {
  130.       if (strcmp (hashname, hash->name) == 0)
  131.     {
  132.       free (hashname);
  133.       return hash->charset;
  134.     }
  135.       if (!hash->next)
  136.     break;
  137.     }
  138.  
  139.   /* A new charset has to be created.  */
  140.  
  141.   if (number_of_charsets == MAX_CHARSETS)
  142.     error (EXIT_FAILURE, 0, "MAX_CHARSETS is too small");
  143.  
  144.   charset = charset_array + number_of_charsets++;
  145.  
  146.   /* If the current slot is already used, create an overflow entry and
  147.      initialize it enough so it could be taken for the current slot.  */
  148.  
  149.   if (hash->name)
  150.     {
  151.       hash->next = (struct hash *) xmalloc (sizeof (struct hash));
  152.       hash = hash->next;
  153.       hash->next = NULL;
  154.     }
  155.  
  156.   /* Initialize the current slot with the new charset.  */
  157.  
  158.   hash->name = hashname;
  159.   hash->charset = charset;
  160.  
  161.   charset->name = name;
  162.   charset->ignore = 0;
  163.   charset->table = NULL;
  164.  
  165.   return charset;
  166. }
  167.  
  168. /*-------------------------------------------------------------------------.
  169. | Have NAME as an alternate charset name for OLD_NAME.  Create OLD_NAME if |
  170. | it does not exist already.                           |
  171. `-------------------------------------------------------------------------*/
  172.  
  173. void
  174. declare_alias (const char *name, const char *old_name)
  175. {
  176.   char *hashname;
  177.   struct hash *hash;
  178.   CHARSET *old_charset;
  179.  
  180.   /* Find the old value.  */
  181.  
  182.   old_charset = find_charset (old_name);
  183.  
  184.   /* Search the whole hash bucket.  */
  185.  
  186.   hashname = cleanup_charset_name (name);
  187.   for (hash = hash_table + hash_string (hashname);
  188.        hash->name;
  189.        hash = hash->next)
  190.     {
  191.       if (strcmp (hashname, hash->name) == 0)
  192.     {
  193.       if (hash->charset != old_charset)
  194.         error (EXIT_FAILURE, 0, "Charset %s already exists and is not %s",
  195.            name, old_name);
  196.       free (hashname);
  197.       return;
  198.     }
  199.       if (!hash->next)
  200.     break;
  201.     }
  202.  
  203.   /* If the current slot is already used, create an overflow entry and
  204.      initialize it enough so it could be taken for the current slot.  */
  205.  
  206.   if (hash->name)
  207.     {
  208.       hash->next = (struct hash *) xmalloc (sizeof (struct hash));
  209.       hash = hash->next;
  210.       hash->next = NULL;
  211.     }
  212.  
  213.   /* Initialize the current slot with the new charset.  */
  214.  
  215.   hash->name = hashname;
  216.   hash->charset = old_charset;
  217. }
  218.  
  219. /*------------------------------------------.
  220. | Construct the string array for argmatch.  |
  221. `------------------------------------------*/
  222.  
  223. void
  224. make_argmatch_array (void)
  225. {
  226.   struct hash *hash;        /* cursor in charsets */
  227.   int number;            /* number of strings */
  228.   int counter;            /* all purpose counter */
  229.  
  230.   /* Count how many strings we need.  */
  231.  
  232.   number = 0;
  233.   for (counter = 0; counter < HASH_TABLE_SIZE; counter++)
  234.     for (hash = hash_table + counter;
  235.      hash && hash->name;
  236.      hash = hash->next)
  237.       number++;
  238.  
  239.   /* Allocate the argmatch array, with place for a NULL sentinel.  */
  240.  
  241.   argmatch_array
  242.     = (const char **) xmalloc ((number + 1) * sizeof (const char *));
  243.  
  244.   /* Fill in the array.  */
  245.  
  246.   number = 0;
  247.   for (counter = 0; counter < HASH_TABLE_SIZE; counter++)
  248.     for (hash = hash_table + counter;
  249.      hash && hash->name;
  250.      hash = hash->next)
  251.       argmatch_array[number++] = hash->name;
  252.  
  253.   argmatch_array[number] = NULL;
  254. }
  255.  
  256. /*-----------------------------------------------------------------------.
  257. | Return the NAME of a charset, un-abbreviated and cleaned up.  Diagnose |
  258. | and abort if this cannot be done successfully.  A NULL or empty string |
  259. | means the default charset, if this default charset is defined.     |
  260. `-----------------------------------------------------------------------*/
  261.  
  262. const char *
  263. clean_charset_name (const char *name)
  264. {
  265.   char *hashname;
  266.   int ordinal;
  267.  
  268.   /* Notify usage that we are decoding charsets.  */
  269.  
  270.   decoding_charset_flag = 1;
  271.  
  272.   /* Look for a match.  */
  273.  
  274.   if (!name)
  275.     name = "";
  276. #ifdef DEFAULT_CHARSET
  277.   if (!*name)
  278.     name = DEFAULT_CHARSET;
  279. #endif
  280.   hashname = cleanup_charset_name (name);
  281.   ordinal = argmatch (hashname, argmatch_array);
  282.   free (hashname);
  283.  
  284.   /* Diagnose any match error.  */
  285.  
  286.   switch (ordinal)
  287.     {
  288.     case -2:
  289.       error (0, 0, "Ambiguous charset `%s'", name);
  290.       usage (EXIT_FAILURE);
  291.  
  292.     case -1:
  293.       error (0, 0, "Unknown charset `%s'", name);
  294.       usage (EXIT_FAILURE);
  295.     }
  296.  
  297.   /* Notify usage that we are finished with charsets, then return.  */
  298.  
  299.   decoding_charset_flag = 0;
  300.   return argmatch_array[ordinal];
  301. }
  302.  
  303. /*----------------------------------------------------------------------.
  304. | Order two struct hash's, using the true charset name as the first key |
  305. | and the current name as the second key.                    |
  306. `----------------------------------------------------------------------*/
  307.  
  308. static int
  309. compare_struct_hash (const void *void_first, const void *void_second)
  310. {
  311.   int value;
  312.  
  313.   value = strcmp (((const struct hash *) void_first)->charset->name,
  314.           ((const struct hash *) void_second)->charset->name);
  315.   if (value != 0)
  316.     return value;
  317.   
  318.   value = strcmp (((const struct hash *) void_first)->name,
  319.           ((const struct hash *) void_second)->name);
  320.   return value;
  321. }
  322.  
  323. /*------------------------------.
  324. | List all available charsets.  |
  325. `------------------------------*/
  326.  
  327. void
  328. list_all_charsets (void)
  329. {
  330.   struct hash *array;
  331.   struct hash *hash;
  332.   int number;
  333.   int counter;
  334.  
  335.   /* Count how many charsets we have.  */
  336.  
  337.   number = 0;
  338.   for (counter = 0; counter < HASH_TABLE_SIZE; counter++)
  339.     for (hash = hash_table + counter;
  340.      hash && hash->name;
  341.      hash = hash->next)
  342.       number++;
  343.  
  344.   /* Allocate a structure to hold them.  */
  345.  
  346.   array = (struct hash *) xmalloc (number * sizeof (struct hash));
  347.  
  348.   /* Copy all charsets in it.  */
  349.  
  350.   number = 0;
  351.   for (counter = 0; counter < HASH_TABLE_SIZE; counter++)
  352.     for (hash = hash_table + counter;
  353.      hash && hash->name;
  354.      hash = hash->next)
  355.       array[number++] = *hash;
  356.  
  357.   /* Sort it.  */
  358.  
  359.   qsort (array, number, sizeof (struct hash), compare_struct_hash);
  360.  
  361.   /* Print it, one line per charset, giving the true charset name first,
  362.      followed by all its alias in lexicographic order.  */
  363.  
  364.   for (hash = array; hash < array + number; hash++)
  365.     {
  366.  
  367.       /* Begin a new line with the true charset name when it changes.  */
  368.  
  369.       if (hash == array || hash->charset->name != (hash - 1)->charset->name)
  370.     {
  371.       if (hash != array)
  372.         printf ("\n");
  373.       printf ("%s", hash->charset->name);
  374.     }
  375.  
  376.       /* Print the charset name or alias in its cleaned up form.  */
  377.  
  378.       printf (" %s", hash->name);
  379.     }
  380.   printf ("\n");
  381.  
  382.   /* Release the work array.  */
  383.  
  384.   free (array);
  385. }
  386.  
  387. /*--------------------------------------------------------------------.
  388. | Return a statically allocated 10646 symbol in a CHARSET for a given |
  389. | CODE, or NULL if this symbol is not defined.                  |
  390. `--------------------------------------------------------------------*/
  391.  
  392. static char *
  393. code_to_symbol (CHARSET *charset, int code)
  394. {
  395.   static char symbol[MAX_SYMBOL_SIZE + 1];
  396.   const char *in;
  397.   char *out;
  398.   int counter;
  399.  
  400.   if (in = (*charset->table)[code / 32], !in)
  401.     return NULL;
  402.  
  403.   in += charset->size * (code % 32);
  404.   if (*in == ' ')
  405.     return NULL;
  406.  
  407.   out = symbol;
  408.   for (counter = 0; counter < charset->size; counter++)
  409.     if (*in == ' ')
  410.       in++;
  411.     else
  412.       *out++ = *in++;
  413.   *out = '\0'; 
  414.   return symbol;
  415. }
  416.  
  417. /*------------------------------------------------------------------------.
  418. | Print a 10646 symbol in a CHARSET for a given CODE, padding with spaces |
  419. | after to the proper width.                          |
  420. `------------------------------------------------------------------------*/
  421.  
  422. static void
  423. print_symbol (CHARSET *charset, int code)
  424. {
  425.   int counter;
  426.   char *cursor;
  427.  
  428.   counter = 0;
  429.   cursor = code_to_symbol (charset, code);
  430.   
  431.   if (cursor)
  432.     for (; *cursor && counter < charset->size; counter++)
  433.       {
  434.     putchar (*cursor);
  435.     cursor++;
  436.       }
  437.   for (; counter < charset->size; counter++)
  438.     putchar (' ');
  439. }
  440.  
  441. /*------------------------------------------------------.
  442. | Print a full CHARSET description on standard output.  |
  443. `------------------------------------------------------*/
  444.  
  445. void
  446. list_full_charset (CHARSET *charset)
  447. {
  448.   int insert_white;        /* insert a while line before printing */
  449.   int code;            /* code counter */
  450.   const char *symbol;        /* symbol for code */
  451.   const char *charname;        /* charname for code */
  452.  
  453.   /* Ensure we have a double table to play with.  */
  454.  
  455.   if (!charset->table)
  456.     error (EXIT_FAILURE, 0,
  457.        "Cannot list `%s', no 10646 names available for this charset",
  458.        charset->name);
  459.  
  460.   /* Print the long table.  */
  461.  
  462.   printf ("dec  oct hex    ch   %s\n", charset->name);
  463.   insert_white = 1;
  464.  
  465.   for (code = 0; code < 256; code++)
  466.     if ((symbol = code_to_symbol (charset, code)), symbol)
  467.       {
  468.     if (insert_white)
  469.       {
  470.         printf ("\n");
  471.         insert_white = 0;
  472.       }
  473.     printf ("%3d  %0.3o  %0.2x    ", code, code, code);
  474.     print_symbol (charset, code);
  475.     if ((charname = symbol_to_charname (symbol)), charname)
  476.       printf ("   %s", charname);
  477.     printf ("\n");
  478.       }
  479.     else
  480.       insert_white = 1;
  481. }
  482.  
  483. /*------------------------------------------------------------------.
  484. | Print a concise, tabular CHARSET description on standard output.  |
  485. `------------------------------------------------------------------*/
  486.  
  487. void
  488. list_concise_charset (CHARSET *charset)
  489. {
  490.   DOUBLE_TABLE *table;        /* double table */
  491.   int half;            /* half 0, half 1 of the table */
  492.   const char *format;        /* format string */
  493.   int counter;            /* code counter */
  494.   int counter2;            /* code counter */
  495.   int code;            /* code value */
  496.  
  497.   /* Ensure we have a double table to play with.  */
  498.  
  499.   if (charset->table)
  500.     table = charset->table;
  501.   else
  502.     error (EXIT_FAILURE, 0,
  503.        "Cannot list `%s', no 10646 names available for this charset",
  504.        charset->name);
  505.  
  506.   printf ("%s\n", charset->name);
  507.  
  508.   /* Select format for numbers.  */
  509.  
  510.   switch (list_format)
  511.     {
  512.     case FULL_FORMAT:
  513.       return;            /* cannot happen */
  514.  
  515.     case NO_FORMAT:
  516.     case DECIMAL_FORMAT:
  517.       format = "%3d";
  518.       break;
  519.  
  520.     case OCTAL_FORMAT:
  521.       format = "%0.3o";
  522.       break;
  523.  
  524.     case HEXADECIMAL_FORMAT:
  525.       format = "%0.2x";
  526.       break;
  527.     }
  528.  
  529.   /* Print both halves of the table.  */
  530.  
  531.   for (half = 0; half < 2; half++)
  532.     {
  533.  
  534.       /* Skip printing this half if it is empty.  */
  535.  
  536.       for (counter = 4 * half; counter < 4 * half + 4; counter++)
  537.     if ((*table)[counter])
  538.       break;
  539.       if (counter == 4 * half + 4)
  540.     continue;
  541.  
  542.       /* Print this half.  */
  543.  
  544.       printf ("\n");
  545.       for (counter = 128 * half; counter < 128 * half + 16; counter++)
  546.     for (counter2 = 0; counter2 < 128; counter2 += 16)
  547.       {
  548.         if (counter2 > 0)
  549.           printf ("  ");
  550.  
  551.         code = counter + counter2;
  552.         printf (format, code);
  553.         printf (" ");
  554.         print_symbol (charset, code);
  555.  
  556.         if (counter2 == 112)
  557.           printf ("\n");
  558.       }
  559.     }
  560. }
  561.