POSIX.1 National Language Support API for MinGW
Révision | aeedfdf6ea611f82e97fd878b15d872cf4c9a593 (tree) |
---|---|
l'heure | 2007-05-13 01:54:36 |
Auteur | Keith Marshall <keithmarshall@user...> |
Commiter | Keith Marshall |
Add support for single message deletion.
@@ -1,3 +1,29 @@ | ||
1 | +2007-05-12 Keith Marshall <keithmarshall@users.sourceforge.net> | |
2 | + | |
3 | + Add support for single message deletion. | |
4 | + | |
5 | + * mcsource.c: More comment improvements. | |
6 | + (mc_source): Set `this->base = NULL' on parsing a message number | |
7 | + immediately followed by `newline'; this causes the message to be | |
8 | + removed from the internal catalogue index, when the input record | |
9 | + is merged. | |
10 | + | |
11 | + * mcmerge.c (mc_merge): Reorganise logic; add section to remove | |
12 | + entries with `set > 0 && msg > 0 && base == NULL'. | |
13 | + Relocate logic block for processing `delset' requests; still need | |
14 | + an implementation for this. | |
15 | + Add logic block to catch and diagnose invalid index entries. | |
16 | + | |
17 | + * include/gcmsgs.h (MSG_CATLOAD_FAILED): Renamed symbolic define... | |
18 | + (MSG_BAD_CATALOGUE): ...to this. | |
19 | + (MSG_INTERNAL_ERROR, MSG_BAD_INDEX): New message defines; used by | |
20 | + `mc_merge', to diagnose invalid index entries. | |
21 | + | |
22 | + * include/gencat.h (msgarg): New macro; used by `mc_merge', to | |
23 | + associate `MSG_BAD_INDEX' with `MSG_INTERNAL_ERROR'. | |
24 | + | |
25 | + * gencat.c (main): Use `MSG_BAD_CATALOGUE'. | |
26 | + | |
1 | 27 | 2007-05-11 Keith Marshall <keithmarshall@users.sourceforge.net> |
2 | 28 | |
3 | 29 | * mcsource.c: Miscellaneous comment and layout improvements; |
@@ -8,7 +8,7 @@ | ||
8 | 8 | * This file implements the `main' function for the `gencat' program. |
9 | 9 | * |
10 | 10 | * Written by Keith Marshall <keithmarshall@users.sourceforge.net> |
11 | - * Last modification: 05-Mar-2007 | |
11 | + * Last modification: 12-May-2007 | |
12 | 12 | * |
13 | 13 | * |
14 | 14 | * This is free software. It is provided AS IS, in the hope that it may |
@@ -90,7 +90,6 @@ int main( int argc, char **argv ) | ||
90 | 90 | /* Initialise the message list, to incorporate any messages which |
91 | 91 | * are already contained within the specified message catalogue. |
92 | 92 | */ |
93 | - | |
94 | 93 | if( (cat = mc_load( msgcat = *++argv )) == NULL ) |
95 | 94 | switch( errno ) |
96 | 95 | { |
@@ -102,13 +101,12 @@ int main( int argc, char **argv ) | ||
102 | 101 | break; |
103 | 102 | |
104 | 103 | default: |
105 | - fprintf( errmsg( MSG_CATLOAD_FAILED ), progname, msgcat ); | |
104 | + fprintf( errmsg( MSG_BAD_CATALOGUE ), progname, msgcat ); | |
106 | 105 | return EXIT_FAILURE; |
107 | 106 | } |
108 | 107 | |
109 | 108 | /* Merge new or updated message definitions from input files. |
110 | 109 | */ |
111 | - | |
112 | 110 | while( --argc ) |
113 | 111 | cat = mc_merge( cat, mc_source( *++argv )); |
114 | 112 |
@@ -199,7 +197,6 @@ int main( int argc, char **argv ) | ||
199 | 197 | /* User specified insufficient command line arguments. |
200 | 198 | * Diagnose, and bail out. |
201 | 199 | */ |
202 | - | |
203 | 200 | fprintf( errmsg( MSG_MISSING_ARGS ), progname ); |
204 | 201 | fprintf( errmsg( MSG_GENCAT_USAGE ), progname ); |
205 | 202 | return EXIT_FAILURE; |
@@ -207,4 +204,4 @@ int main( int argc, char **argv ) | ||
207 | 204 | return EXIT_SUCCESS; |
208 | 205 | } |
209 | 206 | |
210 | -/* $RCSfile$Revision$: end of file */ | |
207 | +/* $RCSfile$Revision: 1.1.1.1 $: end of file */ |
@@ -40,7 +40,8 @@ | ||
40 | 40 | #define MSG_GENCAT_USAGE 1, 2, "usage: %s catalogue-name input-file ...\n" |
41 | 41 | #define MSG_OUTPUT_NOFILE 1, 3, "%s: %s: cannot create temporary output file\n" |
42 | 42 | #define MSG_OUT_OF_MEMORY 1, 4, "%s: out of memory\n" |
43 | -#define MSG_CATLOAD_FAILED 2, 1, "%s: %s: catalogue exists, but failed to load\n" | |
43 | +#define MSG_INTERNAL_ERROR 1, 5, "%s: internal error: %s\n" | |
44 | +#define MSG_BAD_CATALOGUE 2, 1, "%s: %s: file is not a valid message catalogue\n" | |
44 | 45 | #define MSG_UNKNOWN_CODESET 2, 2, "%s: %s: unknown codeset descriptor\n" |
45 | 46 | #define MSG_CODESET_CLASH 2, 3, "%s:%u: codeset `%s' conflicts with prior declaration\n" |
46 | 47 | #define MSG_HAD_CODESET 2, 4, "%s:%u: codeset `%s' was previously declared here\n" |
@@ -48,11 +49,12 @@ | ||
48 | 49 | #define MSG_MSGNUM_NOT_INCR 2, 6, "invalid message number: expecting > %d; got %d\n" |
49 | 50 | #define MSG_REDEFINED 2, 7, "%s: %s:%u: redefinition of message %u in set %u\n" |
50 | 51 | #define MSG_PREVIOUS_HERE 2, 8, "%s: %s:%u: previous definition was here\n" |
51 | -#define MSG_DEL_UNSUPPORTED 3, 1, "%s: %s:%u: deletion of message entities not yet supported\n" | |
52 | +#define MSG_DEL_UNSUPPORTED 3, 1, "%s: %s:%u: `delset' operation not yet supported\n" | |
52 | 53 | #define MSG_EOF_IN_QUOTES 3, 2, "%s:%u: unexpected EOF encountered before closing quote\n" |
53 | 54 | #define MSG_TEXT_DISCARDED 3, 3, "%s:%u: incomplete message marked for deletion\n" |
54 | 55 | #define MSG_MISSING_NEWLINE 3, 4, "%s:%u: missing newline at end of file\n" |
56 | +#define MSG_BAD_INDEX 3, 5, "invalid reference in message index" | |
55 | 57 | /* ! |
56 | 58 | * !$ end of file |
57 | 59 | */ |
58 | -#endif /* !defined( GCMSGS_H ): $RCSfile$Revision$: end of file */ | |
60 | +#endif /* !defined( GCMSGS_H ): $RCSfile$Revision: 1.1.1.1 $: end of file */ |
@@ -11,7 +11,7 @@ | ||
11 | 11 | * the prototypes for the functions used to implement `gencat'. |
12 | 12 | * |
13 | 13 | * Written by Keith Marshall <keithmarshall@users.sourceforge.net> |
14 | - * Last modification: 27-Mar-2007 | |
14 | + * Last modification: 12-May-2007 | |
15 | 15 | * |
16 | 16 | * |
17 | 17 | * This is free software. It is provided AS IS, in the hope that it may |
@@ -89,10 +89,11 @@ extern struct msgdict *mc_merge( struct msgdict *, struct msgdict * ); | ||
89 | 89 | extern char *map_codeset( iconv_t *, char *, char * ); |
90 | 90 | extern size_t iconv_wrap( int, iconv_t, char *, size_t, char *, size_t ); |
91 | 91 | |
92 | +#define msgarg(MSG) catgets( gencat_messages, MSG ) | |
92 | 93 | #define errmsg(MSG) stderr, catgets( gencat_messages, MSG ) |
93 | 94 | #define FATAL(MSG) input, linenum, catgets( gencat_messages, MSG ) |
94 | 95 | |
95 | 96 | #define GENCAT_MSG_SRC(REF) progname, (REF)->src, (REF)->lineno |
96 | 97 | #define GENCAT_MSG_INPUT GENCAT_MSG_SRC( input ) |
97 | 98 | |
98 | -#endif /* !defined( GENCAT_H ): $RCSfile$Revision$: end of file */ | |
99 | +#endif /* !defined( GENCAT_H ): $RCSfile$Revision: 1.1.1.1 $: end of file */ |
@@ -10,7 +10,7 @@ | ||
10 | 10 | * any single source file into its current internal dictionary. |
11 | 11 | * |
12 | 12 | * Written by Keith Marshall <keithmarshall@users.sourceforge.net> |
13 | - * Last modification: 30-Dec-2006 | |
13 | + * Last modification: 12-May-2007 | |
14 | 14 | * |
15 | 15 | * |
16 | 16 | * This is free software. It is provided AS IS, in the hope that it may |
@@ -65,128 +65,196 @@ struct msgdict *mc_merge( struct msgdict *cat, struct msgdict *input ) | ||
65 | 65 | |
66 | 66 | while( input ) |
67 | 67 | { |
68 | + /* Save a pointer to the *next* input record; | |
69 | + * we will use this later, to progress to the next record, | |
70 | + * after we've freed the current reference structure. | |
71 | + */ | |
68 | 72 | struct msgdict *next = input->link; |
69 | 73 | |
70 | 74 | dfprintf(( stderr, "Process entry from %s line %u\n", input->src, input->lineno )); |
71 | - if( input->base == NULL ) | |
72 | - { | |
73 | - /* This is a `delete' operation... | |
74 | - * FIXME: we don't have support for this yet! | |
75 | - */ | |
76 | - fprintf( errmsg( MSG_DEL_UNSUPPORTED ), progname, input->src, input->lineno ); | |
77 | - free( input ); | |
78 | - } | |
79 | 75 | |
80 | - else | |
76 | + if( input->set && input->msg ) | |
81 | 77 | { |
82 | - /* This is either an `insert' or a `replace' operation... | |
83 | - * locate the insertion point, within the current message list. | |
78 | + /* The input reference specifies both set and message numbers. | |
79 | + * Thus, the operation to be performed relates to a single message, | |
80 | + * which is to be inserted, replaced or deleted at the appropriate | |
81 | + * position within the current message list; before proceeding, | |
82 | + * we must locate this position. | |
84 | 83 | */ |
85 | - | |
86 | 84 | struct msgdict *curr = mark; |
87 | 85 | while( curr && (curr->key < input->key) ) |
88 | 86 | { |
87 | + /* We loop over the existing messages in the dictionary, | |
88 | + * until we find the location at which the input message | |
89 | + * should be placed; when we find it, we leave `curr' | |
90 | + * pointing at the target location reference, while | |
91 | + * `mark' points to its immediate predecessor. | |
92 | + */ | |
89 | 93 | mark = curr; |
90 | 94 | curr = curr->link; |
91 | 95 | } |
92 | 96 | |
93 | - if( curr == NULL ) | |
97 | + /* Now that we've identified *where* the current input reference | |
98 | + * belongs, in the current message list, we may determine *what* | |
99 | + * action is to be performed for this record. | |
100 | + */ | |
101 | + if( input->base && (curr == NULL) ) | |
94 | 102 | { |
95 | - /* This is appending to the end of the message list... */ | |
96 | - | |
103 | + /* The input record specifies actual message content, | |
104 | + * which is to be appended to the end of the message list... | |
105 | + */ | |
97 | 106 | if( mark ) |
98 | 107 | { |
99 | - /* ...extending an existing message list. */ | |
100 | - | |
108 | + /* ...extending an existing message list. | |
109 | + */ | |
101 | 110 | input->link = mark->link; |
102 | 111 | mark->link = input; |
103 | 112 | dfprintf(( stderr, "Append set %u message %u after set %u message %u\n", |
104 | 113 | input->set, input->msg, mark->set, mark->msg |
105 | 114 | )); |
106 | 115 | } |
107 | - | |
108 | 116 | else |
109 | 117 | { |
110 | - /* There is no current message list; start one now! */ | |
111 | - | |
118 | + /* ...there is no current message list; start one now! | |
119 | + */ | |
112 | 120 | cat = mark = input; |
113 | 121 | mark->link = NULL; |
114 | 122 | dfprintf(( stderr, "Initialise message list at set %u message %u\n", mark->set, mark->msg )); |
115 | 123 | } |
116 | 124 | } |
117 | - | |
118 | 125 | else if( curr->key == input->key ) |
119 | 126 | { |
120 | - /* This is replacement of an existing message. */ | |
121 | - | |
122 | - if( curr->lineno > 0 ) | |
127 | + /* The input record refers to a message which is already present | |
128 | + * in the current message list; the operation to be performed is | |
129 | + * either deletion or replacement. | |
130 | + */ | |
131 | + if( input->base == NULL ) | |
123 | 132 | { |
124 | - /* This a collision... | |
125 | - * diagnose, and ignore this redefinition. | |
133 | + /* This input reference specifies no message content; | |
134 | + * it is a request to delete the existing message. | |
135 | + */ | |
136 | + if( curr == cat ) | |
137 | + /* | |
138 | + * We are deleting the first message in the current list, | |
139 | + * so we simply reassign the initial list entry. | |
140 | + */ | |
141 | + cat = cat->link; | |
142 | + | |
143 | + else | |
144 | + /* We are deleting a message from within the list, so we | |
145 | + * relink the immediately preceding reference, to chain it | |
146 | + * directly to the immediately succeeding one. | |
147 | + */ | |
148 | + mark->link = curr->link; | |
149 | + | |
150 | + /* In either case, we may release the the memory allocated to | |
151 | + * the defunct dictionary reference for the deleted message. | |
126 | 152 | */ |
153 | + free( curr ); | |
154 | + } | |
127 | 155 | |
156 | + else if( curr->lineno > 0 ) | |
157 | + { | |
158 | + /* This a redefinition of a message which has previously been | |
159 | + * sourced from another input file in the current input stream; | |
160 | + * this represents a collision, which is probably unintentional, | |
161 | + * so diagnose it, and ignore this redefinition. | |
162 | + */ | |
128 | 163 | fprintf( errmsg( MSG_REDEFINED ), GENCAT_MSG_INPUT, curr->msg, curr->set ); |
129 | 164 | fprintf( errmsg( MSG_PREVIOUS_HERE ), GENCAT_MSG_SRC( curr )); |
130 | 165 | } |
131 | 166 | |
132 | 167 | else |
133 | 168 | { |
169 | + /* This is replacement of an existing message, which has | |
170 | + * been inherited from a previously existing message catalogue; | |
171 | + * such replacement is assumed to be intentional, so... | |
172 | + */ | |
134 | 173 | dfprintf(( stderr, "Replace set %u message %u\n", curr->set, curr->msg )); |
135 | - | |
136 | 174 | if( curr == cat ) |
137 | 175 | { |
138 | - /* This is the first message in the current list, | |
139 | - * so we simply replace it. | |
176 | + /* ...when this is the first message in the current list, | |
177 | + * we simply replace it. | |
140 | 178 | */ |
141 | - | |
142 | 179 | cat = input; |
143 | 180 | } |
144 | 181 | |
145 | 182 | else |
146 | 183 | { |
147 | - /* There are preceding messages in the list, | |
148 | - * so we must relink the predecessor to this replacement. | |
184 | + /* ...but when there are preceding messages in the list, | |
185 | + * we must relink the predecessor to this replacement. | |
149 | 186 | */ |
150 | - | |
151 | 187 | mark->link = input; |
152 | 188 | } |
153 | 189 | |
190 | + /* Now, to complete the replacement of the original message, | |
191 | + * link any successor to the new reference, release the memory | |
192 | + * allocated to the replaced dictionary entry, and mark the | |
193 | + * new entry as the current reference point. | |
194 | + */ | |
154 | 195 | input->link = curr->link; |
155 | 196 | free( curr ); |
156 | 197 | mark = input; |
157 | 198 | } |
158 | 199 | } |
159 | - | |
160 | 200 | else |
161 | 201 | { |
162 | - /* This is insertion of a new message within the current list, | |
163 | - * (maybe preceding all messages which are already in the list). | |
202 | + /* There is no existing reference with set and message numbers | |
203 | + * matching the current input record; thus the input record must | |
204 | + * be inserted between the existing `mark' and `curr' entries. | |
164 | 205 | */ |
165 | - | |
166 | 206 | dfprintf(( stderr, "Insert set %u message %u ", input->set, input->msg )); |
167 | 207 | if( mark == curr ) |
168 | 208 | { |
169 | - /* This entry must precede any which is already in the list, | |
170 | - * so make it the new initial message. | |
209 | + /* The `curr' entry is the first in the existing dictionary, | |
210 | + * so we insert the input record before it, as the new initial | |
211 | + * entry in the dictionary, leaving `mark' pointing to it. | |
171 | 212 | */ |
172 | - | |
173 | 213 | dfprintf(( stderr, "at start of list " )); |
174 | 214 | cat = mark = input; |
175 | 215 | } |
176 | - | |
177 | 216 | else |
178 | 217 | { |
179 | - /* There is already an existing message which must precede this one, | |
180 | - * so link this new one to follow the existing predecessor. | |
218 | + /* There is already an existing message which must precede this | |
219 | + * new entry in the dictionary, so we link this new entry as its | |
220 | + * immediate successor. | |
181 | 221 | */ |
182 | - | |
183 | 222 | dfprintf(( stderr, "after set %u message %u and ", mark->set, mark->msg )); |
184 | 223 | mark->link = input; |
185 | 224 | } |
225 | + /* | |
226 | + * In either case, any existing `curr' entry must be linked as | |
227 | + * successor to the inserted entry. | |
228 | + */ | |
186 | 229 | dfprintf(( stderr, "before set %u message %u\n", curr->set, curr->msg )); |
187 | 230 | input->link = curr; |
188 | 231 | } |
189 | 232 | } |
233 | + | |
234 | + else if( input->set && (input->base == NULL) ) | |
235 | + { | |
236 | + /* This is a a `delset' operation... | |
237 | + * FIXME: we don't have support for this yet! | |
238 | + */ | |
239 | + fprintf( errmsg( MSG_DEL_UNSUPPORTED ), progname, input->src, input->lineno ); | |
240 | + free( input ); | |
241 | + } | |
242 | + | |
243 | + else | |
244 | + { | |
245 | + /* The input record contains an improperly formed message reference. | |
246 | + * We should *never* get to here! If we do, then the entire message | |
247 | + * catalogue dictionary structure is invalid; diagnose and abort. | |
248 | + */ | |
249 | + fprintf( errmsg( MSG_INTERNAL_ERROR ), progname, msgarg( MSG_BAD_INDEX ) ); | |
250 | + exit( EXIT_FAILURE ); | |
251 | + } | |
252 | + | |
253 | + /* Whatever operation we have just performed, if no fatal error | |
254 | + * occurred we proceed to the next input record, if any, using the | |
255 | + * pointer we saved earlier, since `input->link' may not now be | |
256 | + * a valid reference; (`input' may have been `freed'). | |
257 | + */ | |
190 | 258 | input = next; |
191 | 259 | } |
192 | 260 | # ifdef DEBUG |
@@ -197,7 +265,11 @@ struct msgdict *mc_merge( struct msgdict *cat, struct msgdict *input ) | ||
197 | 265 | fprintf( stderr, "%s:%u: set %u message %u\n", curr->src, curr->lineno, curr->set, curr->msg ); |
198 | 266 | } |
199 | 267 | # endif |
268 | + | |
269 | + /* When all input records have been processed, | |
270 | + * we return the resultant message catalogue index to the caller. | |
271 | + */ | |
200 | 272 | return cat; |
201 | 273 | } |
202 | 274 | |
203 | -/* $RCSfile$Revision$: end of file */ | |
275 | +/* $RCSfile$Revision: 1.1.1.1 $: end of file */ |
@@ -9,7 +9,7 @@ | ||
9 | 9 | * used internally by `gencat', to compile message dictionaries. |
10 | 10 | * |
11 | 11 | * Written by Keith Marshall <keithmarshall@users.sourceforge.net> |
12 | - * Last modification: 11-May-2007 | |
12 | + * Last modification: 12-May-2007 | |
13 | 13 | * |
14 | 14 | * |
15 | 15 | * This is free software. It is provided AS IS, in the hope that it may |
@@ -543,9 +543,16 @@ struct msgdict *mc_source( const char *input ) | ||
543 | 543 | |
544 | 544 | /* We may now complete the message details in the new |
545 | 545 | * dictionary slot, and commit the record to the catalogue. |
546 | + * Note that, if the message number tag in the source file | |
547 | + * is on an otherwise empty line, and is *immediately* | |
548 | + * followed by a newline, with no intervening space, | |
549 | + * then this message should be deleted; we flag this | |
550 | + * by setting `this->base = NULL'. In all other cases, | |
551 | + * the message is to be placed into the catalogue, so | |
552 | + * we set 'this->base = messages'. | |
546 | 553 | */ |
547 | 554 | this->src = input; |
548 | - this->base = messages; | |
555 | + this->base = (c == L'\n') ? NULL : messages; | |
549 | 556 | this->lineno = linenum; |
550 | 557 | this->set = setnum; |
551 | 558 | this->msg = msgnum = accumulator; |
@@ -573,8 +580,10 @@ struct msgdict *mc_source( const char *input ) | ||
573 | 580 | |
574 | 581 | else |
575 | 582 | { |
576 | - /* This doesn't satisfy the requirement for incrementing "msgnum", | |
577 | - * so complain, and bail out. | |
583 | + /* This doesn't satisfy the POSIX requirement that, | |
584 | + * within each set, messages must appear in strictly | |
585 | + * incrementing "msgnum" order, so complain, and | |
586 | + * bail out. | |
578 | 587 | */ |
579 | 588 | dfputc(( '\n', stderr )); |
580 | 589 | gencat_errno = mc_errout( FATAL( MSG_MSGNUM_NOT_INCR ), msgnum, accumulator ); |
@@ -832,6 +841,12 @@ struct msgdict *mc_source( const char *input ) | ||
832 | 841 | dfprintf(( stderr, "\n\nAllocation adjusted to %u bytes\n", (unsigned)(msgloc) )); |
833 | 842 | for( tail = head; tail != NULL; tail = tail->link ) |
834 | 843 | { |
844 | + /* Just do this for all entries in the list! | |
845 | + * Don't assume we can optimise by quitting if we find a reference | |
846 | + * which is already mapped to the correct address; the list could | |
847 | + * have moved, and subsequently have moved back to the old address, | |
848 | + * in which case a later entry could be invalid. | |
849 | + */ | |
835 | 850 | if( tail->base != NULL ) |
836 | 851 | /* |
837 | 852 | * Update index entries *except* those with a NULL base pointer; |
@@ -849,4 +864,4 @@ struct msgdict *mc_source( const char *input ) | ||
849 | 864 | return head; |
850 | 865 | } |
851 | 866 | |
852 | -/* $RCSfile$Revision: 1.4 $: end of file */ | |
867 | +/* $RCSfile$Revision: 1.5 $: end of file */ |