else continued = 0;
read_input_file (struct catalog *current, const char *fname){  FILE *fp;  char *buf;  size_t len;  size_t line_number;  wchar_t *wbuf;  size_t wbufsize;  iconv_t cd_towc = (iconv_t) -1;  iconv_t cd_tomb = (iconv_t) -1;  wchar_t escape_char = L'\\';  char *codeset = NULL;  if (strcmp (fname, "-") == 0 || strcmp (fname, "/dev/stdin") == 0)    {      fp = stdin;      fname = gettext ("*standard input*");    }  else    fp = fopen (fname, "r");  if (fp == NULL)    {      error (0, errno, gettext ("cannot open input file `%s'"), fname);      return current;    }  /* If we haven't seen anything yet, allocate result structure.  */  if (current == NULL)    {      current = (struct catalog *) xcalloc (1, sizeof (*current));#define obstack_chunk_alloc malloc#define obstack_chunk_free free      obstack_init (&current->mem_pool);      current->current_set = find_set (current, NL_SETD);    }  buf = NULL;  len = 0;  line_number = 0;  wbufsize = 1024;  wbuf = (wchar_t *) xmalloc (wbufsize);  while (!feof (fp))    {      int continued;      int used;      size_t start_line = line_number + 1;      char *this_line;      do	{	  int act_len;	  act_len = getline (&buf, &len, fp);	  if (act_len <= 0)	    break;	  ++line_number;	  /* It the line continued?  */	  if (buf[act_len - 1] == '\n')	    {	      --act_len;	      continued = buf[act_len - 1] == '\\';	      if (continued)		--act_len;	    }	  else	    continued = 0;	  /* Append to currently selected line.  */	  obstack_grow (&current->mem_pool, buf, act_len);	}      while (continued);      obstack_1grow (&current->mem_pool, '\0');      this_line = (char *) obstack_finish (&current->mem_pool);      used = 0;      if (this_line[0] == '$')	{	  if (isblank (this_line[1]))	    {	      int cnt = 1;	      while (isblank (this_line[cnt]))		++cnt;	      if (strncmp (&this_line[cnt], "codeset=", 8) != 0)		/* This is a comment line. Do nothing.  */;	      else if (codeset != NULL)		/* Ignore multiple codeset. */;	      else		{		  int start = cnt + 8;		  cnt = start;		  while (this_line[cnt] != '\0' && !isspace (this_line[cnt]))		    ++cnt;		  if (cnt != start)		    {		      int len = cnt - start;		      codeset = xmalloc (len + 1);		      *((char *) mempcpy (codeset, &this_line[start], len))			= '\0';		    }		}	    }	  else if (strncmp (&this_line[1], "set", 3) == 0)	    {	      int cnt = sizeof ("set");	      int set_number;	      const char *symbol = NULL;	      while (isspace (this_line[cnt]))		++cnt;	      if (isdigit (this_line[cnt]))		{		  set_number = atol (&this_line[cnt]);		  /* If the given number for the character set is		     higher than any we used for symbolic set names		     avoid clashing by using only higher numbers for		     the following symbolic definitions.  */		  if (set_number > current->last_set)		    current->last_set = set_number;		}	      else		{		  /* See whether it is a reasonable identifier.  */		  int start = cnt;		  while (isalnum (this_line[cnt]) || this_line[cnt] == '_')		    ++cnt;		  if (cnt == start)		    {		      /* No correct character found.  */		      error_at_line (0, 0, fname, start_line,				     gettext ("illegal set number"));		      set_number = 0;		    }		  else		    {		      /* We have found seomthing that looks like a			 correct identifier.  */		      struct set_list *runp;		      this_line[cnt] = '\0';		      used = 1;		      symbol = &this_line[start];		      /* Test whether the identifier was already used.  */		      runp = current->all_sets;		      while (runp != 0)			if (runp->symbol != NULL			    && strcmp (runp->symbol, symbol) == 0)			  break;			else			  runp = runp->next;		      if (runp != NULL)			{			  /* We cannot allow duplicate identifiers for			     message sets.  */			  error_at_line (0, 0, fname, start_line,					 gettext ("duplicate set definition"));			  error_at_line (0, 0, runp->fname, runp->line,					 gettext ("\this is the first definition"));			  set_number = 0;			}		      else			/* Allocate next free message set for identifier.  */			set_number = ++current->last_set;		    }		}	      if (set_number != 0)		{		  /* We found a legal set number.  */		  current->current_set = find_set (current, set_number);		  if (symbol != NULL)		      used = 1;		  current->current_set->symbol = symbol;		  current->current_set->fname = fname;		  current->current_set->line = start_line;		}	    }	  else if (strncmp (&this_line[1], "delset", 6) == 0)	    {	      int cnt = sizeof ("delset");	      size_t set_number;	      while (isspace (this_line[cnt]))		++cnt;	      if (isdigit (this_line[cnt]))		{		  size_t set_number = atol (&this_line[cnt]);		  struct set_list *set;		  /* Mark the message set with the given number as		     deleted.  */		  set = find_set (current, set_number);		  set->deleted = 1;		}	      else		{		  /* See whether it is a reasonable identifier.  */		  int start = cnt;		  while (isalnum (this_line[cnt]) || this_line[cnt] == '_')		    ++cnt;		  if (cnt == start)		    {		      error_at_line (0, 0, fname, start_line,				     gettext ("illegal set number"));		      set_number = 0;		    }		  else		    {		      const char *symbol;		      struct set_list *runp;		      this_line[cnt] = '\0';		      used = 1;		      symbol = &this_line[start];		      /* We have a symbolic set name.  This name must			 appear somewhere else in the catalogs read so			 far.  */		      set_number = 0;		      for (runp = current->all_sets; runp != NULL;			   runp = runp->next)			{			  if (strcmp (runp->symbol, symbol) == 0)			    {			      runp->deleted = 1;			      break;			    }			}		      if (runp == NULL)			/* Name does not exist before.  */			error_at_line (0, 0, fname, start_line,				       gettext ("unknown set `%s'"), symbol);		    }		}	    }	  else if (strncmp (&this_line[1], "quote", 5) == 0)	    {	      char buf[2];	      char *bufptr;	      size_t buflen;	      char *wbufptr;	      size_t wbuflen;	      int cnt;	      cnt = sizeof ("quote");	      while (isspace (this_line[cnt]))		++cnt;	      /* We need the conversion.  */	      if (cd_towc == (iconv_t) -1		  && open_conversion (codeset, &cd_towc, &cd_tomb,				      &escape_char) != 0)		/* Something is wrong.  */		goto out;	      /* Yes, the quote char can be '\0'; this means no quote		 char.  The function using the information works on		 wide characters so we have to convert it here.  */	      buf[0] = this_line[cnt];	      buf[1] = '\0';	      bufptr = buf;	      buflen = 2;	      wbufptr = (char *) wbuf;	      wbuflen = wbufsize;	      /* Flush the state.  */	      iconv (cd_towc, NULL, NULL, NULL, NULL);	      iconv (cd_towc, &bufptr, &buflen, &wbufptr, &wbuflen);	      if (buflen != 0 || (wchar_t *) wbufptr != &wbuf[2])		error_at_line (0, 0, fname, start_line,			       gettext ("invalid quote character"));	      else		/* Use the converted wide character.  */		current->quote_char = wbuf[0];	    }	  else	    {	      int cnt;	      cnt = 2;	      while (this_line[cnt] != '\0' && !isspace (this_line[cnt]))		++cnt;	      this_line[cnt] = '\0';	      error_at_line (0, 0, fname, start_line,			     gettext ("unknown directive `%s': line ignored"),			     &this_line[1]);	    }	}      else if (isalnum (this_line[0]) || this_line[0] == '_')	{	  const char *ident = this_line;	  char *line = this_line;	  int message_number;	  do	    ++line;	  while (line[0] != '\0' && !isspace (line[0]));	  if (line[0] != '\0')	    *line++ = '\0';	/* Terminate the identifier.  */	  /* Now we found the beginning of the message itself.  */	  if (isdigit (ident[0]))	    {	      struct message_list *runp;	      struct message_list *lastp;	      message_number = atoi (ident);	      /* Find location to insert the new message.  */	      runp = current->current_set->messages;	      lastp = NULL;	      while (runp != NULL)		if (runp->number == message_number)		  break;		else		  {		    lastp = runp;		    runp = runp->next;		  }	      if (runp != NULL)		{		  /* Oh, oh.  There is already a message with this		     number in the message set.  */		  error_at_line (0, 0, fname, start_line,				 gettext ("duplicated message number"));		  error_at_line (0, 0, runp->fname, runp->line,				 gettext ("this is the first definition"));		  message_number = 0;		}	      ident = NULL;	/* We don't have a symbol.  */	      if (message_number != 0		  && message_number > current->current_set->last_message)		current->current_set->last_message = message_number;	    }	  else if (ident[0] != '\0')	    {	      struct message_list *runp;	      struct message_list *lastp;	      /* Test whether the symbolic name was not used for		 another message in this message set.  */	      runp = current->current_set->messages;	      lastp = NULL;	      while (runp != NULL)		if (runp->symbol != NULL && strcmp (ident, runp->symbol) == 0)		  break;		else		  runp = runp->next;	      if (runp != NULL)		{		  /* The name is already used.  */		  error_at_line (0, 0, fname, start_line, gettext ("\duplicated message identifier"));		  error_at_line (0, 0, runp->fname, runp->line,				 gettext ("this is the first definition"));		  message_number = 0;		}	      else		/* Give the message the next unused number.  */		message_number = ++current->current_set->last_message;	    }	  else	    message_number = 0;	  if (message_number != 0)	    {	      char *inbuf;	      size_t inlen;	      char *outbuf;	      size_t outlen;	      struct message_list *newp;	      size_t line_len = strlen (line) + 1;	      size_t ident_len = 0;	      /* We need the conversion.  */	      if (cd_towc == (iconv_t) -1		  && open_conversion (codeset, &cd_towc, &cd_tomb,				      &escape_char) != 0)		/* Something is wrong.  */		goto out;	      /* Convert to a wide character string.  We have to		 interpret escape sequences which will be impossible		 without doing the conversion if the codeset of the		 message is stateful.  */	      while (1)		{		  inbuf = line;		  inlen = line_len;		  outbuf = (char *) wbuf;		  outlen = wbufsize;		  /* Flush the state.  */		  iconv (cd_towc, NULL, NULL, NULL, NULL);		  iconv (cd_towc, &inbuf, &inlen, &outbuf, &outlen);		  if (inlen == 0)		    {		      /* The string is converted.  */		      assert (outlen < wbufsize);		      assert (wbuf[(wbufsize - outlen) / sizeof (wchar_t) - 1]			      == L'\0');		      break;		    }		  if (outlen != 0)		    {		      /* Something is wrong with this string, we ignore it.  */		      error_at_line (0, 0, fname, start_line, gettext ("\invalid character: message ignored"));		      goto ignore;		    }		  /* The output buffer is too small.  */		  wbufsize *= 2;		  wbuf = (wchar_t *) xrealloc (wbuf, wbufsize);		}	      /* Strip quote characters, change escape sequences into		 correct characters etc.  */	      normalize_line (fname, start_line, cd_towc, wbuf,			      current->quote_char, escape_char);	      if (ident)		ident_len = line - this_line;	      /* Now the string is free of escape sequences.  Convert it		 back into a multibyte character string.  First free the		 memory allocated for the original string.  */	      obstack_free (&current->mem_pool, this_line);	      used = 1;	/* Yes, we use the line.  */	      /* Now fill in the new string.  It should never happen that		 the replaced string is longer than the original.  */	      inbuf = (char *) wbuf;	      inlen = (wcslen (wbuf) + 1) * sizeof (wchar_t);	      outlen = obstack_room (&current->mem_pool);	      obstack_blank (&current->mem_pool, outlen);	      this_line = (char *) obstack_base (&current->mem_pool);	      outbuf = this_line + ident_len;	      outlen -= ident_len;	      /* Flush the state.  */	      iconv (cd_tomb, NULL, NULL, NULL, NULL);	      iconv (cd_tomb, &inbuf, &inlen, &outbuf, &outlen);	      if (inlen != 0)		{		  error_at_line (0, 0, fname, start_line,				 gettext ("invalid line"));		  goto ignore;		}	      assert (outbuf[-1] == '\0');	      /* Free the memory in the obstack we don't use.  */	      obstack_blank (&current->mem_pool, -(int) outlen);	      line = obstack_finish (&current->mem_pool);	      newp = (struct message_list *) xmalloc (sizeof (*newp));	      newp->number = message_number;	      newp->message = line + ident_len;	      /* Remember symbolic name; is NULL if no is given.  */	      newp->symbol = ident ? line : NULL;	      /* Remember where we found the character.  */	      newp->fname = fname;	      newp->line = start_line;	      /* Find place to insert to message.  We keep them in a		 sorted single linked list.  */	      if (current->current_set->messages == NULL		  || current->current_set->messages->number > message_number)		{		  newp->next = current->current_set->messages;		  current->current_set->messages = newp;		}	      else		{		  struct message_list *runp;		  runp = current->current_set->messages;		  while (runp->next != NULL)		    if (runp->next->number > message_number)		      break;		    else		      runp = runp->next;		  newp->next = runp->next;		  runp->next = newp;		}	    }	  ++current->total_messages;	}      else	{	  size_t cnt;	  cnt = 0;	  /* See whether we have any non-white space character in this	     line.  */	  while (this_line[cnt] != '\0' && isspace (this_line[cnt]))	    ++cnt;	  if (this_line[cnt] != '\0')	    /* Yes, some unknown characters found.  */	    error_at_line (0, 0, fname, start_line,			   gettext ("malformed line ignored"));	}    ignore:      /* We can save the memory for the line if it was not used.  */      if (!used)	obstack_free (&current->mem_pool, this_line);    }  /* Close the conversion modules.  */  iconv_close (cd_towc);  iconv_close (cd_tomb);  free (codeset); out:  free (wbuf);  if (fp != stdin)    fclose (fp);  return current;}