WPBDC 2013.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ext/WPBDC/WPBDC.c +237 -0
- data/ext/WPBDC/analysis.c +672 -0
- data/ext/WPBDC/bridge.c +288 -0
- data/ext/WPBDC/bridge_cost.c +60 -0
- data/ext/WPBDC/bridge_hash.c +126 -0
- data/ext/WPBDC/bridge_parser.c +1119 -0
- data/ext/WPBDC/bridge_random.c +292 -0
- data/ext/WPBDC/bridge_sketch.c +125 -0
- data/ext/WPBDC/extconf.rb +5 -0
- data/ext/WPBDC/geometry.c +46 -0
- data/ext/WPBDC/internal.h +518 -0
- data/ext/WPBDC/judge.c +563 -0
- data/ext/WPBDC/judge.h +142 -0
- data/ext/WPBDC/loading.c +128 -0
- data/ext/WPBDC/params.c +166 -0
- data/ext/WPBDC/proto.h +98 -0
- data/ext/WPBDC/rc4.c +62 -0
- data/ext/WPBDC/rc4.h +19 -0
- data/ext/WPBDC/rc4_key.c +2 -0
- data/ext/WPBDC/rubydefs.h +75 -0
- data/ext/WPBDC/scenario.c +671 -0
- data/ext/WPBDC/sketch.c +496 -0
- data/ext/WPBDC/sketch.h +51 -0
- data/ext/WPBDC/stdafx.h +11 -0
- data/lib/WPBDC.rb +9 -0
- metadata +71 -0
@@ -0,0 +1,1119 @@
|
|
1
|
+
/*
|
2
|
+
* bridge_parser.c -- Parsers and unparsers of various kinds
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "stdafx.h"
|
6
|
+
#include "internal.h"
|
7
|
+
#include "rc4.h"
|
8
|
+
|
9
|
+
// unadvertised global hack that allows rewriter to read other-year bridge files
|
10
|
+
unsigned contest_year = CONTEST_YEAR;
|
11
|
+
|
12
|
+
#define FILE_BANNER "West Point Bridge Designer 2004"
|
13
|
+
#define LOWEST_SCENARIO_NUMBER MinVariableScenario
|
14
|
+
#define HIGHEST_SCENARIO_NUMBER MaxVariableScenario
|
15
|
+
|
16
|
+
// Get a line by replacing \n in buffer with \0 and returning the line start.
|
17
|
+
// I.e. *buf is modified.
|
18
|
+
// Set a pointer 'next' to the start of next line, if there is one. Otherwise set it to NULL.
|
19
|
+
// Return start of line gotten.
|
20
|
+
// We take care of \r\n line terminators by setting _both_ the \r and \n to \0.
|
21
|
+
// If buffer is NULL or if line exceeds max length, both *next and the returned line
|
22
|
+
// pointer are set to NULL. Consequence of this convention is that you can ask for more
|
23
|
+
// than one line in a row without checking return
|
24
|
+
// value until the end:
|
25
|
+
// line_1 = get_line(buf, &next);
|
26
|
+
// line_2 = get_line(next, &next);
|
27
|
+
// line_3 = get_line(next, &next);
|
28
|
+
// if (!line_3) error(...)
|
29
|
+
char *get_line(char *buf, char **next)
|
30
|
+
{
|
31
|
+
char *p;
|
32
|
+
|
33
|
+
if (!buf) {
|
34
|
+
*next = NULL;
|
35
|
+
return NULL;
|
36
|
+
}
|
37
|
+
|
38
|
+
p = buf;
|
39
|
+
for (;;) {
|
40
|
+
|
41
|
+
if (p - buf >= MAX_LINE_LENGTH) {
|
42
|
+
*next = NULL;
|
43
|
+
return NULL;
|
44
|
+
}
|
45
|
+
if (*p == '\n' || *p == '\r') {
|
46
|
+
*p = '\0';
|
47
|
+
p++;
|
48
|
+
if (*p == '\n')
|
49
|
+
*p++ = '\0';
|
50
|
+
*next = p;
|
51
|
+
return buf;
|
52
|
+
}
|
53
|
+
if (*p == '\0') {
|
54
|
+
*next = NULL;
|
55
|
+
return buf;
|
56
|
+
}
|
57
|
+
|
58
|
+
p++;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
// Parse a string from buf and copy it to str without the surrounding quotes.
|
63
|
+
// Embedded repeated quotes become a single quote per Basic convention.
|
64
|
+
// On error (NULL buffer or unterminated string), returns NULL and sets str
|
65
|
+
// to the empty string. Return pointer to whatever follows with string.
|
66
|
+
char *parse_string(char *buf, char *str)
|
67
|
+
{
|
68
|
+
char *p = buf;
|
69
|
+
|
70
|
+
if (!p || *p != '"') {
|
71
|
+
*str = '\0';
|
72
|
+
return NULL;
|
73
|
+
}
|
74
|
+
|
75
|
+
// Skip past quote.
|
76
|
+
p++;
|
77
|
+
|
78
|
+
// Loop through all appearances of repeated quote.
|
79
|
+
for (;;) {
|
80
|
+
|
81
|
+
// Loop until next quote (or misplaced end of string).
|
82
|
+
for (;;) {
|
83
|
+
if (*p == '\0') {
|
84
|
+
*str = '\0';
|
85
|
+
return NULL;
|
86
|
+
}
|
87
|
+
if (*p == '"')
|
88
|
+
break;
|
89
|
+
*str++ = *p++;
|
90
|
+
}
|
91
|
+
|
92
|
+
// Skip matching quote.
|
93
|
+
p++;
|
94
|
+
|
95
|
+
// If next char is not a repeat quote, we're done.
|
96
|
+
if (*p != '"')
|
97
|
+
break;
|
98
|
+
|
99
|
+
// Handle repeat quote.
|
100
|
+
*str++ = '"';
|
101
|
+
p++;
|
102
|
+
}
|
103
|
+
|
104
|
+
*str = '\0';
|
105
|
+
return p;
|
106
|
+
}
|
107
|
+
|
108
|
+
// Convert given source string to Basic format at dst. This
|
109
|
+
// consists of putting "" around it and doubling any embedded "'s.
|
110
|
+
void basic_string (char *dst, char *src)
|
111
|
+
{
|
112
|
+
*dst++ = '\"';
|
113
|
+
while (*src)
|
114
|
+
if ((*dst++ = *src++) == '\"')
|
115
|
+
*dst++ = '\"';
|
116
|
+
*dst++ = '\"';
|
117
|
+
*dst = '\0';
|
118
|
+
}
|
119
|
+
|
120
|
+
// Check that next character is a comma and return pointer to whatever follows the comma.
|
121
|
+
// If comma is not found, return NULL.
|
122
|
+
char *parse_comma(char *buf)
|
123
|
+
{
|
124
|
+
if (!buf || *buf != ',')
|
125
|
+
return NULL;
|
126
|
+
return buf + 1;
|
127
|
+
}
|
128
|
+
|
129
|
+
// Get an unsigned value from the field of given width, possibly
|
130
|
+
// with leading but no trailing spaces. Return a pointer to the
|
131
|
+
// character following the field in next.
|
132
|
+
unsigned scan_unsigned(char *str, unsigned width, char **next)
|
133
|
+
{
|
134
|
+
unsigned val = 0;
|
135
|
+
|
136
|
+
if (!str) {
|
137
|
+
*next = 0;
|
138
|
+
return 0;
|
139
|
+
}
|
140
|
+
|
141
|
+
// Skip whitespace.
|
142
|
+
while (width > 0 && *str == ' ') {
|
143
|
+
width--;
|
144
|
+
str++;
|
145
|
+
}
|
146
|
+
while (width > 0) {
|
147
|
+
if ('0' <= *str && *str <= '9') {
|
148
|
+
val = val * 10 + (*str - '0');
|
149
|
+
width--;
|
150
|
+
str++;
|
151
|
+
}
|
152
|
+
else {
|
153
|
+
*next = 0;
|
154
|
+
return 0;
|
155
|
+
}
|
156
|
+
}
|
157
|
+
*next = str;
|
158
|
+
return val;
|
159
|
+
}
|
160
|
+
|
161
|
+
// Same as above, but allow for a negative sign.
|
162
|
+
int scan_int(char *str, unsigned width, char **next)
|
163
|
+
{
|
164
|
+
int val = 0;
|
165
|
+
TBool negate_p = False;
|
166
|
+
|
167
|
+
if (!str) {
|
168
|
+
*next = 0;
|
169
|
+
return 0;
|
170
|
+
}
|
171
|
+
|
172
|
+
// Skip whitespace.
|
173
|
+
while (width > 0 && *str == ' ') {
|
174
|
+
width--;
|
175
|
+
str++;
|
176
|
+
}
|
177
|
+
|
178
|
+
// Process negative sign, if present.
|
179
|
+
if (width >= 2 && *str == '-') {
|
180
|
+
width--;
|
181
|
+
str++;
|
182
|
+
negate_p = True;
|
183
|
+
}
|
184
|
+
|
185
|
+
while (width > 0) {
|
186
|
+
if ('0' <= *str && *str <= '9') {
|
187
|
+
val = val * 10 + (*str - '0');
|
188
|
+
width--;
|
189
|
+
str++;
|
190
|
+
}
|
191
|
+
else {
|
192
|
+
*next = 0;
|
193
|
+
return 0;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
*next = str;
|
197
|
+
return negate_p ? -val : val;
|
198
|
+
}
|
199
|
+
|
200
|
+
// Get a string fieldd of given width into a buffer with \0 termination.
|
201
|
+
void scan_field(char *buf, char *str, unsigned width, char **next)
|
202
|
+
{
|
203
|
+
char *p = buf;
|
204
|
+
|
205
|
+
if (!str) {
|
206
|
+
*next = 0;
|
207
|
+
return;
|
208
|
+
}
|
209
|
+
|
210
|
+
while (width > 0) {
|
211
|
+
if (*str == '\0') {
|
212
|
+
*next = 0;
|
213
|
+
buf[0] = '\0';
|
214
|
+
return;
|
215
|
+
}
|
216
|
+
width--;
|
217
|
+
*p++ = *str++;
|
218
|
+
}
|
219
|
+
*p = '\0';
|
220
|
+
*next = str;
|
221
|
+
}
|
222
|
+
|
223
|
+
// These are the status values we'll find in the V4+ bridge files.
|
224
|
+
static char *test_status_tag[] = {
|
225
|
+
"",
|
226
|
+
"\007",
|
227
|
+
"\011",
|
228
|
+
"\007\011",
|
229
|
+
};
|
230
|
+
|
231
|
+
// Return a TestStatus enumeration value given the corresponding
|
232
|
+
// code string from the V4+ bridge file.
|
233
|
+
TTestStatus lookup_test_status_tag(const char *str)
|
234
|
+
{
|
235
|
+
int i;
|
236
|
+
|
237
|
+
for (i = 0; i < STATIC_ARRAY_SIZE(test_status_tag); i++)
|
238
|
+
if (strcmp(str, test_status_tag[i]) == 0)
|
239
|
+
return (TTestStatus)i;
|
240
|
+
return NullTestStatus;
|
241
|
+
}
|
242
|
+
|
243
|
+
// Destructive: scan to next delimiter; replace with \0;
|
244
|
+
// return scanned string.
|
245
|
+
#define PACKED_DELIM "|"
|
246
|
+
|
247
|
+
char *get_to_delim(char *str, char **next)
|
248
|
+
{
|
249
|
+
char *p;
|
250
|
+
|
251
|
+
if (!str) {
|
252
|
+
*next = 0;
|
253
|
+
return 0;
|
254
|
+
}
|
255
|
+
for (p = str; *p; p++) {
|
256
|
+
if (*p == PACKED_DELIM[0]) {
|
257
|
+
*p++ = '\0';
|
258
|
+
*next = p;
|
259
|
+
return str;
|
260
|
+
}
|
261
|
+
}
|
262
|
+
*next = 0;
|
263
|
+
return str;
|
264
|
+
}
|
265
|
+
|
266
|
+
// Encrypt or decrpyt a buffer of given size. You can't use
|
267
|
+
// strlen to find size of an encrypted buffer!
|
268
|
+
void endecrypt_in_place(char *buf, int size)
|
269
|
+
{
|
270
|
+
TRC4State rc4[1];
|
271
|
+
|
272
|
+
init_rc4(rc4);
|
273
|
+
setup_rc4(rc4, RC4_Key, strlen(RC4_Key));
|
274
|
+
endecrypt_rc4(buf, size, rc4);
|
275
|
+
clear_rc4(rc4);
|
276
|
+
}
|
277
|
+
|
278
|
+
// Parse a long string to fill a bridge structure.
|
279
|
+
// Bridge structure must be set to known-empty by init_bridge.
|
280
|
+
// This allocates memory that can be reclaimed later with clear_bridge.
|
281
|
+
void parse_bridge(TBridge *bridge, STRING *str)
|
282
|
+
{
|
283
|
+
unsigned i, line_no;
|
284
|
+
unsigned char *mutable_copy, *p;
|
285
|
+
|
286
|
+
New(95, mutable_copy, str->size + 1, unsigned char);
|
287
|
+
memcpy(mutable_copy, str->ptr, str->size);
|
288
|
+
|
289
|
+
// Check for illegal characters.
|
290
|
+
for (line_no = 1, i = 0, p = mutable_copy; i < (unsigned)str->size; i++, p++) {
|
291
|
+
if (*p == '\0' || (128 <= *p && *p <= 159)) {
|
292
|
+
Safefree(mutable_copy);
|
293
|
+
clear_bridge(bridge);
|
294
|
+
|
295
|
+
#if defined(UNPACKED_BRIDGE_FILES)
|
296
|
+
bridge->error_line = line_no;
|
297
|
+
#else
|
298
|
+
bridge->error_line = i + 1; // character number
|
299
|
+
#endif
|
300
|
+
|
301
|
+
bridge->error = BridgeBadChar;
|
302
|
+
return;
|
303
|
+
}
|
304
|
+
if (*p == '\n')
|
305
|
+
line_no++;
|
306
|
+
}
|
307
|
+
*p = '\0';
|
308
|
+
|
309
|
+
#if defined(UNPACKED_BRIDGE_FILES)
|
310
|
+
parse_unpacked_bridge_destructive(bridge, mutable_copy);
|
311
|
+
#else
|
312
|
+
parse_packed_bridge_destructive(bridge, mutable_copy);
|
313
|
+
#endif
|
314
|
+
|
315
|
+
Safefree(mutable_copy);
|
316
|
+
}
|
317
|
+
|
318
|
+
// This parses the bridge string and munges it in the process.
|
319
|
+
void parse_unpacked_bridge_destructive(TBridge *bridge, char *str)
|
320
|
+
{
|
321
|
+
char buf[MAX_LINE_LENGTH + 1];
|
322
|
+
unsigned
|
323
|
+
n_design_iterations,
|
324
|
+
n_joints, n_members,
|
325
|
+
line_no,
|
326
|
+
start_line_no,
|
327
|
+
start_joint,
|
328
|
+
end_joint,
|
329
|
+
material,
|
330
|
+
section,
|
331
|
+
size,
|
332
|
+
joint_index,
|
333
|
+
member_index;
|
334
|
+
int x, y;
|
335
|
+
double label_pos;
|
336
|
+
char *line, *next;
|
337
|
+
|
338
|
+
clear_bridge(bridge);
|
339
|
+
|
340
|
+
// Line 1 - Banner
|
341
|
+
line_no = 1;
|
342
|
+
line = get_line(str, &str);
|
343
|
+
if (!line) {
|
344
|
+
clear_bridge(bridge);
|
345
|
+
bridge->error_line = line_no;
|
346
|
+
bridge->error = BridgeMissingData;
|
347
|
+
return;
|
348
|
+
}
|
349
|
+
next = parse_string(line, buf);
|
350
|
+
if (!next) {
|
351
|
+
clear_bridge(bridge);
|
352
|
+
bridge->error_line = line_no;
|
353
|
+
bridge->error = BridgeMissingHeader;
|
354
|
+
return;
|
355
|
+
}
|
356
|
+
|
357
|
+
// Vector to parser depending on version.
|
358
|
+
if (strcmp(buf, FILE_BANNER) != 0) {
|
359
|
+
// Couldn't match banner.
|
360
|
+
clear_bridge(bridge);
|
361
|
+
bridge->error_line = line_no;
|
362
|
+
bridge->error = BridgeBadHeader;
|
363
|
+
return;
|
364
|
+
}
|
365
|
+
|
366
|
+
// Version 4.00 or later contest derivative
|
367
|
+
bridge->version = BD_VERSION;
|
368
|
+
|
369
|
+
// Test status flag.
|
370
|
+
next = parse_comma(next);
|
371
|
+
next = parse_string(next, buf);
|
372
|
+
if (!next) {
|
373
|
+
clear_bridge(bridge);
|
374
|
+
bridge->error_line = line_no;
|
375
|
+
bridge->error = BridgeMissingTestStatus;
|
376
|
+
return;
|
377
|
+
}
|
378
|
+
|
379
|
+
if ((bridge->test_status = lookup_test_status_tag(buf)) == NullTestStatus) {
|
380
|
+
clear_bridge(bridge);
|
381
|
+
bridge->error_line = line_no;
|
382
|
+
bridge->error = BridgeBadTestStatus;
|
383
|
+
return;
|
384
|
+
}
|
385
|
+
|
386
|
+
// Line 2 - Scenario.
|
387
|
+
line_no++;
|
388
|
+
line = get_line(str, &str);
|
389
|
+
if (!line) {
|
390
|
+
clear_bridge(bridge);
|
391
|
+
bridge->error_line = line_no;
|
392
|
+
bridge->error = BridgeMissingData;
|
393
|
+
return;
|
394
|
+
}
|
395
|
+
if (lookup_scenario_descriptor(&bridge->scenario_descriptor, line) < 0) {
|
396
|
+
clear_bridge(bridge);
|
397
|
+
bridge->error_line = line_no;
|
398
|
+
bridge->error = BridgeBadScenario;
|
399
|
+
return;
|
400
|
+
}
|
401
|
+
|
402
|
+
// Fill in load scenario based on index.
|
403
|
+
setup_load_scenario(&bridge->load_scenario, &bridge->scenario_descriptor);
|
404
|
+
if (bridge->load_scenario.error != LoadScenarioNoError) {
|
405
|
+
clear_bridge(bridge);
|
406
|
+
bridge->error_line = line_no;
|
407
|
+
bridge->error = BridgeBadLoadScenario;
|
408
|
+
return;
|
409
|
+
}
|
410
|
+
|
411
|
+
// Line 3 - Designer/Project ID.
|
412
|
+
line_no++;
|
413
|
+
line = get_line(str, &str);
|
414
|
+
if (!line) {
|
415
|
+
clear_bridge(bridge);
|
416
|
+
bridge->error_line = line_no;
|
417
|
+
bridge->error = BridgeMissingData;
|
418
|
+
return;
|
419
|
+
}
|
420
|
+
next = parse_string(line, buf);
|
421
|
+
if (!next) {
|
422
|
+
clear_bridge(bridge);
|
423
|
+
bridge->error_line = line_no;
|
424
|
+
bridge->error = BridgeSyntax;
|
425
|
+
return;
|
426
|
+
}
|
427
|
+
|
428
|
+
NewStr(98, bridge->designer, buf);
|
429
|
+
next = parse_comma(next);
|
430
|
+
next = parse_string(next, buf);
|
431
|
+
if (!next) {
|
432
|
+
clear_bridge(bridge);
|
433
|
+
bridge->error_line = line_no;
|
434
|
+
bridge->error = BridgeSyntax;
|
435
|
+
return;
|
436
|
+
}
|
437
|
+
NewStr(99, bridge->project_id, buf);
|
438
|
+
|
439
|
+
// Line 4 - # design iterations.
|
440
|
+
line_no++;
|
441
|
+
line = get_line(str, &str);
|
442
|
+
if (!line) {
|
443
|
+
clear_bridge(bridge);
|
444
|
+
bridge->error_line = line_no;
|
445
|
+
bridge->error = BridgeMissingData;
|
446
|
+
return;
|
447
|
+
}
|
448
|
+
if (sscanf(line, "%u", &n_design_iterations) != 1) {
|
449
|
+
clear_bridge(bridge);
|
450
|
+
bridge->error_line = line_no;
|
451
|
+
bridge->error = BridgeBadNDesignIterations;
|
452
|
+
return;
|
453
|
+
}
|
454
|
+
bridge->n_design_iterations = n_design_iterations;
|
455
|
+
|
456
|
+
// Line 5 - # joints, # members
|
457
|
+
line_no++;
|
458
|
+
line = get_line(str, &str);
|
459
|
+
if (!line) {
|
460
|
+
clear_bridge(bridge);
|
461
|
+
bridge->error_line = line_no;
|
462
|
+
bridge->error = BridgeMissingData;
|
463
|
+
return;
|
464
|
+
}
|
465
|
+
if (sscanf(line, "%u,%u", &n_joints, &n_members) != 2) {
|
466
|
+
clear_bridge(bridge);
|
467
|
+
bridge->error_line = line_no;
|
468
|
+
bridge->error = BridgeMissingData;
|
469
|
+
return;
|
470
|
+
}
|
471
|
+
if (n_joints < 3) {
|
472
|
+
clear_bridge(bridge);
|
473
|
+
bridge->error_line = line_no;
|
474
|
+
bridge->error = BridgeTooFewJoints;
|
475
|
+
return;
|
476
|
+
}
|
477
|
+
if (n_members < 3) {
|
478
|
+
clear_bridge(bridge);
|
479
|
+
bridge->error_line = line_no;
|
480
|
+
bridge->error = BridgeTooFewMembers;
|
481
|
+
return;
|
482
|
+
}
|
483
|
+
if (n_joints > MAX_JOINTS ||
|
484
|
+
n_members > MAX_MEMBERS) {
|
485
|
+
clear_bridge(bridge);
|
486
|
+
bridge->error_line = line_no;
|
487
|
+
bridge->error = BridgeTooManyElements;
|
488
|
+
return;
|
489
|
+
}
|
490
|
+
bridge->n_joints = n_joints;
|
491
|
+
bridge->n_members = n_members;
|
492
|
+
|
493
|
+
// Joint array is 1-based for easy transposition of Basic code in analysis.
|
494
|
+
Newz(120, bridge->joints, n_joints + 1, TJoint);
|
495
|
+
joint_index = 1;
|
496
|
+
for (start_line_no = ++line_no; line_no < start_line_no + n_joints; line_no++) {
|
497
|
+
line = get_line(str, &str);
|
498
|
+
if (!line) {
|
499
|
+
clear_bridge(bridge);
|
500
|
+
bridge->error_line = line_no;
|
501
|
+
bridge->error = BridgeTooFewJoints;
|
502
|
+
return;
|
503
|
+
}
|
504
|
+
if (sscanf(line, "%d,%d", &x, &y) != 2) {
|
505
|
+
clear_bridge(bridge);
|
506
|
+
bridge->error_line = line_no;
|
507
|
+
bridge->error = BridgeSyntax;
|
508
|
+
return;
|
509
|
+
}
|
510
|
+
bridge->joints[joint_index].number = joint_index;
|
511
|
+
bridge->joints[joint_index].x = x;
|
512
|
+
bridge->joints[joint_index].y = y;
|
513
|
+
joint_index++;
|
514
|
+
}
|
515
|
+
|
516
|
+
if (n_joints < bridge->load_scenario.n_prescribed_joints ||
|
517
|
+
!joint_lists_eq(bridge->load_scenario.prescribed_joints,
|
518
|
+
&bridge->joints[1],
|
519
|
+
bridge->load_scenario.n_prescribed_joints)) {
|
520
|
+
clear_bridge(bridge);
|
521
|
+
bridge->error_line= line_no;
|
522
|
+
bridge->error = BridgeWrongPrescribedJoints;
|
523
|
+
return;
|
524
|
+
}
|
525
|
+
|
526
|
+
// Member array is 1-based for easy transposition of Basic code in analysis.
|
527
|
+
Newz(130, bridge->members, n_members + 1, TMember);
|
528
|
+
member_index = 1;
|
529
|
+
for (start_line_no = line_no; line_no < start_line_no + n_members; line_no++) {
|
530
|
+
line = get_line(str, &str);
|
531
|
+
if (!line) {
|
532
|
+
clear_bridge(bridge);
|
533
|
+
bridge->error_line = line_no;
|
534
|
+
bridge->error = BridgeTooFewMembers;
|
535
|
+
return;
|
536
|
+
}
|
537
|
+
if (sscanf(line, "%u,%u,%u,%u,%u,%s",
|
538
|
+
&start_joint,
|
539
|
+
&end_joint,
|
540
|
+
&material,
|
541
|
+
§ion,
|
542
|
+
&size,
|
543
|
+
buf) != 6 || // Buffer gets tension and compression test strings.
|
544
|
+
start_joint > n_joints ||
|
545
|
+
end_joint > n_joints ||
|
546
|
+
start_joint == end_joint ||
|
547
|
+
material >= NMaterials ||
|
548
|
+
section >= NSections ||
|
549
|
+
size >= n_sizes(section)) {
|
550
|
+
|
551
|
+
clear_bridge(bridge);
|
552
|
+
bridge->error_line = line_no;
|
553
|
+
bridge->error = BridgeSyntax;
|
554
|
+
return;
|
555
|
+
}
|
556
|
+
|
557
|
+
bridge->members[member_index].number = member_index;
|
558
|
+
bridge->members[member_index].start_joint = start_joint;
|
559
|
+
bridge->members[member_index].end_joint = end_joint;
|
560
|
+
bridge->members[member_index].x_section.material = material;
|
561
|
+
bridge->members[member_index].x_section.section = section;
|
562
|
+
bridge->members[member_index].x_section.size = size;
|
563
|
+
|
564
|
+
// Move the force strings into the line buffer for parsing.
|
565
|
+
strcpy(line, buf);
|
566
|
+
next = parse_string(line, buf);
|
567
|
+
if (!next ||
|
568
|
+
strlen(buf) >= FORCE_STR_SIZE ||
|
569
|
+
strchr(buf, '"')) { // Embedded quote is illegal and would unparse with bad syntax.
|
570
|
+
clear_bridge(bridge);
|
571
|
+
bridge->error_line = line_no;
|
572
|
+
bridge->error = BridgeSyntax;
|
573
|
+
return;
|
574
|
+
}
|
575
|
+
strcpy(bridge->members[member_index].compression, buf);
|
576
|
+
|
577
|
+
next = parse_comma(next);
|
578
|
+
|
579
|
+
next = parse_string(next, buf);
|
580
|
+
if (!next ||
|
581
|
+
strlen(buf) >= FORCE_STR_SIZE ||
|
582
|
+
strchr(buf, '"')) { // Embedded quote is illegal and would unparse with bad syntax.
|
583
|
+
clear_bridge(bridge);
|
584
|
+
bridge->error_line = line_no;
|
585
|
+
bridge->error = BridgeSyntax;
|
586
|
+
return;
|
587
|
+
}
|
588
|
+
strcpy(bridge->members[member_index].tension, buf);
|
589
|
+
|
590
|
+
member_index++;
|
591
|
+
}
|
592
|
+
|
593
|
+
// Next Line - Label position
|
594
|
+
line = get_line(str, &str);
|
595
|
+
if (!line) {
|
596
|
+
clear_bridge(bridge);
|
597
|
+
bridge->error_line = line_no;
|
598
|
+
bridge->error = BridgeMissingData;
|
599
|
+
return;
|
600
|
+
}
|
601
|
+
|
602
|
+
if (sscanf(line, "%lf", &label_pos) != 1) {
|
603
|
+
clear_bridge(bridge);
|
604
|
+
bridge->error_line = line_no;
|
605
|
+
bridge->error = BridgeBadLabelPos;
|
606
|
+
return;
|
607
|
+
}
|
608
|
+
bridge->label_pos = label_pos;
|
609
|
+
|
610
|
+
// EOF
|
611
|
+
line_no++;
|
612
|
+
line = get_line(str, &str);
|
613
|
+
if ( (line && *line != '\0') || str ) {
|
614
|
+
clear_bridge(bridge);
|
615
|
+
bridge->error_line = line_no;
|
616
|
+
bridge->error = BridgeExtraJunk;
|
617
|
+
return;
|
618
|
+
}
|
619
|
+
}
|
620
|
+
|
621
|
+
#define YEAR_LEN 4
|
622
|
+
#define SCENARIO_CODE_LEN 10
|
623
|
+
#define N_JOINTS_LEN 2
|
624
|
+
#define N_MEMBERS_LEN 3
|
625
|
+
#define JOINT_COORD_LEN 3
|
626
|
+
#define MEMBER_JOINT_LEN 2
|
627
|
+
#define MEMBER_MATERIAL_LEN 1
|
628
|
+
#define MEMBER_SECTION_LEN 1
|
629
|
+
#define MEMBER_SIZE_LEN 2
|
630
|
+
#define MAX_TOKEN_LEN 10
|
631
|
+
|
632
|
+
// This parses the bridge string and munges it in the process.
|
633
|
+
void parse_packed_bridge_destructive(TBridge *bridge, char *str)
|
634
|
+
{
|
635
|
+
unsigned
|
636
|
+
year,
|
637
|
+
n_design_iterations,
|
638
|
+
n_joints, n_members,
|
639
|
+
start_joint,
|
640
|
+
end_joint,
|
641
|
+
material,
|
642
|
+
section,
|
643
|
+
size,
|
644
|
+
joint_index,
|
645
|
+
member_index;
|
646
|
+
int x, y;
|
647
|
+
char
|
648
|
+
*next,
|
649
|
+
*mark,
|
650
|
+
*compression,
|
651
|
+
*tension,
|
652
|
+
*field;
|
653
|
+
double label_pos;
|
654
|
+
|
655
|
+
clear_bridge(bridge);
|
656
|
+
|
657
|
+
// Version 4.00 or later contest derivative
|
658
|
+
bridge->version = BD_VERSION;
|
659
|
+
|
660
|
+
// Packed format doesn't include test status.
|
661
|
+
bridge->test_status = Unrecorded;
|
662
|
+
|
663
|
+
// Field 1: Year of contest.
|
664
|
+
mark = str;
|
665
|
+
year = scan_unsigned(str, YEAR_LEN, &next);
|
666
|
+
if (!next || year != contest_year) {
|
667
|
+
clear_bridge(bridge);
|
668
|
+
bridge->error_line = (mark - str) + 1;
|
669
|
+
bridge->error = BridgeBadHeader;
|
670
|
+
return;
|
671
|
+
}
|
672
|
+
|
673
|
+
// Field 2: Scenario id.
|
674
|
+
mark = next;
|
675
|
+
if (lookup_scenario_descriptor(&bridge->scenario_descriptor, next) < 0) {
|
676
|
+
clear_bridge(bridge);
|
677
|
+
bridge->error_line = (mark - str) + 1;
|
678
|
+
bridge->error = BridgeBadScenario;
|
679
|
+
return;
|
680
|
+
}
|
681
|
+
next += SCENARIO_ID_SIZE;
|
682
|
+
|
683
|
+
// Fill in load scenario based on index.
|
684
|
+
setup_load_scenario(&bridge->load_scenario, &bridge->scenario_descriptor);
|
685
|
+
if (bridge->load_scenario.error != LoadScenarioNoError) {
|
686
|
+
clear_bridge(bridge);
|
687
|
+
bridge->error_line = (mark - str) + 1;
|
688
|
+
bridge->error = BridgeBadLoadScenario;
|
689
|
+
return;
|
690
|
+
}
|
691
|
+
|
692
|
+
// Field 3 - # joints, # members
|
693
|
+
mark = next;
|
694
|
+
n_joints = scan_unsigned(next, N_JOINTS_LEN, &next);
|
695
|
+
n_members = scan_unsigned(next, N_MEMBERS_LEN, &next);
|
696
|
+
if (!next) {
|
697
|
+
clear_bridge(bridge);
|
698
|
+
bridge->error_line = (mark - str) + 1;
|
699
|
+
bridge->error = BridgeMissingData;
|
700
|
+
return;
|
701
|
+
}
|
702
|
+
if (n_joints < 3) {
|
703
|
+
clear_bridge(bridge);
|
704
|
+
bridge->error_line = (mark - str) + 1;
|
705
|
+
bridge->error = BridgeTooFewJoints;
|
706
|
+
return;
|
707
|
+
}
|
708
|
+
if (n_members < 3) {
|
709
|
+
clear_bridge(bridge);
|
710
|
+
bridge->error_line = (mark - str) + 1;
|
711
|
+
bridge->error = BridgeTooFewMembers;
|
712
|
+
return;
|
713
|
+
}
|
714
|
+
if (n_joints > MAX_JOINTS ||
|
715
|
+
n_members > MAX_MEMBERS) {
|
716
|
+
clear_bridge(bridge);
|
717
|
+
bridge->error_line = (mark - str) + 1;
|
718
|
+
bridge->error = BridgeTooManyElements;
|
719
|
+
return;
|
720
|
+
}
|
721
|
+
bridge->n_joints = n_joints;
|
722
|
+
bridge->n_members = n_members;
|
723
|
+
|
724
|
+
// Fields 4 through 4 + n_joints - 1: Joint coordinates
|
725
|
+
// Joint array is 1-based for easy transposition of Basic code in analysis.
|
726
|
+
Newz(120, bridge->joints, n_joints + 1, TJoint);
|
727
|
+
for (joint_index = 1; joint_index <= n_joints; joint_index++) {
|
728
|
+
mark = next;
|
729
|
+
x = scan_int(next, JOINT_COORD_LEN, &next);
|
730
|
+
y = scan_int(next, JOINT_COORD_LEN, &next);
|
731
|
+
if (!next) {
|
732
|
+
clear_bridge(bridge);
|
733
|
+
bridge->error_line = (mark - str) + 1;
|
734
|
+
bridge->error = BridgeSyntax;
|
735
|
+
return;
|
736
|
+
}
|
737
|
+
bridge->joints[joint_index].number = joint_index;
|
738
|
+
bridge->joints[joint_index].x = x;
|
739
|
+
bridge->joints[joint_index].y = y;
|
740
|
+
}
|
741
|
+
|
742
|
+
// Verify that prescribed joints are where they should be.
|
743
|
+
if (n_joints < bridge->load_scenario.n_prescribed_joints ||
|
744
|
+
!joint_lists_eq(bridge->load_scenario.prescribed_joints,
|
745
|
+
&bridge->joints[1],
|
746
|
+
bridge->load_scenario.n_prescribed_joints)) {
|
747
|
+
clear_bridge(bridge);
|
748
|
+
bridge->error_line= (mark - str) + 1;
|
749
|
+
bridge->error = BridgeWrongPrescribedJoints;
|
750
|
+
return;
|
751
|
+
}
|
752
|
+
|
753
|
+
// Member array is 1-based for easy transposition of Basic code in analysis.
|
754
|
+
Newz(130, bridge->members, n_members + 1, TMember);
|
755
|
+
for (member_index = 1; member_index <= n_members; member_index++) {
|
756
|
+
mark = next;
|
757
|
+
start_joint = scan_unsigned(next, MEMBER_JOINT_LEN, &next);
|
758
|
+
end_joint = scan_unsigned(next, MEMBER_JOINT_LEN, &next);
|
759
|
+
material = scan_unsigned(next, MEMBER_MATERIAL_LEN, &next);
|
760
|
+
section = scan_unsigned(next, MEMBER_SECTION_LEN, &next);
|
761
|
+
size = scan_unsigned(next, MEMBER_SIZE_LEN, &next);
|
762
|
+
if (!next ||
|
763
|
+
start_joint > n_joints ||
|
764
|
+
end_joint > n_joints ||
|
765
|
+
start_joint == end_joint ||
|
766
|
+
material >= NMaterials ||
|
767
|
+
section >= NSections ||
|
768
|
+
size >= n_sizes(section)) {
|
769
|
+
|
770
|
+
clear_bridge(bridge);
|
771
|
+
bridge->error_line = (mark - str) + 1;
|
772
|
+
bridge->error = BridgeSyntax;
|
773
|
+
return;
|
774
|
+
}
|
775
|
+
bridge->members[member_index].number = member_index;
|
776
|
+
bridge->members[member_index].start_joint = start_joint;
|
777
|
+
bridge->members[member_index].end_joint = end_joint;
|
778
|
+
bridge->members[member_index].x_section.material = material;
|
779
|
+
bridge->members[member_index].x_section.section = section;
|
780
|
+
bridge->members[member_index].x_section.size = size;
|
781
|
+
}
|
782
|
+
|
783
|
+
for (member_index = 1; member_index <= n_members; member_index++) {
|
784
|
+
mark = next;
|
785
|
+
compression = get_to_delim(next, &next);
|
786
|
+
tension = get_to_delim(next, &next);
|
787
|
+
if (!next ||
|
788
|
+
strlen(compression) >= FORCE_STR_SIZE ||
|
789
|
+
strlen(tension) >= FORCE_STR_SIZE) {
|
790
|
+
|
791
|
+
clear_bridge(bridge);
|
792
|
+
bridge->error_line = (mark - str) + 1;
|
793
|
+
bridge->error = BridgeSyntax;
|
794
|
+
return;
|
795
|
+
}
|
796
|
+
strcpy(bridge->members[member_index].compression, compression);
|
797
|
+
strcpy(bridge->members[member_index].tension, tension);
|
798
|
+
}
|
799
|
+
|
800
|
+
// Designer
|
801
|
+
mark = next;
|
802
|
+
field = get_to_delim(next, &next);
|
803
|
+
if (!next || field - mark > MAX_LINE_LENGTH) {
|
804
|
+
clear_bridge(bridge);
|
805
|
+
bridge->error_line = (mark - str) + 1;
|
806
|
+
bridge->error = BridgeSyntax;
|
807
|
+
return;
|
808
|
+
}
|
809
|
+
NewStr(98, bridge->designer, field);
|
810
|
+
|
811
|
+
// Project ID
|
812
|
+
mark = next;
|
813
|
+
field = get_to_delim(next, &next);
|
814
|
+
if (!next || field - mark > MAX_LINE_LENGTH) {
|
815
|
+
clear_bridge(bridge);
|
816
|
+
bridge->error_line = (mark - str) + 1;
|
817
|
+
bridge->error = BridgeSyntax;
|
818
|
+
return;
|
819
|
+
}
|
820
|
+
NewStr(99, bridge->project_id, field);
|
821
|
+
|
822
|
+
// Design iteration
|
823
|
+
mark = next;
|
824
|
+
field = get_to_delim(next, &next);
|
825
|
+
if (!next ||
|
826
|
+
field - mark > MAX_LINE_LENGTH ||
|
827
|
+
sscanf(field, "%u", &n_design_iterations) != 1) {
|
828
|
+
|
829
|
+
clear_bridge(bridge);
|
830
|
+
bridge->error_line = (mark - str) + 1;
|
831
|
+
bridge->error = BridgeSyntax;
|
832
|
+
return;
|
833
|
+
}
|
834
|
+
bridge->n_design_iterations = n_design_iterations;
|
835
|
+
|
836
|
+
// Label position.
|
837
|
+
mark = next;
|
838
|
+
field = get_to_delim(next, &next);
|
839
|
+
if (!next ||
|
840
|
+
sscanf(field, "%lf", &label_pos) != 1) {
|
841
|
+
|
842
|
+
clear_bridge(bridge);
|
843
|
+
bridge->error_line = (mark - str) + 1;
|
844
|
+
bridge->error = BridgeSyntax;
|
845
|
+
return;
|
846
|
+
}
|
847
|
+
bridge->label_pos = label_pos;
|
848
|
+
|
849
|
+
// Scan once more for end of string. Allow a CRLF for
|
850
|
+
// editing test data during debugging,
|
851
|
+
mark = next;
|
852
|
+
if (next[0] && next[1] && next[2]) {
|
853
|
+
clear_bridge(bridge);
|
854
|
+
bridge->error_line = (mark - str) + 1;
|
855
|
+
bridge->error = BridgeExtraJunk;
|
856
|
+
return;
|
857
|
+
}
|
858
|
+
}
|
859
|
+
|
860
|
+
char *unparse_bridge(TBridge *bridge)
|
861
|
+
{
|
862
|
+
#if defined(UNPACKED_BRIDGE_FILES)
|
863
|
+
return unparse_unpacked_bridge(bridge);
|
864
|
+
#else
|
865
|
+
return unparse_packed_bridge(bridge);
|
866
|
+
#endif
|
867
|
+
}
|
868
|
+
|
869
|
+
// Turns bridge back into a string. String is allocated
|
870
|
+
// with "malloc". Must be freed by caller. With the possible
|
871
|
+
// exception of the last line (floating point label height),
|
872
|
+
// this ought to exactly invert parse_packed_bridge above.
|
873
|
+
char *unparse_packed_bridge(TBridge *bridge)
|
874
|
+
{
|
875
|
+
size_t rtn_size = 1024 * 8;
|
876
|
+
char *rtn, *p;
|
877
|
+
char buf[MAX_LINE_LENGTH + 1];
|
878
|
+
unsigned joint_index, member_index;
|
879
|
+
|
880
|
+
if (bridge->error != BridgeNoError)
|
881
|
+
return 0;
|
882
|
+
|
883
|
+
// Allocate an initial return buffer.
|
884
|
+
New(140, rtn, rtn_size, char);
|
885
|
+
p = rtn;
|
886
|
+
|
887
|
+
#define Append(S) do { \
|
888
|
+
char *q = (S); \
|
889
|
+
while ((*p = *q++) != 0) \
|
890
|
+
if (++p >= rtn + rtn_size) { \
|
891
|
+
unsigned p_ofs = p - rtn; \
|
892
|
+
rtn_size *= 2; \
|
893
|
+
Renew(rtn, rtn_size, char); \
|
894
|
+
p = rtn + p_ofs; \
|
895
|
+
} \
|
896
|
+
} while (0)
|
897
|
+
|
898
|
+
// Year
|
899
|
+
sprintf(buf, "%u", contest_year);
|
900
|
+
Append(buf);
|
901
|
+
|
902
|
+
// Scenario ID.
|
903
|
+
Append(bridge->scenario_descriptor.id);
|
904
|
+
|
905
|
+
// Numbers of joints and members.
|
906
|
+
sprintf(buf,
|
907
|
+
"%" STR(N_JOINTS_LEN) "u"
|
908
|
+
"%" STR(N_MEMBERS_LEN) "u",
|
909
|
+
bridge->n_joints,
|
910
|
+
bridge->n_members);
|
911
|
+
Append(buf);
|
912
|
+
|
913
|
+
// Joint coordinates.
|
914
|
+
for (joint_index = 1; joint_index <= bridge->n_joints; joint_index++) {
|
915
|
+
sprintf(buf,
|
916
|
+
"%" STR(JOINT_COORD_LEN) "d"
|
917
|
+
"%" STR(JOINT_COORD_LEN) "d",
|
918
|
+
bridge->joints[joint_index].x,
|
919
|
+
bridge->joints[joint_index].y);
|
920
|
+
Append(buf);
|
921
|
+
}
|
922
|
+
|
923
|
+
// Members data.
|
924
|
+
for (member_index = 1; member_index <= bridge->n_members; member_index++) {
|
925
|
+
sprintf(buf,
|
926
|
+
"%" STR(MEMBER_JOINT_LEN) "d"
|
927
|
+
"%" STR(MEMBER_JOINT_LEN) "d"
|
928
|
+
"%" STR(MEMBER_MATERIAL_LEN) "d"
|
929
|
+
"%" STR(MEMBER_SECTION_LEN) "d"
|
930
|
+
"%" STR(MEMBER_SIZE_LEN) "d",
|
931
|
+
bridge->members[member_index].start_joint,
|
932
|
+
bridge->members[member_index].end_joint,
|
933
|
+
bridge->members[member_index].x_section.material,
|
934
|
+
bridge->members[member_index].x_section.section,
|
935
|
+
bridge->members[member_index].x_section.size);
|
936
|
+
Append(buf);
|
937
|
+
}
|
938
|
+
|
939
|
+
// Variable length data.
|
940
|
+
|
941
|
+
// Most recent member forces.
|
942
|
+
for (member_index = 1; member_index <= bridge->n_members; member_index++) {
|
943
|
+
sprintf(buf, "%s" PACKED_DELIM "%s" PACKED_DELIM,
|
944
|
+
bridge->members[member_index].compression,
|
945
|
+
bridge->members[member_index].tension);
|
946
|
+
Append(buf);
|
947
|
+
}
|
948
|
+
|
949
|
+
// Designer.
|
950
|
+
Append(bridge->designer);
|
951
|
+
Append(PACKED_DELIM);
|
952
|
+
|
953
|
+
// Project ID
|
954
|
+
Append(bridge->project_id);
|
955
|
+
Append(PACKED_DELIM);
|
956
|
+
|
957
|
+
// # Design iterations.
|
958
|
+
sprintf(buf, "%u" PACKED_DELIM, bridge->n_design_iterations);
|
959
|
+
Append(buf);
|
960
|
+
|
961
|
+
// Label position
|
962
|
+
sprintf(buf, "%.7lg" PACKED_DELIM, bridge->label_pos);
|
963
|
+
Append(buf);
|
964
|
+
|
965
|
+
// Return the buffer. Could trim with realloc here.
|
966
|
+
return rtn;
|
967
|
+
|
968
|
+
#undef Append
|
969
|
+
}
|
970
|
+
|
971
|
+
// Turns bridge back into a packed string. String is allocated
|
972
|
+
// with "malloc". Must be freed by caller. With the possible
|
973
|
+
// exception of the last line (floating point label height),
|
974
|
+
// this ought to exactly invert parse_bridge above.
|
975
|
+
char *unparse_unpacked_bridge(TBridge *bridge)
|
976
|
+
{
|
977
|
+
size_t rtn_size = 1024 * 8;
|
978
|
+
char *rtn, *p;
|
979
|
+
char buf[MAX_LINE_LENGTH + 1];
|
980
|
+
unsigned joint_index, member_index;
|
981
|
+
|
982
|
+
if (bridge->error != BridgeNoError)
|
983
|
+
return 0;
|
984
|
+
|
985
|
+
// Allocate an initial return buffer.
|
986
|
+
New(140, rtn, rtn_size, char);
|
987
|
+
p = rtn;
|
988
|
+
|
989
|
+
#define Append(S) do { \
|
990
|
+
char *q = (S); \
|
991
|
+
while ((*p = *q++) != 0) \
|
992
|
+
if (++p >= rtn + rtn_size) { \
|
993
|
+
unsigned p_ofs = p - rtn; \
|
994
|
+
rtn_size *= 2; \
|
995
|
+
Renew(rtn, rtn_size, char); \
|
996
|
+
p = rtn + p_ofs; \
|
997
|
+
} \
|
998
|
+
} while (0)
|
999
|
+
|
1000
|
+
// Line 1 - Banner
|
1001
|
+
basic_string(buf, FILE_BANNER);
|
1002
|
+
Append(buf);
|
1003
|
+
Append(",\"");
|
1004
|
+
Append(test_status_tag[bridge->test_status]);
|
1005
|
+
Append("\"\n");
|
1006
|
+
|
1007
|
+
// Line 2 - Scenario.
|
1008
|
+
Append(bridge->scenario_descriptor.id);
|
1009
|
+
|
1010
|
+
// Line 3 - Designer/Project ID.
|
1011
|
+
basic_string(buf, bridge->designer);
|
1012
|
+
Append(buf);
|
1013
|
+
Append(",");
|
1014
|
+
basic_string(buf, bridge->project_id);
|
1015
|
+
Append(buf);
|
1016
|
+
Append("\n");
|
1017
|
+
|
1018
|
+
// Line 4 - # design iterations.
|
1019
|
+
sprintf(buf, "%u\n", bridge->n_design_iterations);
|
1020
|
+
Append(buf);
|
1021
|
+
|
1022
|
+
// Line 5 - # joints, # members
|
1023
|
+
sprintf(buf, "%u,%u\n", bridge->n_joints, bridge->n_members);
|
1024
|
+
Append(buf);
|
1025
|
+
|
1026
|
+
// Joint array is 1-based for easy transposition of Basic code in analysis.
|
1027
|
+
for (joint_index = 1; joint_index <= bridge->n_joints; joint_index++) {
|
1028
|
+
sprintf(buf, "%d,%d\n",
|
1029
|
+
bridge->joints[joint_index].x,
|
1030
|
+
bridge->joints[joint_index].y);
|
1031
|
+
Append(buf);
|
1032
|
+
}
|
1033
|
+
|
1034
|
+
// Member array is 1-based for easy transposition of Basic code in analysis.
|
1035
|
+
for (member_index = 1; member_index <= bridge->n_members; member_index++) {
|
1036
|
+
sprintf(buf, "%u,%u,%u,%u,%u,\"%s\",\"%s\"\n",
|
1037
|
+
bridge->members[member_index].start_joint,
|
1038
|
+
bridge->members[member_index].end_joint,
|
1039
|
+
bridge->members[member_index].x_section.material,
|
1040
|
+
bridge->members[member_index].x_section.section,
|
1041
|
+
bridge->members[member_index].x_section.size,
|
1042
|
+
bridge->members[member_index].compression,
|
1043
|
+
bridge->members[member_index].tension);
|
1044
|
+
Append(buf);
|
1045
|
+
}
|
1046
|
+
|
1047
|
+
// Next Line - Label position
|
1048
|
+
sprintf(buf, "%.7lg\n", bridge->label_pos);
|
1049
|
+
Append(buf);
|
1050
|
+
|
1051
|
+
// Return the buffer. Could trim with realloc here.
|
1052
|
+
return rtn;
|
1053
|
+
|
1054
|
+
#undef Append
|
1055
|
+
}
|
1056
|
+
|
1057
|
+
void pack_bridge(STRING *in_str, STRING *out_str,
|
1058
|
+
TBool decrypt_p, TBool encrypt_p)
|
1059
|
+
{
|
1060
|
+
TBridge bridge[1];
|
1061
|
+
char *mutable_copy;
|
1062
|
+
char *rtn = 0;
|
1063
|
+
|
1064
|
+
init_bridge(bridge);
|
1065
|
+
|
1066
|
+
New(97, mutable_copy, in_str->size + 1, char);
|
1067
|
+
memcpy(mutable_copy, in_str->ptr, in_str->size);
|
1068
|
+
mutable_copy[in_str->size] = '\0';
|
1069
|
+
|
1070
|
+
if (decrypt_p)
|
1071
|
+
endecrypt_in_place(mutable_copy, in_str->size);
|
1072
|
+
|
1073
|
+
parse_unpacked_bridge_destructive(bridge, mutable_copy);
|
1074
|
+
Safefree(mutable_copy);
|
1075
|
+
if (bridge->error == BridgeNoError) {
|
1076
|
+
out_str->ptr = unparse_packed_bridge(bridge);
|
1077
|
+
out_str->size = strlen(out_str->ptr);
|
1078
|
+
if (encrypt_p)
|
1079
|
+
endecrypt_in_place(out_str->ptr, out_str->size);
|
1080
|
+
}
|
1081
|
+
else {
|
1082
|
+
out_str->ptr = 0;
|
1083
|
+
out_str->size = 0;
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
clear_bridge(bridge);
|
1087
|
+
}
|
1088
|
+
|
1089
|
+
void unpack_bridge(STRING *in_str, STRING *out_str,
|
1090
|
+
TBool decrypt_p, TBool encrypt_p)
|
1091
|
+
{
|
1092
|
+
TBridge bridge[1];
|
1093
|
+
char *mutable_copy;
|
1094
|
+
char *rtn = 0;
|
1095
|
+
|
1096
|
+
init_bridge(bridge);
|
1097
|
+
|
1098
|
+
New(97, mutable_copy, in_str->size + 1, char);
|
1099
|
+
memcpy(mutable_copy, in_str->ptr, in_str->size);
|
1100
|
+
mutable_copy[in_str->size] = '\0';
|
1101
|
+
|
1102
|
+
if (decrypt_p)
|
1103
|
+
endecrypt_in_place(mutable_copy, in_str->size);
|
1104
|
+
|
1105
|
+
parse_packed_bridge_destructive(bridge, mutable_copy);
|
1106
|
+
Safefree(mutable_copy);
|
1107
|
+
if (bridge->error == BridgeNoError) {
|
1108
|
+
out_str->ptr = unparse_bridge(bridge);
|
1109
|
+
out_str->size = strlen(out_str->ptr);
|
1110
|
+
if (encrypt_p)
|
1111
|
+
endecrypt_in_place(out_str->ptr, out_str->size);
|
1112
|
+
}
|
1113
|
+
else {
|
1114
|
+
out_str->ptr = 0;
|
1115
|
+
out_str->size = 0;
|
1116
|
+
}
|
1117
|
+
|
1118
|
+
clear_bridge(bridge);
|
1119
|
+
}
|