text: /* Message list header manipulation.
     Copyright (C) 2007 Free Software Foundation, Inc.
     Written by Bruno Haible <bruno@clisp.org>, 2007.
  
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 3 of the License, or
     (at your option) any later version.
  
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
  
     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
  
  
  #ifdef HAVE_CONFIG_H
  # include "config.h"
  #endif
  
  /* Specification.  */
  #include "msgl-header.h"
  
  #include <string.h>
  
  #include "xalloc.h"
  
  #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
  
  
  void
  msgdomain_list_set_header_field (msgdomain_list_ty *mdlp,
                                   const char *field, const char *value)
  {
    /* The known fields in their usual order.  */
    static const struct
      {
        const char *name;
        size_t len;
      }
    known_fields[] =
      {
        { "Project-Id-Version:", sizeof ("Project-Id-Version:") - 1 },
        { "Report-Msgid-Bugs-To:", sizeof ("Report-Msgid-Bugs-To:") - 1 },
        { "POT-Creation-Date:", sizeof ("POT-Creation-Date:") - 1 },
        { "PO-Revision-Date:", sizeof ("PO-Revision-Date:") - 1 },
        { "Last-Translator:", sizeof ("Last-Translator:") - 1 },
        { "Language-Team:", sizeof ("Language-Team:") - 1 },
        { "Language:", sizeof ("Language:") - 1 },
        { "MIME-Version:", sizeof ("MIME-Version:") - 1 },
        { "Content-Type:", sizeof ("Content-Type:") - 1 },
        { "Content-Transfer-Encoding:",
          sizeof ("Content-Transfer-Encoding:") - 1 }
      };
    size_t field_len;
    int field_index;
    size_t k, i;
  
    field_len = strlen (field);
  
    /* Search the field in known_fields[].  */
    field_index = -1;
    for (k = 0; k < SIZEOF (known_fields); k++)
      if (strcmp (known_fields[k].name, field) == 0)
        {
          field_index = k;
          break;
        }
  
    for (i = 0; i < mdlp->nitems; i++)
      {
        message_list_ty *mlp = mdlp->item[i]->messages;
        size_t j;
  
        /* Search the header entry.  */
        for (j = 0; j < mlp->nitems; j++)
          if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete)
            {
              message_ty *mp = mlp->item[j];
  
              /* Modify the header entry.  */
              const char *header = mp->msgstr;
              char *new_header =
                XNMALLOC (strlen (header) + 1
                          + strlen (field) + 1 + strlen (value) + 1 + 1,
                          char);
  
              /* Test whether the field already occurs in the header entry.  */
              const char *h;
  
              for (h = header; *h != '\0'; )
                {
                  if (strncmp (h, field, field_len) == 0)
                    break;
                  h = strchr (h, '\n');
                  if (h == NULL)
                    break;
                  h++;
                }
              if (h != NULL && *h != '\0')
                {
                  /* Replace the field.  */
                  char *p = new_header;
                  memcpy (p, header, h - header);
                  p += h - header;
                  p = stpcpy (p, field);
                  p = stpcpy (stpcpy (stpcpy (p, " "), value), "\n");
                  h = strchr (h, '\n');
                  if (h != NULL)
                    {
                      h++;
                      stpcpy (p, h);
                    }
                }
              else if (field_index < 0)
                {
                  /* An unknown field.  Append it at the end.  */
                  char *p = new_header;
                  p = stpcpy (p, header);
                  if (p > new_header && p[-1] != '\n')
                    *p++ = '\n';
                  p = stpcpy (p, field);
                  stpcpy (stpcpy (stpcpy (p, " "), value), "\n");
                }
              else
                {
                  /* Find the appropriate position for inserting the field.  */
                  for (h = header; *h != '\0'; )
                    {
                      /* Test whether h starts with a field name whose index is
                         > field_index.  */
                      for (k = field_index + 1; k < SIZEOF (known_fields); k++)
                        if (strncmp (h, known_fields[k].name, known_fields[k].len)
                            == 0)
                          break;
                      if (k < SIZEOF (known_fields))
                        break;
                      h = strchr (h, '\n');
                      if (h == NULL)
                        break;
                      h++;
                    }
                  if (h != NULL && *h != '\0')
                    {
                      /* Insert the field at position h.  */
                      char *p = new_header;
                      memcpy (p, header, h - header);
                      p += h - header;
                      p = stpcpy (p, field);
                      p = stpcpy (stpcpy (stpcpy (p, " "), value), "\n");
                      stpcpy (p, h);
                    }
                  else
                    {
                      /* Append it at the end.  */
                      char *p = new_header;
                      p = stpcpy (p, header);
                      if (p > new_header && p[-1] != '\n')
                        *p++ = '\n';
                      p = stpcpy (p, field);
                      stpcpy (stpcpy (stpcpy (p, " "), value), "\n");
                    }
                }
  
              mp->msgstr = new_header;
            }
      }
  }
  