fprintf (fp, "#define AutomaticSet%d%s %#x\t/* %s:%u */\n",
fprintf (fp, "#define AutomaticSet%d%s %#x\t/* %s:%Zu */\n",
write_out (struct catalog *catalog, const char *output_name,	   const char *header_name){  /* Computing the "optimal" size.  */  struct set_list *set_run;  size_t best_total, best_size, best_depth;  size_t act_size, act_depth;  struct catalog_obj obj;  struct obstack string_pool;  const char *strings;  size_t strings_size;  u_int32_t *array1, *array2;  size_t cnt;  int fd;  /* If not otherwise told try to read file with existing     translations.  */  if (!force_new)    read_old (catalog, output_name);  /* Initialize best_size with a very high value.  */  best_total = best_size = best_depth = UINT_MAX;  /* We need some start size for testing.  Let's start with     TOTAL_MESSAGES / 5, which theoretically provides a mean depth of     5.  */  act_size = 1 + catalog->total_messages / 5;  /* We determine the size of a hash table here.  Because the message     numbers can be chosen arbitrary by the programmer we cannot use     the simple method of accessing the array using the message     number.  The algorithm is based on the trivial hash function     NUMBER % TABLE_SIZE, where collisions are stored in a second     dimension up to TABLE_DEPTH.  We here compute TABLE_SIZE so that     the needed space (= TABLE_SIZE * TABLE_DEPTH) is minimal.  */  while (act_size <= best_total)    {      size_t deep[act_size];      act_depth = 1;      memset (deep, '\0', act_size * sizeof (size_t));      set_run = catalog->all_sets;      while (set_run != NULL)	{	  struct message_list *message_run;	  message_run = set_run->messages;	  while (message_run != NULL)	    {	      size_t idx = (message_run->number * set_run->number) % act_size;	      ++deep[idx];	      if (deep[idx] > act_depth)		{		  act_depth = deep[idx];		  if (act_depth * act_size > best_total)		    break;		}	      message_run = message_run->next;	    }	  if (act_depth * act_size <= best_total)	    {	      /* We have found a better solution.  */	      best_total = act_depth * act_size;	      best_size = act_size;	      best_depth = act_depth;	    }	  set_run = set_run->next;	}      ++act_size;    }  /* let's be prepared for an empty message file.  */  if (best_size == UINT_MAX)    {      best_size = 1;      best_depth = 1;    }  /* OK, now we have the size we will use.  Fill in the header, build     the table and the second one with swapped byte order.  */  obj.magic = CATGETS_MAGIC;  obj.plane_size = best_size;  obj.plane_depth = best_depth;  /* Allocate room for all needed arrays.  */  array1 =    (u_int32_t *) alloca (best_size * best_depth * sizeof (u_int32_t) * 3);  memset (array1, '\0', best_size * best_depth * sizeof (u_int32_t) * 3);  array2    = (u_int32_t *) alloca (best_size * best_depth * sizeof (u_int32_t) * 3);  obstack_init (&string_pool);  set_run = catalog->all_sets;  while (set_run != NULL)    {      struct message_list *message_run;      message_run = set_run->messages;      while (message_run != NULL)	{	  size_t idx = (((message_run->number * set_run->number) % best_size)			* 3);	  /* Determine collision depth.  */	  while (array1[idx] != 0)	    idx += best_size * 3;	  /* Store set number, message number and pointer into string	     space, relative to the first string.  */	  array1[idx + 0] = set_run->number;	  array1[idx + 1] = message_run->number;	  array1[idx + 2] = obstack_object_size (&string_pool);	  /* Add current string to the continuous space containing all	     strings.  */	  obstack_grow0 (&string_pool, message_run->message,			 strlen (message_run->message));	  message_run = message_run->next;	}      set_run = set_run->next;    }  strings_size = obstack_object_size (&string_pool);  strings = obstack_finish (&string_pool);  /* Compute ARRAY2 by changing the byte order.  */  for (cnt = 0; cnt < best_size * best_depth * 3; ++cnt)    array2[cnt] = SWAPU32 (array1[cnt]);  /* Now we can write out the whole data.  */  if (strcmp (output_name, "-") == 0      || strcmp (output_name, "/dev/stdout") == 0)    fd = STDOUT_FILENO;  else    {      fd = creat (output_name, 0666);      if (fd < 0)	error (EXIT_FAILURE, errno, gettext ("cannot open output file `%s'"),	       output_name);    }  /* Write out header.  */  write (fd, &obj, sizeof (obj));  /* We always write out the little endian version of the index     arrays.  */#if __BYTE_ORDER == __LITTLE_ENDIAN  write (fd, array1, best_size * best_depth * sizeof (u_int32_t) * 3);  write (fd, array2, best_size * best_depth * sizeof (u_int32_t) * 3);#elif __BYTE_ORDER == __BIG_ENDIAN  write (fd, array2, best_size * best_depth * sizeof (u_int32_t) * 3);  write (fd, array1, best_size * best_depth * sizeof (u_int32_t) * 3);#else# error Cannot handle __BYTE_ORDER byte order#endif  /* Finally write the strings.  */  write (fd, strings, strings_size);  if (fd != STDOUT_FILENO)    close (fd);  /* If requested now write out the header file.  */  if (header_name != NULL)    {      int first = 1;      FILE *fp;      /* Open output file.  "-" or "/dev/stdout" means write to	 standard output.  */      if (strcmp (header_name, "-") == 0	  || strcmp (header_name, "/dev/stdout") == 0)	fp = stdout;      else	{	  fp = fopen (header_name, "w");	  if (fp == NULL)	    error (EXIT_FAILURE, errno,		   gettext ("cannot open output file `%s'"), header_name);	}      /* Iterate over all sets and all messages.  */      set_run = catalog->all_sets;      while (set_run != NULL)	{	  struct message_list *message_run;	  /* If the current message set has a symbolic name write this	     out first.  */	  if (set_run->symbol != NULL)	    fprintf (fp, "%s#define %sSet %#x\t/* %s:%u */\n",		     first ? "" : "\n", set_run->symbol, set_run->number - 1,		     set_run->fname, set_run->line);	  first = 0;	  message_run = set_run->messages;	  while (message_run != NULL)	    {	      /* If the current message has a symbolic name write		 #define out.  But we have to take care for the set		 not having a symbolic name.  */	      if (message_run->symbol != NULL)		if (set_run->symbol == NULL)		  fprintf (fp, "#define AutomaticSet%d%s %#x\t/* %s:%u */\n",			   set_run->number, message_run->symbol,			   message_run->number, message_run->fname,			   message_run->line);		else		  fprintf (fp, "#define %s%s %#x\t/* %s:%u */\n",			   set_run->symbol, message_run->symbol,			   message_run->number, message_run->fname,			   message_run->line);	      message_run = message_run->next;	    }	  set_run = set_run->next;	}      if (fp != stdout)	fclose (fp);    }}