Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

[a784c9]: mcmerge.c Maximize Restore History

Download this file

mcmerge.c    380 lines (353 with data), 12.2 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
/*
* mcmerge.c
*
* $Id$
*
* Copyright (C) 2006, Keith Marshall
*
* This file implements the `mc_merge' function, which is used by
* `gencat' to merge the compiled message dictionary derived from
* any single source file into its current internal dictionary.
*
* Written by Keith Marshall <keithmarshall@users.sourceforge.net>
* Last modification: 17-Aug-2007
*
*
* This is free software. It is provided AS IS, in the hope that it may
* be useful, but WITHOUT WARRANTY OF ANY KIND, not even an IMPLIED WARRANTY
* of MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.
*
* Permission is granted to redistribute this software, either "as is" or
* in modified form, under the terms of the GNU General Public License, as
* published by the Free Software Foundation; either version 2, or (at your
* option) any later version.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to the
* Free Software Foundation, 51 Franklin St - Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <debug.h>
#include <stdio.h>
#include <stdlib.h>
#include <gencat.h>
#include <gcmsgs.h>
static
struct msgdict *mc_delset( unsigned short setnum, struct msgdict *msgset )
{
/* Helper function, called by `mc_merge', to unlink message references
* in any set specified in a `delset' directive.
*/
while( msgset && (msgset->set == setnum) )
{
/* Walk the message list, freeing the memory allocated to message
* entries with matching set number.
*/
struct msgdict *ref = msgset;
msgset = msgset->link;
free( ref );
}
/* When done, return the address of the first message in the set,
* if any, following the one we just deleted; `mc_merge' will link
* this to succeed the predecessor, if any, of the deleted set,
* or otherwise, replacing the first set in the catalogue,
* thus implicitly unlinking the deleted messages.
*/
return msgset;
}
struct msgdict *mc_merge( struct msgdict *cat, struct msgdict *input )
{
struct msgdict *mark = cat;
# ifdef DEBUG
if( input )
{
struct msgdict *curr;
if( cat == NULL )
{
fprintf( stderr, "no existing messages in catalogue; loading %s\n", input->src );
}
else
{
fprintf( stderr, "merge messages from %s\n", input->src );
for( curr = cat; curr != NULL; curr = curr->link )
fprintf( stderr, "%s:%u: set %u message %u\n", curr->src, curr->lineno, curr->set, curr->msg );
}
for( curr = input; curr != NULL; curr = curr->link )
fprintf( stderr, "%s:%u: set %u message %u\n", curr->src, curr->lineno, curr->set, curr->msg );
}
# endif
while( input )
{
/* Save a pointer to the *next* input record;
* we will use this later, to progress to the next record,
* after we've freed the current reference structure.
*/
struct msgdict *next = input->link;
dfprintf(( stderr, "Process entry from %s line %u\n", input->src, input->lineno ));
if( input->set && input->msg )
{
/* The input reference specifies both set and message numbers.
* Thus, the operation to be performed relates to a single message,
* which is to be inserted, replaced or deleted at the appropriate
* position within the current message list; before proceeding,
* we must locate this position.
*/
struct msgdict *curr = mark;
while( curr && (curr->key < input->key) )
{
/* We loop over the existing messages in the dictionary,
* until we find the location at which the input message
* should be placed; when we find it, we leave `curr'
* pointing at the target location reference, while
* `mark' points to its immediate predecessor.
*/
mark = curr;
curr = curr->link;
}
/* Now that we've identified *where* the current input reference
* belongs, in the current message list, we may determine *what*
* action is to be performed for this record.
*/
if( input->base && (curr == NULL) )
{
/* The input record specifies actual message content,
* which is to be appended to the end of the message list...
*/
if( mark )
{
/* ...extending an existing message list.
*/
input->link = mark->link;
mark->link = input;
dfprintf(( stderr, "Append set %u message %u after set %u message %u\n",
input->set, input->msg, mark->set, mark->msg
));
}
else
{
/* ...there is no current message list; start one now!
*/
cat = mark = input;
mark->link = NULL;
dfprintf(( stderr, "Initialise message list at set %u message %u\n", mark->set, mark->msg ));
}
}
else if( curr && (curr->key == input->key) )
{
/* The input record refers to a message which is already present
* in the current message list; the operation to be performed is
* either deletion or replacement.
*/
if( input->base == NULL )
{
/* This input reference specifies no message content;
* it is a request to delete the existing message.
*/
if( curr == cat )
/*
* We are deleting the first message in the current list,
* so we simply reassign the initial list entry.
*/
cat = cat->link;
else
/* We are deleting a message from within the list, so we
* relink the immediately preceding reference, to chain it
* directly to the immediately succeeding one.
*/
mark->link = curr->link;
/* In either case, we may release the the memory allocated to
* the defunct dictionary reference for the deleted message.
*/
free( curr );
}
else if( curr->lineno > 0 )
{
/* This a redefinition of a message which has previously been
* sourced from another input file in the current input stream;
* this represents a collision, which is probably unintentional,
* so diagnose it, and ignore this redefinition.
*/
fprintf( errmsg( MSG_REDEFINED ), GENCAT_MSG_INPUT, curr->msg, curr->set );
fprintf( errmsg( MSG_PREVIOUS_HERE ), GENCAT_MSG_SRC( curr ));
}
else
{
/* This is replacement of an existing message, which has
* been inherited from a previously existing message catalogue;
* such replacement is assumed to be intentional, so...
*/
dfprintf(( stderr, "Replace set %u message %u\n", curr->set, curr->msg ));
if( curr == cat )
{
/* ...when this is the first message in the current list,
* we simply replace it.
*/
cat = input;
}
else
{
/* ...but when there are preceding messages in the list,
* we must relink the predecessor to this replacement.
*/
mark->link = input;
}
/* Now, to complete the replacement of the original message,
* link any successor to the new reference, release the memory
* allocated to the replaced dictionary entry, and mark the
* new entry as the current reference point.
*/
input->link = curr->link;
free( curr );
mark = input;
}
}
else if( curr )
{
/* There is no existing reference with set and message numbers
* matching the current input record; thus the input record must
* be inserted between the existing `mark' and `curr' entries.
*/
dfprintf(( stderr, "Insert set %u message %u ", input->set, input->msg ));
if( mark == curr )
{
/* The `curr' entry is the first in the existing dictionary,
* so we insert the input record before it, as the new initial
* entry in the dictionary, leaving `mark' pointing to it.
*/
dfprintf(( stderr, "at start of list " ));
cat = mark = input;
}
else
{
/* There is already an existing message which must precede this
* new entry in the dictionary, so we link this new entry as its
* immediate successor.
*/
dfprintf(( stderr, "after set %u message %u and ", mark->set, mark->msg ));
mark->link = input;
}
/*
* In either case, any existing `curr' entry must be linked as
* successor to the inserted entry.
*/
dfprintf(( stderr, "before set %u message %u\n", curr->set, curr->msg ));
input->link = curr;
}
# ifdef DEBUG
else
{
/* There is no `curr' record and the input record has not been
* appended; this must be a delete request, with nothing to act on,
* so we simply ignore it.
*/
dfprintf(( stderr, "Ignore delete request for non-existent message\n" ));
}
# endif
}
else if( input->set && (input->base == NULL) )
{
/* This is a a `delset' operation; it will delete all messages
* currently present in the catalogue, which are assigned to the
* specified message set.
*
* Obviously, if the catalogue is currently empty, then this is
* a no-op...
*/
if( cat )
{
/* ...but when we do already have some content defined, then we
* must locate and delete the specified set, if it exists.
*/
if( cat->set == input->set )
{
/* The set to be deleted is the first in the catalogue...
*/
if( mark->set == input->set )
/*
* ...and the current insertion point also lies within
* this set, so *both* references must be adjusted.
*/
mark = cat = mc_delset( input->set, cat );
else
/* ...the current insertion point has already advanced
* beyond the set to be deleted, so leave it unchanged,
* and simply remove the entire initial message set.
*/
cat = mc_delset( input->set, cat );
}
else
{
/* The set to be deleted is not the first in the catalogue,
* so we must locate the last message entry in the set which
* immediately precedes that to be deleted; this becomes the
* reference point, from which deletion commences, and to
* which any following message set must be relinked.
*/
struct msgdict *delset, *ref = cat;
/* Our search for this reference entry begins at the start
* of the catalogue; however, if the current insertion point
* lies in a set which precedes that to be deleted, then we
* may immediately jump ahead to this point.
*/
if( mark->key < input->key )
ref = mark;
/* We now walk the message list, until we either find the
* required reference point, or our search overruns the end
* of the list.
*/
while( ((delset = ref->link) != NULL) && (delset->key < input->key) )
ref = delset;
/* Now, we must check the current insertion point, to ensure
* that * it does not refer to an entry we are about to delete;
* if it points to a message with a set number matching that of
* the set to be deleted, then we must adjust it.
*/
if( mark->set == input->set )
mark = ref;
/* Finally, if we found entries in the set to be deleted,
* then we discard them.
*/
if( delset->set == input->set )
ref->link = mc_delset( input->set, delset );
}
}
/* Whether or not we actually found and deleted the specified
* message set, (if not, we silently ignore the `delset' request),
* the current input record serves no further purpose.
*/
free( input );
}
else
{
/* The input record contains an improperly formed message reference.
* We should *never* get to here! If we do, then the entire message
* catalogue dictionary structure is invalid; diagnose and abort.
*/
fprintf( errmsg( MSG_INTERNAL_ERROR ), progname, msgarg( MSG_BAD_INDEX ) );
exit( EXIT_FAILURE );
}
/* Whatever operation we have just performed, if no fatal error
* occurred we proceed to the next input record, if any, using the
* pointer we saved earlier, since `input->link' may not now be
* a valid reference; (`input' may have been `freed').
*/
input = next;
}
# ifdef DEBUG
if( cat )
{
struct msgdict *curr;
for( curr = cat; curr != NULL; curr = curr->link )
fprintf( stderr, "%s:%u: set %u message %u\n", curr->src, curr->lineno, curr->set, curr->msg );
}
# endif
/* When all input records have been processed,
* we return the resultant message catalogue index to the caller.
*/
return cat;
}
/* $RCSfile$Revision: 1.3 $: end of file */