• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Message list header manipulation.
2    Copyright (C) 2007, 2016-2017 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2007.
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 3 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU 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, see <https://www.gnu.org/licenses/>.  */
17 
18 
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 
23 /* Specification.  */
24 #include "msgl-header.h"
25 
26 #include <string.h>
27 
28 #include "xalloc.h"
29 
30 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
31 
32 
33 /* The known fields in their usual order.  */
34 static const struct
35 {
36   const char *name;
37   size_t len;
38 }
39 known_fields[] =
40   {
41     { "Project-Id-Version:", sizeof ("Project-Id-Version:") - 1 },
42     { "Report-Msgid-Bugs-To:", sizeof ("Report-Msgid-Bugs-To:") - 1 },
43     { "POT-Creation-Date:", sizeof ("POT-Creation-Date:") - 1 },
44     { "PO-Revision-Date:", sizeof ("PO-Revision-Date:") - 1 },
45     { "Last-Translator:", sizeof ("Last-Translator:") - 1 },
46     { "Language-Team:", sizeof ("Language-Team:") - 1 },
47     { "Language:", sizeof ("Language:") - 1 },
48     { "MIME-Version:", sizeof ("MIME-Version:") - 1 },
49     { "Content-Type:", sizeof ("Content-Type:") - 1 },
50     { "Content-Transfer-Encoding:", sizeof ("Content-Transfer-Encoding:") - 1 }
51   };
52 
53 
54 void
msgdomain_list_set_header_field(msgdomain_list_ty * mdlp,const char * field,const char * value)55 msgdomain_list_set_header_field (msgdomain_list_ty *mdlp,
56                                  const char *field, const char *value)
57 {
58   size_t field_len;
59   int field_index;
60   size_t k, i;
61 
62   field_len = strlen (field);
63 
64   /* Search the field in known_fields[].  */
65   field_index = -1;
66   for (k = 0; k < SIZEOF (known_fields); k++)
67     if (strcmp (known_fields[k].name, field) == 0)
68       {
69         field_index = k;
70         break;
71       }
72 
73   for (i = 0; i < mdlp->nitems; i++)
74     {
75       message_list_ty *mlp = mdlp->item[i]->messages;
76       size_t j;
77 
78       /* Search the header entry.  */
79       for (j = 0; j < mlp->nitems; j++)
80         if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete)
81           {
82             message_ty *mp = mlp->item[j];
83 
84             /* Modify the header entry.  */
85             const char *header = mp->msgstr;
86             char *new_header =
87               XNMALLOC (strlen (header) + 1
88                         + strlen (field) + 1 + strlen (value) + 1 + 1,
89                         char);
90 
91             /* Test whether the field already occurs in the header entry.  */
92             const char *h;
93 
94             for (h = header; *h != '\0'; )
95               {
96                 if (strncmp (h, field, field_len) == 0)
97                   break;
98                 h = strchr (h, '\n');
99                 if (h == NULL)
100                   break;
101                 h++;
102               }
103             if (h != NULL && *h != '\0')
104               {
105                 /* Replace the field.  */
106                 char *p = new_header;
107                 memcpy (p, header, h - header);
108                 p += h - header;
109                 p = stpcpy (p, field);
110                 p = stpcpy (stpcpy (stpcpy (p, " "), value), "\n");
111                 h = strchr (h, '\n');
112                 if (h != NULL)
113                   {
114                     h++;
115                     stpcpy (p, h);
116                   }
117               }
118             else if (field_index < 0)
119               {
120                 /* An unknown field.  Append it at the end.  */
121                 char *p = new_header;
122                 p = stpcpy (p, header);
123                 if (p > new_header && p[-1] != '\n')
124                   *p++ = '\n';
125                 p = stpcpy (p, field);
126                 stpcpy (stpcpy (stpcpy (p, " "), value), "\n");
127               }
128             else
129               {
130                 /* Find the appropriate position for inserting the field.  */
131                 for (h = header; *h != '\0'; )
132                   {
133                     /* Test whether h starts with a field name whose index is
134                        > field_index.  */
135                     for (k = field_index + 1; k < SIZEOF (known_fields); k++)
136                       if (strncmp (h, known_fields[k].name, known_fields[k].len)
137                           == 0)
138                         break;
139                     if (k < SIZEOF (known_fields))
140                       break;
141                     h = strchr (h, '\n');
142                     if (h == NULL)
143                       break;
144                     h++;
145                   }
146                 if (h != NULL && *h != '\0')
147                   {
148                     /* Insert the field at position h.  */
149                     char *p = new_header;
150                     memcpy (p, header, h - header);
151                     p += h - header;
152                     p = stpcpy (p, field);
153                     p = stpcpy (stpcpy (stpcpy (p, " "), value), "\n");
154                     stpcpy (p, h);
155                   }
156                 else
157                   {
158                     /* Append it at the end.  */
159                     char *p = new_header;
160                     p = stpcpy (p, header);
161                     if (p > new_header && p[-1] != '\n')
162                       *p++ = '\n';
163                     p = stpcpy (p, field);
164                     stpcpy (stpcpy (stpcpy (p, " "), value), "\n");
165                   }
166               }
167 
168             mp->msgstr = new_header;
169             mp->msgstr_len = strlen (new_header) + 1;
170           }
171     }
172 }
173 
174 
175 void
message_list_delete_header_field(message_list_ty * mlp,const char * field)176 message_list_delete_header_field (message_list_ty *mlp,
177                                   const char *field)
178 {
179   size_t field_len = strlen (field);
180   size_t j;
181 
182   /* Search the header entry.  */
183   for (j = 0; j < mlp->nitems; j++)
184     if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete)
185       {
186         message_ty *mp = mlp->item[j];
187 
188         /* Modify the header entry.  */
189         const char *header = mp->msgstr;
190 
191         /* Test whether the field occurs in the header entry.  */
192         const char *h;
193 
194         for (h = header; *h != '\0'; )
195           {
196             if (strncmp (h, field, field_len) == 0)
197               break;
198             h = strchr (h, '\n');
199             if (h == NULL)
200               break;
201             h++;
202           }
203         if (h != NULL && *h != '\0')
204           {
205             /* Delete the field.  */
206             char *new_header = XCALLOC (strlen (header) + 1, char);
207 
208             char *p = new_header;
209             memcpy (p, header, h - header);
210             p += h - header;
211             h = strchr (h, '\n');
212             if (h != NULL)
213               {
214                 h++;
215                 strcpy (p, h);
216               }
217             else
218               *p = '\0';
219 
220             mp->msgstr = new_header;
221             mp->msgstr_len = strlen (new_header) + 1;
222           }
223       }
224 }
225