home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / GNU / recode-3.4-MIHS / src / charset.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-13  |  18.8 KB  |  764 lines

  1. /* Conversion of files between different charsets and usages.
  2.    Copyright (C) 1993, 1994 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 pairs (for restricting listing).  */
  32.  
  33. static struct known_pair *pair_restriction = NULL;
  34. static int pair_restrictions = 0;
  35.  
  36. /* Known character sets.  */
  37.  
  38. struct hash
  39.   {
  40.     const char *name;        /* charset or alias name, or NULL */
  41.     CHARSET *charset;        /* associated charset */
  42.     struct hash *next;        /* next index in table, or NULL */
  43.   };
  44. struct hash hash_table[HASH_TABLE_SIZE];
  45. CHARSET charset_array[MAX_CHARSETS];
  46. int number_of_charsets;
  47.  
  48. /* Array of strings ready for argmatch.  */
  49. static const char **argmatch_array;
  50.  
  51. /* Character names.  */
  52.  
  53. /* This module takes care only of short 10646 forms.  Module charname.c
  54.    takes care of the full descriptive name for characters.  */
  55.  
  56. /*--------------------------------------------------------------------.
  57. | Return a statically allocated 10646 symbol in a CHARSET for a given |
  58. | CODE, or NULL if this symbol is not defined.  There are two static  |
  59. | buffers used in alternance.                          |
  60. `--------------------------------------------------------------------*/
  61.  
  62. static char *
  63. code_to_symbol (CHARSET *charset, int code)
  64. {
  65.   static char buffer[2][MAX_SYMBOL_SIZE + 1];
  66.   static int which = 0;
  67.   const char *in;
  68.   char *out;
  69.   int counter;
  70.  
  71.   if (in = (*charset->table)[code / 32], !in)
  72.     return NULL;
  73.  
  74.   in += charset->size * (code % 32);
  75.   if (*in == ' ')
  76.     return NULL;
  77.  
  78.   which = !which;
  79.   out = buffer[which];
  80.   for (counter = 0; counter < charset->size; counter++)
  81.     if (*in == ' ')
  82.       in++;
  83.     else
  84.       *out++ = *in++;
  85.   *out = '\0'; 
  86.   return buffer[which];
  87. }
  88.  
  89. /*------------------------------------------------------------------------.
  90. | Print a 10646 symbol in a CHARSET for a given CODE, padding with spaces |
  91. | after to the proper width.                          |
  92. `------------------------------------------------------------------------*/
  93.  
  94. static void
  95. print_symbol (CHARSET *charset, int code)
  96. {
  97.   int counter;
  98.   char *cursor;
  99.  
  100.   counter = 0;
  101.   cursor = code_to_symbol (charset, code);
  102.   
  103.   if (cursor)
  104.     for (; *cursor && counter < charset->size; counter++)
  105.       {
  106.     putchar (*cursor);
  107.     cursor++;
  108.       }
  109.   for (; counter < charset->size; counter++)
  110.     putchar (' ');
  111. }
  112.  
  113. /*-----------------------------------------------------------------.
  114. | Decode a known PAIRS argument, given in STRING, constructing the |
  115. | pair_restriction array out of it.                   |
  116. `-----------------------------------------------------------------*/
  117.  
  118. void
  119. decode_known_pairs (const char *string)
  120. {
  121.   struct known_pair pair;
  122.   const char *cursor;
  123.   int value;
  124.  
  125.   pair_restriction = (struct known_pair *)
  126.     xmalloc (16 * sizeof (struct known_pair));
  127.  
  128.   value = -1;
  129.   for (cursor = string; *cursor; cursor++)
  130.     switch (*cursor)
  131.       {
  132.       default:
  133.     usage (EXIT_FAILURE);
  134.  
  135.       case '0':
  136.       case '1':
  137.       case '2':
  138.       case '3':
  139.       case '4':
  140.       case '5':
  141.       case '6':
  142.       case '7':
  143.       case '8':
  144.       case '9':
  145.     if (value < 0)
  146.       value = *cursor - '0';
  147.     else
  148.       value = 10 * value + *cursor - '0';
  149.     break;
  150.  
  151.       case ':':
  152.     if (value < 0 || value > 255)
  153.       usage (EXIT_FAILURE);
  154.     pair_restriction[pair_restrictions].left = (unsigned char) value;
  155.     value = -1;
  156.     break;
  157.  
  158.       case ',':
  159.     if (value < 0 || value > 255)
  160.       usage (EXIT_FAILURE);
  161.     pair_restriction[pair_restrictions++].right = (unsigned char) value;
  162.     if (pair_restrictions % 16 == 0)
  163.       pair_restriction = (struct known_pair *)
  164.         xrealloc (pair_restriction,
  165.               (pair_restrictions + 16) * sizeof (struct known_pair));
  166.     value = -1;
  167.     break;
  168.       }
  169.  
  170.   if (value < 0 || value > 255)
  171.     usage (EXIT_FAILURE);
  172.   pair_restriction[pair_restrictions++].right = (unsigned char) value;
  173. }
  174.  
  175. /*-------------------------------------------------------------.
  176. | Return non-zero if BEFORE to AFTER is currently restricted.  |
  177. `-------------------------------------------------------------*/
  178.  
  179. static int
  180. check_restricted (CHARSET *before, CHARSET *after)
  181. {
  182.   struct known_pair *pair;
  183.   const char *left;
  184.   const char *right;
  185.  
  186.   /* Reject the charset if not RFC1345.  */
  187.  
  188.   if (!before->table || !after->table)
  189.     return 1;
  190.  
  191.   for (pair = pair_restriction;
  192.        pair < pair_restriction + pair_restrictions;
  193.        pair++)
  194.     {
  195.  
  196.       /* Reject the charset if the characters in the pair do not exist of
  197.      if their respective definition do not match.  */
  198.  
  199.       left = code_to_symbol (before, pair->left);
  200.       if (!left)
  201.     return 1;
  202.       right = code_to_symbol (after, pair->right);
  203.       if (!right)
  204.     return 1;
  205.       if (strcmp (left, right))
  206.     return 1;
  207.     }
  208.  
  209.   /* No restriction found.  */
  210.  
  211.   return 0;
  212. }
  213.  
  214. /* Charset names.  */
  215.  
  216. /*--------------------------------------.
  217. | Prepare charsets for initialization.  |
  218. `--------------------------------------*/
  219.  
  220. void
  221. prepare_charset_initialization (void)
  222. {
  223.   int counter;
  224.  
  225.   for (counter = 0; counter < HASH_TABLE_SIZE; counter++)
  226.     {
  227.       hash_table[counter].name = NULL;
  228.       hash_table[counter].next = NULL;
  229.     }
  230.   number_of_charsets = 0;
  231. }
  232.  
  233. /*-----------------------------------------------------------------------.
  234. | Return a newly allocated copy of charset NAME, with upper case letters |
  235. | turned into lower case, and all non alphanumeric discarded.         |
  236. `-----------------------------------------------------------------------*/
  237.  
  238. static char *
  239. cleanup_charset_name (const char *name)
  240. {
  241.   char *result;
  242.   char *out;
  243.   const char *in;
  244.   int character;
  245.  
  246.   result = xmalloc (strlen (name) + 1);
  247.   out = result;
  248.   for (in = name; *in; in++)
  249.     {
  250.       character = *(const unsigned char *) in;
  251.       if ((character >= 'a' && character <= 'z')
  252.       || (character >= '0' && character <= '9'))
  253.     *out++ = character;
  254.       else if (character >= 'A' && character <= 'Z')
  255.     *out++ = character - 'A' + 'a';
  256.     }
  257.   *out = '\0';
  258.   return result;
  259. }
  260.  
  261. /*-----------------------------------.
  262. | Return a hash index for a STRING.  |
  263. `-----------------------------------*/
  264.  
  265. #ifdef DIFF_HASH
  266.  
  267. /* Given a hash value and a new character, return a new hash value.  */
  268.  
  269. #define UINT_BIT (sizeof (unsigned) * CHAR_BIT)
  270. #define ROTATE_LEFT(v, n) ((v) << (n) | (v) >> (UINT_BIT - (n)))
  271. #define HASH(h, c) ((c) + ROTATE_LEFT (h, 7))
  272.  
  273. static int
  274. hash_string (const char *string)
  275. {
  276.   unsigned value;
  277.  
  278.   value = 0;
  279.   for (; *string; string++)
  280.     value = HASH (value, *(const unsigned char *) string);
  281.   return value % HASH_TABLE_SIZE;
  282. }
  283.  
  284. #else /* not DIFF_HASH */
  285.  
  286. static int
  287. hash_string (const char *string)
  288. {
  289.   unsigned value;
  290.  
  291.   value = 0;
  292.   for (; *string; string++)
  293.     value = ((value * 31 + (int) *(const unsigned char *) string)
  294.          % HASH_TABLE_SIZE);
  295.   return value;
  296. }
  297.  
  298. #endif /* not DIFF_HASH */
  299.  
  300. /*--------------------------------------------------------------------------.
  301. | Return the charset from its NAME or alias name.  If it does not already   |
  302. | exist, add a new charset entry and initialize it with a brand new value.  |
  303. `--------------------------------------------------------------------------*/
  304.  
  305. CHARSET *
  306. find_charset (const char *name)
  307. {
  308.   char *hashname;
  309.   struct hash *hash;
  310.   CHARSET *charset;
  311.  
  312.   /* Search the whole hash bucket and return any match.  */
  313.  
  314.   hashname = cleanup_charset_name (name);
  315.   for (hash = hash_table + hash_string (hashname);
  316.        hash->name;
  317.        hash = hash->next)
  318.     {
  319.       if (strcmp (hashname, hash->name) == 0)
  320.     {
  321.       free (hashname);
  322.       return hash->charset;
  323.     }
  324.       if (!hash->next)
  325.     break;
  326.     }
  327.  
  328.   /* A new charset has to be created.  */
  329.  
  330.   if (number_of_charsets == MAX_CHARSETS)
  331.     error (EXIT_FAILURE, 0, "MAX_CHARSETS is too small");
  332.  
  333.   charset = charset_array + number_of_charsets++;
  334.  
  335.   /* If the current slot is already used, create an overflow entry and
  336.      initialize it enough so it could be taken for the current slot.  */
  337.  
  338.   if (hash->name)
  339.     {
  340.       hash->next = (struct hash *) xmalloc (sizeof (struct hash));
  341.       hash = hash->next;
  342.       hash->next = NULL;
  343.     }
  344.  
  345.   /* Initialize the current slot with the new charset.  */
  346.  
  347.   hash->name = hashname;
  348.   hash->charset = charset;
  349.  
  350.   charset->name = name;
  351.   charset->ignore = 0;
  352.   charset->table = NULL;
  353.  
  354.   return charset;
  355. }
  356.  
  357. /*-------------------------------------------------------------------------.
  358. | Have NAME as an alternate charset name for OLD_NAME.  Create OLD_NAME if |
  359. | it does not exist already.                           |
  360. `-------------------------------------------------------------------------*/
  361.  
  362. void
  363. declare_alias (const char *name, const char *old_name)
  364. {
  365.   char *hashname;
  366.   struct hash *hash;
  367.   CHARSET *old_charset;
  368.  
  369.   /* Find the old value.  */
  370.  
  371.   old_charset = find_charset (old_name);
  372.  
  373.   /* Search the whole hash bucket.  */
  374.  
  375.   hashname = cleanup_charset_name (name);
  376.   for (hash = hash_table + hash_string (hashname);
  377.        hash->name;
  378.        hash = hash->next)
  379.     {
  380.       if (strcmp (hashname, hash->name) == 0)
  381.     {
  382.       if (hash->charset != old_charset)
  383.         error (EXIT_FAILURE, 0, "Charset %s already exists and is not %s",
  384.            name, old_name);
  385.       free (hashname);
  386.       return;
  387.     }
  388.       if (!hash->next)
  389.     break;
  390.     }
  391.  
  392.   /* If the current slot is already used, create an overflow entry and
  393.      initialize it enough so it could be taken for the current slot.  */
  394.  
  395.   if (hash->name)
  396.     {
  397.       hash->next = (struct hash *) xmalloc (sizeof (struct hash));
  398.       hash = hash->next;
  399.       hash->next = NULL;
  400.     }
  401.  
  402.   /* Initialize the current slot with the old charset.  */
  403.  
  404.   hash->name = hashname;
  405.   hash->charset = old_charset;
  406. }
  407.  
  408. /*------------------------------------------.
  409. | Construct the string array for argmatch.  |
  410. `------------------------------------------*/
  411.  
  412. void
  413. make_argmatch_array (void)
  414. {
  415.   struct hash *hash;        /* cursor in charsets */
  416.   int number;            /* number of strings */
  417.   int counter;            /* all purpose counter */
  418. #ifdef HASH_STATS
  419.   int buckets;            /* number of non-empty buckets */
  420. #endif
  421.  
  422.   /* Count how many strings we need.  */
  423.  
  424.   number = 0;
  425.   for (counter = 0; counter < HASH_TABLE_SIZE; counter++)
  426.     for (hash = hash_table + counter;
  427.      hash && hash->name;
  428.      hash = hash->next)
  429.       number++;
  430.  
  431. #ifdef HASH_STATS
  432.   buckets = 0;
  433.   for (counter = 0; counter < HASH_TABLE_SIZE; counter++)
  434.     if (hash_table[counter].name)
  435.       buckets++;
  436.  
  437.   fprintf (stderr, "Hash stats: %d names using %d buckets out of %d\n",
  438.        number, buckets, HASH_TABLE_SIZE);
  439. #endif
  440.  
  441.   /* Allocate the argmatch array, with place for a NULL sentinel.  */
  442.  
  443.   argmatch_array
  444.     = (const char **) xmalloc ((number + 1) * sizeof (const char *));
  445.  
  446.   /* Fill in the array.  */
  447.  
  448.   number = 0;
  449.   for (counter = 0; counter < HASH_TABLE_SIZE; counter++)
  450.     for (hash = hash_table + counter;
  451.      hash && hash->name;
  452.      hash = hash->next)
  453.       argmatch_array[number++] = hash->name;
  454.  
  455.   argmatch_array[number] = NULL;
  456. }
  457.  
  458. /*-----------------------------------------------------------------------.
  459. | Return the NAME of a charset, un-abbreviated and cleaned up.  Diagnose |
  460. | and abort if this cannot be done successfully.  A NULL or empty string |
  461. | means the default charset, if this default charset is defined.     |
  462. `-----------------------------------------------------------------------*/
  463.  
  464. const char *
  465. clean_charset_name (const char *name)
  466. {
  467.   char *hashname;
  468.   int ordinal;
  469.  
  470.   /* Look for a match.  */
  471.  
  472.   if (!name)
  473.     name = "";
  474. #ifdef DEFAULT_CHARSET
  475.   if (!*name)
  476.     name = DEFAULT_CHARSET;
  477. #endif
  478.   hashname = cleanup_charset_name (name);
  479.   ordinal = argmatch (hashname, argmatch_array);
  480.   free (hashname);
  481.  
  482.   /* Diagnose any match error, notifying usage that we are decoding
  483.      charsets.  */
  484.  
  485.   switch (ordinal)
  486.     {
  487.     case -2:
  488.       error (0, 0, "Ambiguous charset `%s'", name);
  489.       decoding_charset_flag = 1;
  490.       usage (EXIT_FAILURE);
  491.  
  492.     case -1:
  493.       error (0, 0, "Unknown charset `%s'", name);
  494.       decoding_charset_flag = 1;
  495.       usage (EXIT_FAILURE);
  496.     }
  497.  
  498.   return argmatch_array[ordinal];
  499. }
  500.  
  501. /*----------------------------------------------------------------------.
  502. | Order two struct hash's, using the true charset name as the first key |
  503. | and the current name as the second key.                    |
  504. `----------------------------------------------------------------------*/
  505.  
  506. static int
  507. compare_struct_hash (const void *void_first, const void *void_second)
  508. {
  509.   int value;
  510.  
  511.   value = strcmp (((const struct hash *) void_first)->charset->name,
  512.           ((const struct hash *) void_second)->charset->name);
  513.   if (value != 0)
  514.     return value;
  515.   
  516.   value = strcmp (((const struct hash *) void_first)->name,
  517.           ((const struct hash *) void_second)->name);
  518.   return value;
  519. }
  520.  
  521. /*-----------------------------------------------------------------------.
  522. | List all available charsets, obeying restrictions for an AFTER charset |
  523. | if any.                                 |
  524. `-----------------------------------------------------------------------*/
  525.  
  526. void
  527. list_all_charsets (CHARSET *after)
  528. {
  529.   struct hash *array;
  530.   struct hash *hash;
  531.   int number;
  532.   int counter;
  533.   int list_flag;
  534.  
  535.   /* Count how many charsets we have.  */
  536.  
  537.   number = 0;
  538.   for (counter = 0; counter < HASH_TABLE_SIZE; counter++)
  539.     for (hash = hash_table + counter;
  540.      hash && hash->name;
  541.      hash = hash->next)
  542.       number++;
  543.  
  544.   /* Allocate a structure to hold them.  */
  545.  
  546.   array = (struct hash *) xmalloc (number * sizeof (struct hash));
  547.  
  548.   /* Copy all charsets in it.  */
  549.  
  550.   number = 0;
  551.   for (counter = 0; counter < HASH_TABLE_SIZE; counter++)
  552.     for (hash = hash_table + counter;
  553.      hash && hash->name;
  554.      hash = hash->next)
  555.       array[number++] = *hash;
  556.  
  557.   /* Sort it.  */
  558.  
  559.   qsort (array, number, sizeof (struct hash), compare_struct_hash);
  560.  
  561.   /* Print it, one line per charset, giving the true charset name first,
  562.      followed by all its alias in lexicographic order.  */
  563.  
  564.   for (hash = array; hash < array + number; hash++)
  565.     {
  566.  
  567.       /* Begin a new line with the true charset name when it changes.  */
  568.  
  569.       if (hash == array || hash->charset->name != (hash - 1)->charset->name)
  570.     {
  571.       if (list_flag && hash != array)
  572.         printf ("\n");
  573.  
  574.       list_flag = !after || !check_restricted (hash->charset, after);
  575.  
  576.       if (list_flag)
  577.         printf ("%s", hash->charset->name);
  578.     }
  579.  
  580.       /* Print the charset name or alias in its cleaned up form.  */
  581.  
  582.       if (list_flag)
  583.     printf (" %s", hash->name);
  584.     }
  585.   if (list_flag)
  586.     printf ("\n");
  587.  
  588.   /* Release the work array.  */
  589.  
  590.   free (array);
  591. }
  592.  
  593. /* Charset contents.  */
  594.  
  595. /*-----------------------------------------------------------------------.
  596. | For a given STEP recoding into a RFC 1345 charset, produce an explicit |
  597. | recoding table.                             |
  598. `-----------------------------------------------------------------------*/
  599.  
  600. void
  601. init_table_for_rfc1345 (STEP *step)
  602. {
  603.   const char *symbol;
  604.   char *pool;
  605.   const char **table;
  606.   int length;
  607.   int counter;
  608.  
  609.   /* First compute how much memory is needed.  */
  610.  
  611.   length = 0;
  612.   for (counter = 0; counter < 256; counter++)
  613.     {
  614.       symbol = code_to_symbol (step->before, counter);
  615.       if (symbol)
  616.     length += strlen (symbol) + 1;
  617.     }
  618.  
  619.   /* Do the actual allocation and filling.  */
  620.  
  621.   table = (const char **) xmalloc (256 * sizeof (char *) + length);
  622.   pool = (char *) (table + 256);
  623.  
  624.   for (counter = 0; counter < 256; counter++)
  625.     {
  626.       symbol = code_to_symbol (step->before, counter);
  627.       if (symbol)
  628.     {
  629.       if (strcmp (symbol, "SP") == 0)
  630.         symbol = " ";
  631.       else if (strcmp (symbol, "LF") == 0)
  632.         symbol = "\n";
  633.  
  634.       table[counter] = pool;
  635.       while (*pool++ = *symbol++)
  636.         ;
  637.     }
  638.       else
  639.     table[counter] = NULL;
  640.     }
  641.  
  642.   step->one_to_many = table;
  643. }
  644.  
  645. /*------------------------------------------------------------------.
  646. | Print a concise, tabular CHARSET description on standard output.  |
  647. `------------------------------------------------------------------*/
  648.  
  649. void
  650. list_concise_charset (CHARSET *charset)
  651. {
  652.   DOUBLE_TABLE *table;        /* double table */
  653.   int half;            /* half 0, half 1 of the table */
  654.   const char *format;        /* format string */
  655.   int counter;            /* code counter */
  656.   int counter2;            /* code counter */
  657.   int code;            /* code value */
  658.  
  659.   /* Ensure we have a double table to play with.  */
  660.  
  661.   if (charset->table)
  662.     table = charset->table;
  663.   else
  664.     error (EXIT_FAILURE, 0,
  665.        "Cannot list `%s', no 10646 names available for this charset",
  666.        charset->name);
  667.  
  668.   printf ("%s\n", charset->name);
  669.  
  670.   /* Select format for numbers.  */
  671.  
  672.   switch (list_format)
  673.     {
  674.     default:
  675.       return;            /* cannot happen */
  676.  
  677.     case NO_FORMAT:
  678.     case DECIMAL_FORMAT:
  679.       format = "%3d";
  680.       break;
  681.  
  682.     case OCTAL_FORMAT:
  683.       format = "%0.3o";
  684.       break;
  685.  
  686.     case HEXADECIMAL_FORMAT:
  687.       format = "%0.2x";
  688.       break;
  689.     }
  690.  
  691.   /* Print both halves of the table.  */
  692.  
  693.   for (half = 0; half < 2; half++)
  694.     {
  695.  
  696.       /* Skip printing this half if it is empty.  */
  697.  
  698.       for (counter = 4 * half; counter < 4 * half + 4; counter++)
  699.     if ((*table)[counter])
  700.       break;
  701.       if (counter == 4 * half + 4)
  702.     continue;
  703.  
  704.       /* Print this half.  */
  705.  
  706.       printf ("\n");
  707.       for (counter = 128 * half; counter < 128 * half + 16; counter++)
  708.     for (counter2 = 0; counter2 < 128; counter2 += 16)
  709.       {
  710.         if (counter2 > 0)
  711.           printf ("  ");
  712.  
  713.         code = counter + counter2;
  714.         printf (format, code);
  715.         printf (" ");
  716.         print_symbol (charset, code);
  717.  
  718.         if (counter2 == 112)
  719.           printf ("\n");
  720.       }
  721.     }
  722. }
  723.  
  724. /*------------------------------------------------------.
  725. | Print a full CHARSET description on standard output.  |
  726. `------------------------------------------------------*/
  727.  
  728. void
  729. list_full_charset (CHARSET *charset)
  730. {
  731.   int insert_white;        /* insert a while line before printing */
  732.   int code;            /* code counter */
  733.   const char *symbol;        /* symbol for code */
  734.   const char *charname;        /* charname for code */
  735.  
  736.   /* Ensure we have a double table to play with.  */
  737.  
  738.   if (!charset->table)
  739.     error (EXIT_FAILURE, 0,
  740.        "Sorry, no 10646 names available for `%s'", charset->name);
  741.  
  742.   /* Print the long table.  */
  743.  
  744.   printf ("dec  oct hex    ch   %s\n", charset->name);
  745.   insert_white = 1;
  746.  
  747.   for (code = 0; code < 256; code++)
  748.     if ((symbol = code_to_symbol (charset, code)), symbol)
  749.       {
  750.     if (insert_white)
  751.       {
  752.         printf ("\n");
  753.         insert_white = 0;
  754.       }
  755.     printf ("%3d  %0.3o  %0.2x    ", code, code, code);
  756.     print_symbol (charset, code);
  757.     if ((charname = symbol_to_charname (symbol)), charname)
  758.       printf ("   %s", charname);
  759.     printf ("\n");
  760.       }
  761.     else
  762.       insert_white = 1;
  763. }
  764.