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.
@@ -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
+ &section,
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
+ }