naev 0.11.5
unidiff.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
14#include <stdlib.h>
15
16#include "naev.h"
19#include "unidiff.h"
20
21#include "conf.h"
22#include "array.h"
23#include "economy.h"
24#include "log.h"
25#include "map_overlay.h"
26#include "ndata.h"
27#include "nstring.h"
28#include "nxml.h"
29#include "safelanes.h"
30#include "space.h"
31#include "player.h"
32
36typedef struct UniDiffData_ {
37 char *name;
38 char *filename;
47typedef enum UniHunkTargetType_ {
48 HUNK_TARGET_NONE,
49 HUNK_TARGET_SYSTEM,
50 HUNK_TARGET_SPOB,
51 HUNK_TARGET_TECH,
52 HUNK_TARGET_FACTION,
54
60typedef struct UniHunkTarget_ {
62 union {
63 char *name;
64 } u;
66
72typedef enum UniHunkType_ {
73 HUNK_TYPE_NONE,
74 /* Target should be system. */
75 HUNK_TYPE_SPOB_ADD,
76 HUNK_TYPE_SPOB_REMOVE,
77 HUNK_TYPE_VSPOB_ADD,
78 HUNK_TYPE_VSPOB_REMOVE,
79 HUNK_TYPE_JUMP_ADD,
80 HUNK_TYPE_JUMP_REMOVE,
81 HUNK_TYPE_SSYS_BACKGROUND,
82 HUNK_TYPE_SSYS_BACKGROUND_REVERT, /* For internal usage. */
83 HUNK_TYPE_SSYS_FEATURES,
84 HUNK_TYPE_SSYS_FEATURES_REVERT, /* For internal usage. */
85 /* Target should be tech. */
86 HUNK_TYPE_TECH_ADD,
87 HUNK_TYPE_TECH_REMOVE,
88 /* Target should be spob. */
89 HUNK_TYPE_SPOB_FACTION,
90 HUNK_TYPE_SPOB_FACTION_REMOVE, /* For internal usage. */
91 HUNK_TYPE_SPOB_POPULATION,
92 HUNK_TYPE_SPOB_POPULATION_REMOVE, /* For internal usage. */
93 HUNK_TYPE_SPOB_DISPLAYNAME,
94 HUNK_TYPE_SPOB_DISPLAYNAME_REVERT, /* For internal usage. */
95 HUNK_TYPE_SPOB_DESCRIPTION,
96 HUNK_TYPE_SPOB_DESCRIPTION_REVERT, /* For internal usage. */
97 HUNK_TYPE_SPOB_BAR,
98 HUNK_TYPE_SPOB_BAR_REVERT, /* For internal usage. */
99 HUNK_TYPE_SPOB_SERVICE_ADD,
100 HUNK_TYPE_SPOB_SERVICE_REMOVE,
101 HUNK_TYPE_SPOB_NOMISNSPAWN_ADD,
102 HUNK_TYPE_SPOB_NOMISNSPAWN_REMOVE,
103 HUNK_TYPE_SPOB_TECH_ADD,
104 HUNK_TYPE_SPOB_TECH_REMOVE,
105 HUNK_TYPE_SPOB_TAG_ADD,
106 HUNK_TYPE_SPOB_TAG_REMOVE,
107 HUNK_TYPE_SPOB_SPACE,
108 HUNK_TYPE_SPOB_SPACE_REVERT, /* For internal usage. */
109 HUNK_TYPE_SPOB_EXTERIOR,
110 HUNK_TYPE_SPOB_EXTERIOR_REVERT, /* For internal usage. */
111 HUNK_TYPE_SPOB_LUA,
112 HUNK_TYPE_SPOB_LUA_REVERT, /* For internal usage. */
113 /* Target should be faction. */
114 HUNK_TYPE_FACTION_VISIBLE,
115 HUNK_TYPE_FACTION_INVISIBLE,
116 HUNK_TYPE_FACTION_ALLY,
117 HUNK_TYPE_FACTION_ENEMY,
118 HUNK_TYPE_FACTION_NEUTRAL,
119 HUNK_TYPE_FACTION_REALIGN, /* For internal usage. */
121
127typedef struct UniHunk_ {
131 xmlNodePtr node;
132 union {
133 char *name;
134 int data;
135 } u;
136 union {
137 const char *name; /* We just save the pointer, so keep as const. */
138 int data;
139 } o;
140} UniHunk_t;
141
147typedef struct UniDiff_ {
148 char *name;
151} UniDiff_t;
152
153/*
154 * Diff stack.
155 */
156static UniDiff_t *diff_stack = NULL;
158/* Useful variables. */
159static int diff_universe_changed = 0;
160static int diff_universe_defer = 0;
162/*
163 * Prototypes.
164 */
165static int diff_applyInternal( const char *name, int oneshot );
166NONNULL( 1 ) static UniDiff_t *diff_get( const char *name );
167static UniDiff_t *diff_newDiff (void);
168static int diff_removeDiff( UniDiff_t *diff );
169static int diff_patchSystem( UniDiff_t *diff, xmlNodePtr node );
170static int diff_patchTech( UniDiff_t *diff, xmlNodePtr node );
171static int diff_patch( xmlNodePtr parent );
172static int diff_patchHunk( UniHunk_t *hunk );
173static void diff_hunkFailed( UniDiff_t *diff, UniHunk_t *hunk );
174static void diff_hunkSuccess( UniDiff_t *diff, UniHunk_t *hunk );
175static void diff_cleanup( UniDiff_t *diff );
176static void diff_cleanupHunk( UniHunk_t *hunk );
177/* Misc. */
178static int diff_checkUpdateUniverse (void);
179/* Externed. */
180int diff_save( xmlTextWriterPtr writer );
181int diff_load( xmlNodePtr parent );
186static int diff_cmp( const void *p1, const void *p2 )
187{
188 const UniDiffData_t *d1, *d2;
189 d1 = (const UniDiffData_t*) p1;
190 d2 = (const UniDiffData_t*) p2;
191 return strcmp( d1->name, d2->name );
192}
193
200{
201 Uint32 time = SDL_GetTicks();
202 char **diff_files = ndata_listRecursive( UNIDIFF_DATA_PATH );
204 for (int i=0; i<array_size(diff_files); i++ ) {
205 xmlDocPtr doc;
206 xmlNodePtr node;
207 UniDiffData_t *diff;
208
209 /* Parse the header. */
210 doc = xml_parsePhysFS( diff_files[i] );
211 if (doc == NULL) {
212 free( diff_files[i] );
213 continue;
214 }
215
216 node = doc->xmlChildrenNode;
217 if (!xml_isNode(node,"unidiff")) {
218 WARN( _("Malformed XML header for '%s' UniDiff: missing root element '%s'"), diff_files[i], "unidiff" );
219 xmlFreeDoc( doc );
220 free( diff_files[i] );
221 continue;
222 }
223
224 diff = &array_grow(&diff_available);
225 diff->filename = diff_files[i];
226 xmlr_attr_strd(node, "name", diff->name);
227 xmlFreeDoc(doc);
228 }
229 array_free( diff_files );
231
232 /* Sort and warn about duplicates. */
233 qsort( diff_available, array_size(diff_available), sizeof(UniDiffData_t), diff_cmp );
234 for (int i=0; i<array_size(diff_available)-1; i++) {
236 UniDiffData_t *dn = &diff_available[i+1];
237 if (strcmp( d->name, dn->name )==0)
238 WARN(_("Two unidiff have the same name '%s'!"), d->name );
239 }
240
241 if (conf.devmode) {
242 time = SDL_GetTicks() - time;
243 DEBUG( n_("Loaded %d UniDiff in %.3f s", "Loaded %d UniDiffs in %.3f s", array_size(diff_available) ), array_size(diff_available), time/1000. );
244 }
245 else
246 DEBUG( n_("Loaded %d UniDiff", "Loaded %d UniDiffs", array_size(diff_available) ), array_size(diff_available) );
247
248 return 0;
249}
250
257int diff_isApplied( const char *name )
258{
259 if (diff_get(name) != NULL)
260 return 1;
261 return 0;
262}
263
270static UniDiff_t* diff_get( const char *name )
271{
272 for (int i=0; i<array_size(diff_stack); i++)
273 if (strcmp(diff_stack[i].name,name)==0)
274 return &diff_stack[i];
275 return NULL;
276}
277
284int diff_apply( const char *name )
285{
286 return diff_applyInternal( name, 1 );
287}
288
296static int diff_applyInternal( const char *name, int oneshot )
297{
298 xmlNodePtr node;
299 xmlDocPtr doc;
301
302 /* Check if already applied. */
303 if (diff_isApplied(name))
304 return 0;
305
306 /* Reset change variable. */
307 if (oneshot && !diff_universe_defer)
309
310 const UniDiffData_t q = { .name = (char*)name };
311 d = bsearch( &q, diff_available, array_size(diff_available), sizeof(UniDiffData_t), diff_cmp );
312 if (d == NULL) {
313 WARN(_("UniDiff '%s' not found in %s!"), name, UNIDIFF_DATA_PATH);
314 return -1;
315 }
316
317 doc = xml_parsePhysFS( d->filename );
318
319 node = doc->xmlChildrenNode;
320 if (strcmp((char*)node->name,"unidiff")) {
321 ERR(_("Malformed unidiff file: missing root element 'unidiff'"));
322 return 0;
323 }
324
325 /* Apply it. */
326 diff_patch( node );
327
328 xmlFreeDoc(doc);
329
330 /* Update universe. */
331 if (oneshot)
333
334 return 0;
335}
336
344static int diff_patchSystem( UniDiff_t *diff, xmlNodePtr node )
345{
346 UniHunk_t base, hunk;
347 xmlNodePtr cur;
348 char *buf;
349
350 /* Set the target. */
351 memset(&base, 0, sizeof(UniHunk_t));
352 base.target.type = HUNK_TARGET_SYSTEM;
353 xmlr_attr_strd(node,"name",base.target.u.name);
354 if (base.target.u.name==NULL) {
355 WARN(_("Unidiff '%s' has a system node without a 'name' tag, not applying."), diff->name);
356 return -1;
357 }
358
359 /* Now parse the possible changes. */
360 cur = node->xmlChildrenNode;
361 do {
362 xml_onlyNodes(cur);
363 if (xml_isNode(cur,"spob")) {
364 buf = xml_get( cur );
365 if ( buf == NULL ) {
366 WARN( _( "Unidiff '%s': Null hunk type." ), diff->name );
367 continue;
368 }
369
370 hunk.target.type = base.target.type;
371 hunk.target.u.name = strdup(base.target.u.name);
372
373 /* Get the spob to modify. */
374 xmlr_attr_strd(cur,"name",hunk.u.name);
375
376 /* Get the type. */
377 if (strcmp(buf,"add")==0)
378 hunk.type = HUNK_TYPE_SPOB_ADD;
379 else if (strcmp(buf,"remove")==0)
380 hunk.type = HUNK_TYPE_SPOB_REMOVE;
381 else
382 WARN(_("Unidiff '%s': Unknown hunk type '%s' for spob '%s'."), diff->name, buf, hunk.u.name);
383
384 /* Apply diff. */
385 if (diff_patchHunk( &hunk ) < 0)
386 diff_hunkFailed( diff, &hunk );
387 else
388 diff_hunkSuccess( diff, &hunk );
389 continue;
390 }
391 else if (xml_isNode(cur,"spob_virtual")) {
392 buf = xml_get( cur );
393 if ( buf == NULL ) {
394 WARN( _( "Unidiff '%s': Null hunk type." ), diff->name );
395 continue;
396 }
397
398 hunk.target.type = base.target.type;
399 hunk.target.u.name = strdup(base.target.u.name);
400
401 /* Get the spob to modify. */
402 xmlr_attr_strd(cur,"name",hunk.u.name);
403
404 /* Get the type. */
405 if (strcmp(buf,"add")==0)
406 hunk.type = HUNK_TYPE_VSPOB_ADD;
407 else if (strcmp(buf,"remove")==0)
408 hunk.type = HUNK_TYPE_VSPOB_REMOVE;
409 else
410 WARN(_("Unidiff '%s': Unknown hunk type '%s' for virtual spob '%s'."), diff->name, buf, hunk.u.name);
411
412 /* Apply diff. */
413 if (diff_patchHunk( &hunk ) < 0)
414 diff_hunkFailed( diff, &hunk );
415 else
416 diff_hunkSuccess( diff, &hunk );
417 continue;
418 }
419 else if (xml_isNode(cur,"jump")) {
420 buf = xml_get( cur );
421 if (buf == NULL) {
422 WARN( _( "Unidiff '%s': Null hunk type." ), diff->name );
423 continue;
424 }
425
426 hunk.target.type = base.target.type;
427 hunk.target.u.name = strdup(base.target.u.name);
428
429 /* Get the jump point to modify. */
430 xmlr_attr_strd(cur,"target",hunk.u.name);
431
432 /* Get the type. */
433 if (strcmp(buf,"add")==0)
434 hunk.type = HUNK_TYPE_JUMP_ADD;
435 else if (strcmp(buf,"remove")==0)
436 hunk.type = HUNK_TYPE_JUMP_REMOVE;
437 else
438 WARN(_("Unidiff '%s': Unknown hunk type '%s' for jump '%s'."), diff->name, buf, hunk.u.name);
439
440 hunk.node = cur;
441
442 /* Apply diff. */
443 if (diff_patchHunk( &hunk ) < 0)
444 diff_hunkFailed( diff, &hunk );
445 else
446 diff_hunkSuccess( diff, &hunk );
447 continue;
448 }
449 else if (xml_isNode(cur,"background")) {
450 hunk.target.type = base.target.type;
451 hunk.target.u.name = strdup(base.target.u.name);
452 hunk.type = HUNK_TYPE_SSYS_BACKGROUND;
453 hunk.u.name = xml_getStrd(cur);
454
455 /* Apply diff. */
456 if (diff_patchHunk( &hunk ) < 0)
457 diff_hunkFailed( diff, &hunk );
458 else
459 diff_hunkSuccess( diff, &hunk );
460 continue;
461 }
462 else if (xml_isNode(cur,"features")) {
463 hunk.target.type = base.target.type;
464 hunk.target.u.name = strdup(base.target.u.name);
465 hunk.type = HUNK_TYPE_SSYS_FEATURES;
466 hunk.u.name = xml_getStrd(cur);
467
468 /* Apply diff. */
469 if (diff_patchHunk( &hunk ) < 0)
470 diff_hunkFailed( diff, &hunk );
471 else
472 diff_hunkSuccess( diff, &hunk );
473 continue;
474 }
475 WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name);
476 } while (xml_nextNode(cur));
477
478 /* Clean up some stuff. */
479 free(base.target.u.name);
480 base.target.u.name = NULL;
481
482 return 0;
483}
484
492static int diff_patchTech( UniDiff_t *diff, xmlNodePtr node )
493{
494 UniHunk_t base, hunk;
495 xmlNodePtr cur;
496
497 /* Set the target. */
498 memset(&base, 0, sizeof(UniHunk_t));
499 base.target.type = HUNK_TARGET_TECH;
500 xmlr_attr_strd(node,"name",base.target.u.name);
501 if (base.target.u.name==NULL) {
502 WARN(_("Unidiff '%s' has an target node without a 'name' tag"), diff->name);
503 return -1;
504 }
505
506 /* Now parse the possible changes. */
507 cur = node->xmlChildrenNode;
508 do {
509 xml_onlyNodes(cur);
510 if (xml_isNode(cur,"add")) {
511 hunk.target.type = base.target.type;
512 hunk.target.u.name = strdup(base.target.u.name);
513
514 /* Outfit type is constant. */
515 hunk.type = HUNK_TYPE_TECH_ADD;
516
517 /* Get the data. */
518 hunk.u.name = xml_getStrd(cur);
519
520 /* Apply diff. */
521 if (diff_patchHunk( &hunk ) < 0)
522 diff_hunkFailed( diff, &hunk );
523 else
524 diff_hunkSuccess( diff, &hunk );
525 continue;
526 }
527 else if (xml_isNode(cur,"remove")) {
528 hunk.target.type = base.target.type;
529 hunk.target.u.name = strdup(base.target.u.name);
530
531 /* Outfit type is constant. */
532 hunk.type = HUNK_TYPE_TECH_REMOVE;
533
534 /* Get the data. */
535 hunk.u.name = xml_getStrd(cur);
536
537 /* Apply diff. */
538 if (diff_patchHunk( &hunk ) < 0)
539 diff_hunkFailed( diff, &hunk );
540 else
541 diff_hunkSuccess( diff, &hunk );
542 continue;
543 }
544 WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name);
545 } while (xml_nextNode(cur));
546
547 /* Clean up some stuff. */
548 free(base.target.u.name);
549 base.target.u.name = NULL;
550
551 return 0;
552}
553
561static int diff_patchSpob( UniDiff_t *diff, xmlNodePtr node )
562{
563 UniHunk_t base, hunk;
564 xmlNodePtr cur;
565
566 /* Set the target. */
567 memset(&base, 0, sizeof(UniHunk_t));
568 base.target.type = HUNK_TARGET_SPOB;
569 xmlr_attr_strd(node,"name",base.target.u.name);
570 if (base.target.u.name==NULL) {
571 WARN(_("Unidiff '%s' has an target node without a 'name' tag"), diff->name);
572 return -1;
573 }
574
575 /* Now parse the possible changes. */
576 cur = node->xmlChildrenNode;
577 do {
578 xml_onlyNodes(cur);
579 if (xml_isNode(cur,"faction")) {
580 hunk.target.type = base.target.type;
581 hunk.target.u.name = strdup(base.target.u.name);
582 hunk.type = HUNK_TYPE_SPOB_FACTION;
583 hunk.u.name = xml_getStrd(cur);
584
585 /* Apply diff. */
586 if (diff_patchHunk( &hunk ) < 0)
587 diff_hunkFailed( diff, &hunk );
588 else
589 diff_hunkSuccess( diff, &hunk );
590 continue;
591 }
592 else if (xml_isNode(cur,"population")) {
593 hunk.target.type = base.target.type;
594 hunk.target.u.name = strdup(base.target.u.name);
595 hunk.type = HUNK_TYPE_SPOB_POPULATION;
596 hunk.u.data = xml_getUInt(cur);
597
598 /* Apply diff. */
599 if (diff_patchHunk( &hunk ) < 0)
600 diff_hunkFailed( diff, &hunk );
601 else
602 diff_hunkSuccess( diff, &hunk );
603 continue;
604 }
605 else if (xml_isNode(cur,"displayname")) {
606 hunk.target.type = base.target.type;
607 hunk.target.u.name = strdup(base.target.u.name);
608 hunk.type = HUNK_TYPE_SPOB_DISPLAYNAME;
609 hunk.u.name = xml_getStrd(cur);
610
611 /* Apply diff. */
612 if (diff_patchHunk( &hunk ) < 0)
613 diff_hunkFailed( diff, &hunk );
614 else
615 diff_hunkSuccess( diff, &hunk );
616 continue;
617 }
618 else if (xml_isNode(cur,"description")) {
619 hunk.target.type = base.target.type;
620 hunk.target.u.name = strdup(base.target.u.name);
621 hunk.type = HUNK_TYPE_SPOB_DESCRIPTION;
622 hunk.u.name = xml_getStrd(cur);
623
624 /* Apply diff. */
625 if (diff_patchHunk( &hunk ) < 0)
626 diff_hunkFailed( diff, &hunk );
627 else
628 diff_hunkSuccess( diff, &hunk );
629 continue;
630 }
631 else if (xml_isNode(cur,"bar")) {
632 hunk.target.type = base.target.type;
633 hunk.target.u.name = strdup(base.target.u.name);
634 hunk.type = HUNK_TYPE_SPOB_BAR;
635 hunk.u.name = xml_getStrd(cur);
636
637 /* Apply diff. */
638 if (diff_patchHunk( &hunk ) < 0)
639 diff_hunkFailed( diff, &hunk );
640 else
641 diff_hunkSuccess( diff, &hunk );
642 continue;
643 }
644 else if (xml_isNode(cur,"service_add")) {
645 hunk.target.type = base.target.type;
646 hunk.target.u.name = strdup(base.target.u.name);
647 hunk.type = HUNK_TYPE_SPOB_SERVICE_ADD;
648 hunk.u.data = spob_getService( xml_get(cur) );
649
650 /* Apply diff. */
651 if (diff_patchHunk( &hunk ) < 0)
652 diff_hunkFailed( diff, &hunk );
653 else
654 diff_hunkSuccess( diff, &hunk );
655 continue;
656 }
657 else if (xml_isNode(cur,"service_remove")) {
658 hunk.target.type = base.target.type;
659 hunk.target.u.name = strdup(base.target.u.name);
660 hunk.type = HUNK_TYPE_SPOB_SERVICE_REMOVE;
661 hunk.u.data = spob_getService( xml_get(cur) );
662
663 /* Apply diff. */
664 if (diff_patchHunk( &hunk ) < 0)
665 diff_hunkFailed( diff, &hunk );
666 else
667 diff_hunkSuccess( diff, &hunk );
668 continue;
669 }
670 else if (xml_isNode(cur,"nomissionspawn_add")) {
671 hunk.target.type = base.target.type;
672 hunk.target.u.name = strdup(base.target.u.name);
673 hunk.type = HUNK_TYPE_SPOB_NOMISNSPAWN_ADD;
674
675 /* Apply diff. */
676 if (diff_patchHunk( &hunk ) < 0)
677 diff_hunkFailed( diff, &hunk );
678 else
679 diff_hunkSuccess( diff, &hunk );
680 continue;
681 }
682 else if (xml_isNode(cur,"nomissionspawn_remove")) {
683 hunk.target.type = base.target.type;
684 hunk.target.u.name = strdup(base.target.u.name);
685 hunk.type = HUNK_TYPE_SPOB_NOMISNSPAWN_REMOVE;
686
687 /* Apply diff. */
688 if (diff_patchHunk( &hunk ) < 0)
689 diff_hunkFailed( diff, &hunk );
690 else
691 diff_hunkSuccess( diff, &hunk );
692 continue;
693 }
694 else if (xml_isNode(cur,"tech_add")) {
695 hunk.target.type = base.target.type;
696 hunk.target.u.name = strdup(base.target.u.name);
697 hunk.type = HUNK_TYPE_SPOB_TECH_ADD;
698 hunk.u.name = xml_getStrd(cur);
699
700 /* Apply diff. */
701 if (diff_patchHunk( &hunk ) < 0)
702 diff_hunkFailed( diff, &hunk );
703 else
704 diff_hunkSuccess( diff, &hunk );
705 continue;
706 }
707 else if (xml_isNode(cur,"tech_remove")) {
708 hunk.target.type = base.target.type;
709 hunk.target.u.name = strdup(base.target.u.name);
710 hunk.type = HUNK_TYPE_SPOB_TECH_REMOVE;
711 hunk.u.name = xml_getStrd(cur);
712
713 /* Apply diff. */
714 if (diff_patchHunk( &hunk ) < 0)
715 diff_hunkFailed( diff, &hunk );
716 else
717 diff_hunkSuccess( diff, &hunk );
718 continue;
719 }
720 else if (xml_isNode(cur,"tag_add")) {
721 hunk.target.type = base.target.type;
722 hunk.target.u.name = strdup(base.target.u.name);
723 hunk.type = HUNK_TYPE_SPOB_TAG_ADD;
724 hunk.u.name = xml_getStrd(cur);
725
726 /* Apply diff. */
727 if (diff_patchHunk( &hunk ) < 0)
728 diff_hunkFailed( diff, &hunk );
729 else
730 diff_hunkSuccess( diff, &hunk );
731 continue;
732 }
733 else if (xml_isNode(cur,"tag_remove")) {
734 hunk.target.type = base.target.type;
735 hunk.target.u.name = strdup(base.target.u.name);
736 hunk.type = HUNK_TYPE_SPOB_TAG_REMOVE;
737 hunk.u.name = xml_getStrd(cur);
738
739 /* Apply diff. */
740 if (diff_patchHunk( &hunk ) < 0)
741 diff_hunkFailed( diff, &hunk );
742 else
743 diff_hunkSuccess( diff, &hunk );
744 continue;
745 }
746 else if (xml_isNode(cur,"gfx_space")) {
747 char str[PATH_MAX];
748 hunk.target.type = base.target.type;
749 hunk.target.u.name = strdup(base.target.u.name);
750 hunk.type = HUNK_TYPE_SPOB_SPACE;
751 snprintf( str, sizeof(str), SPOB_GFX_SPACE_PATH"%s", xml_get(cur));
752 hunk.u.name = strdup(str);
753
754 /* Apply diff. */
755 if (diff_patchHunk( &hunk ) < 0)
756 diff_hunkFailed( diff, &hunk );
757 else
758 diff_hunkSuccess( diff, &hunk );
759 continue;
760 }
761 else if (xml_isNode(cur,"gfx_exterior")) {
762 char str[PATH_MAX];
763 hunk.target.type = base.target.type;
764 hunk.target.u.name = strdup(base.target.u.name);
765 hunk.type = HUNK_TYPE_SPOB_EXTERIOR;
766 snprintf( str, sizeof(str), SPOB_GFX_EXTERIOR_PATH"%s", xml_get(cur));
767 hunk.u.name = strdup(str);
768
769 /* Apply diff. */
770 if (diff_patchHunk( &hunk ) < 0)
771 diff_hunkFailed( diff, &hunk );
772 else
773 diff_hunkSuccess( diff, &hunk );
774 continue;
775 }
776 else if (xml_isNode(cur,"lua")) {
777 char *str;
778 hunk.target.type = base.target.type;
779 hunk.target.u.name = strdup(base.target.u.name);
780 hunk.type = HUNK_TYPE_SPOB_LUA;
781 str = xml_get(cur);
782 if (str != NULL)
783 hunk.u.name = strdup( str );
784 else
785 hunk.u.name = NULL;
786
787 /* Apply diff. */
788 if (diff_patchHunk( &hunk ) < 0)
789 diff_hunkFailed( diff, &hunk );
790 else
791 diff_hunkSuccess( diff, &hunk );
792 continue;
793 }
794 WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, cur->name);
795 } while (xml_nextNode(cur));
796
797 /* Clean up some stuff. */
798 free(base.target.u.name);
799 base.target.u.name = NULL;
800
801 return 0;
802}
803
811static int diff_patchFaction( UniDiff_t *diff, xmlNodePtr node )
812{
813 UniHunk_t base, hunk;
814 xmlNodePtr cur;
815 char *buf;
816
817 /* Set the target. */
818 memset(&base, 0, sizeof(UniHunk_t));
819 base.target.type = HUNK_TARGET_FACTION;
820 xmlr_attr_strd(node,"name",base.target.u.name);
821 if (base.target.u.name==NULL) {
822 WARN(_("Unidiff '%s' has an target node without a 'name' tag"), diff->name);
823 return -1;
824 }
825
826 /* Now parse the possible changes. */
827 cur = node->xmlChildrenNode;
828 do {
829 xml_onlyNodes(cur);
830 if (xml_isNode(cur,"visible")) {
831 hunk.target.type = base.target.type;
832 hunk.target.u.name = strdup(base.target.u.name);
833
834 /* Faction type is constant. */
835 hunk.type = HUNK_TYPE_FACTION_VISIBLE;
836
837 /* There is no name. */
838 hunk.u.name = NULL;
839
840 /* Apply diff. */
841 if (diff_patchHunk( &hunk ) < 0)
842 diff_hunkFailed( diff, &hunk );
843 else
844 diff_hunkSuccess( diff, &hunk );
845 continue;
846 }
847 else if (xml_isNode(cur,"invisible")) {
848 hunk.target.type = base.target.type;
849 hunk.target.u.name = strdup(base.target.u.name);
850
851 /* Faction type is constant. */
852 hunk.type = HUNK_TYPE_FACTION_INVISIBLE;
853
854 /* There is no name. */
855 hunk.u.name = NULL;
856
857 /* Apply diff. */
858 if (diff_patchHunk( &hunk ) < 0)
859 diff_hunkFailed( diff, &hunk );
860 else
861 diff_hunkSuccess( diff, &hunk );
862 continue;
863 }
864 else if (xml_isNode(cur,"faction")) {
865 buf = xml_get( cur );
866 if ( buf == NULL ) {
867 WARN( _( "Unidiff '%s': Null hunk type." ), diff->name );
868 continue;
869 }
870
871 hunk.target.type = base.target.type;
872 hunk.target.u.name = strdup(base.target.u.name);
873
874 /* Get the faction to set the association of. */
875 xmlr_attr_strd(cur,"name",hunk.u.name);
876
877 /* Get the type. */
878 if (strcmp(buf,"ally")==0)
879 hunk.type = HUNK_TYPE_FACTION_ALLY;
880 else if (strcmp(buf,"enemy")==0)
881 hunk.type = HUNK_TYPE_FACTION_ENEMY;
882 else if (strcmp(buf,"neutral")==0)
883 hunk.type = HUNK_TYPE_FACTION_NEUTRAL;
884 else
885 WARN(_("Unidiff '%s': Unknown hunk type '%s' for faction '%s'."), diff->name, buf, hunk.u.name);
886
887 /* Apply diff. */
888 if (diff_patchHunk( &hunk ) < 0)
889 diff_hunkFailed( diff, &hunk );
890 else
891 diff_hunkSuccess( diff, &hunk );
892 continue;
893 }
894 WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name);
895 } while (xml_nextNode(cur));
896
897 /* Clean up some stuff. */
898 free(base.target.u.name);
899 base.target.u.name = NULL;
900
901 return 0;
902}
903
910static int diff_patch( xmlNodePtr parent )
911{
912 UniDiff_t *diff;
913 xmlNodePtr node;
914 int nfailed;
915
916 /* Prepare it. */
917 diff = diff_newDiff();
918 memset(diff, 0, sizeof(UniDiff_t));
919 xmlr_attr_strd(parent,"name",diff->name);
920
921 node = parent->xmlChildrenNode;
922 do {
923 xml_onlyNodes(node);
924 if (xml_isNode(node,"system")) {
926 diff_patchSystem( diff, node );
927 }
928 else if (xml_isNode(node, "tech"))
929 diff_patchTech( diff, node );
930 else if (xml_isNode(node, "spob")) {
932 diff_patchSpob( diff, node );
933 }
934 else if (xml_isNode(node, "faction")) {
936 diff_patchFaction( diff, node );
937 }
938 else
939 WARN(_("Unidiff '%s' has unknown node '%s'."), diff->name, node->name);
940 } while (xml_nextNode(node));
941
942 nfailed = array_size(diff->failed);
943 if (nfailed > 0) {
944 WARN(
945 n_( "Unidiff '%s' failed to apply %d hunk.", "Unidiff '%s' failed to apply %d hunks.", nfailed ),
946 diff->name, nfailed );
947 for (int i=0; i<nfailed; i++) {
948 UniHunk_t *fail = &diff->failed[i];
949 char *target = fail->target.u.name;
950 switch (fail->type) {
951 case HUNK_TYPE_SPOB_ADD:
952 WARN(_(" [%s] spob add: '%s'"), target, fail->u.name);
953 break;
954 case HUNK_TYPE_SPOB_REMOVE:
955 WARN(_(" [%s] spob remove: '%s'"), target, fail->u.name);
956 break;
957 case HUNK_TYPE_VSPOB_ADD:
958 WARN(_(" [%s] virtual spob add: '%s'"), target, fail->u.name);
959 break;
960 case HUNK_TYPE_VSPOB_REMOVE:
961 WARN(_(" [%s] virtual spob remove: '%s'"), target, fail->u.name);
962 break;
963 case HUNK_TYPE_JUMP_ADD:
964 WARN(_(" [%s] jump add: '%s'"), target, fail->u.name);
965 break;
966 case HUNK_TYPE_JUMP_REMOVE:
967 WARN(_(" [%s] jump remove: '%s'"), target, fail->u.name);
968 break;
969 case HUNK_TYPE_TECH_ADD:
970 WARN(_(" [%s] tech add: '%s'"), target,
971 fail->u.name );
972 break;
973 case HUNK_TYPE_TECH_REMOVE:
974 WARN(_(" [%s] tech remove: '%s'"), target,
975 fail->u.name );
976 break;
977 case HUNK_TYPE_SPOB_FACTION:
978 WARN(_(" [%s] spob faction: '%s'"), target,
979 fail->u.name );
980 break;
981 case HUNK_TYPE_SPOB_FACTION_REMOVE:
982 WARN(_(" [%s] spob faction removal: '%s'"), target,
983 fail->u.name );
984 break;
985 case HUNK_TYPE_SPOB_POPULATION:
986 WARN(_(" [%s] spob population: '%s'"), target,
987 fail->u.name );
988 break;
989 case HUNK_TYPE_SPOB_POPULATION_REMOVE:
990 WARN(_(" [%s] spob population removal: '%s'"), target,
991 fail->u.name );
992 break;
993 case HUNK_TYPE_SPOB_DISPLAYNAME:
994 WARN(_(" [%s] spob displayname: '%s'"), target,
995 fail->u.name );
996 break;
997 case HUNK_TYPE_SPOB_DISPLAYNAME_REVERT:
998 WARN(_(" [%s] spob displayname revert: '%s'"), target,
999 fail->u.name );
1000 break;
1001 case HUNK_TYPE_SPOB_DESCRIPTION:
1002 WARN(_(" [%s] spob description: '%s'"), target,
1003 fail->u.name );
1004 break;
1005 case HUNK_TYPE_SPOB_DESCRIPTION_REVERT:
1006 WARN(_(" [%s] spob description revert: '%s'"), target,
1007 fail->u.name );
1008 break;
1009 case HUNK_TYPE_SPOB_BAR:
1010 WARN(_(" [%s] spob bar: '%s'"), target,
1011 fail->u.name );
1012 break;
1013 case HUNK_TYPE_SPOB_BAR_REVERT:
1014 WARN(_(" [%s] spob bar revert: '%s'"), target,
1015 fail->u.name );
1016 break;
1017 case HUNK_TYPE_SPOB_SPACE:
1018 WARN(_(" [%s] spob space: '%s'"), target,
1019 fail->u.name );
1020 break;
1021 case HUNK_TYPE_SPOB_SPACE_REVERT:
1022 WARN(_(" [%s] spob space revert: '%s'"), target,
1023 fail->u.name );
1024 break;
1025 case HUNK_TYPE_SPOB_EXTERIOR:
1026 WARN(_(" [%s] spob exterior: '%s'"), target,
1027 fail->u.name );
1028 break;
1029 case HUNK_TYPE_SPOB_EXTERIOR_REVERT:
1030 WARN(_(" [%s] spob exterior revert: '%s'"), target,
1031 fail->u.name );
1032 break;
1033 case HUNK_TYPE_SPOB_LUA:
1034 WARN(_(" [%s] spob lua: '%s'"), target,
1035 fail->u.name );
1036 break;
1037 case HUNK_TYPE_SPOB_LUA_REVERT:
1038 WARN(_(" [%s] spob lua revert: '%s'"), target,
1039 fail->u.name );
1040 break;
1041 case HUNK_TYPE_SPOB_SERVICE_ADD:
1042 WARN(_(" [%s] spob service add: '%s'"), target,
1043 spob_getServiceName(fail->u.data) );
1044 break;
1045 case HUNK_TYPE_SPOB_SERVICE_REMOVE:
1046 WARN(_(" [%s] spob service remove: '%s'"), target,
1047 spob_getServiceName(fail->u.data) );
1048 break;
1049 case HUNK_TYPE_SPOB_NOMISNSPAWN_ADD:
1050 WARN(_(" [%s] spob nomissionspawn add"), target );
1051 break;
1052 case HUNK_TYPE_SPOB_NOMISNSPAWN_REMOVE:
1053 WARN(_(" [%s] spob nomissionspawn remove"), target );
1054 break;
1055 case HUNK_TYPE_SPOB_TECH_ADD:
1056 WARN(_(" [%s] spob tech add: '%s'"), target,
1057 fail->u.name );
1058 break;
1059 case HUNK_TYPE_SPOB_TECH_REMOVE:
1060 WARN(_(" [%s] spob tech remove: '%s'"), target,
1061 fail->u.name );
1062 break;
1063 case HUNK_TYPE_SPOB_TAG_ADD:
1064 WARN(_(" [%s] spob tech add: '%s'"), target,
1065 fail->u.name );
1066 break;
1067 case HUNK_TYPE_SPOB_TAG_REMOVE:
1068 WARN(_(" [%s] spob tech remove: '%s'"), target,
1069 fail->u.name );
1070 break;
1071 case HUNK_TYPE_FACTION_VISIBLE:
1072 WARN(_(" [%s] faction visible: '%s'"), target,
1073 fail->u.name );
1074 break;
1075 case HUNK_TYPE_FACTION_INVISIBLE:
1076 WARN(_(" [%s] faction invisible: '%s'"), target,
1077 fail->u.name );
1078 break;
1079 case HUNK_TYPE_FACTION_ALLY:
1080 WARN(_(" [%s] faction set ally: '%s'"), target,
1081 fail->u.name );
1082 break;
1083 case HUNK_TYPE_FACTION_ENEMY:
1084 WARN(_(" [%s] faction set enemy: '%s'"), target,
1085 fail->u.name );
1086 break;
1087 case HUNK_TYPE_FACTION_NEUTRAL:
1088 WARN(_(" [%s] faction set neutral: '%s'"), target,
1089 fail->u.name );
1090 break;
1091 case HUNK_TYPE_FACTION_REALIGN:
1092 WARN(_(" [%s] faction alignment reset: '%s'"), target,
1093 fail->u.name );
1094 break;
1095
1096 default:
1097 WARN(_(" unknown hunk '%d'"), fail->type);
1098 break;
1099 }
1100 }
1101 }
1102
1103 /* Update overlay map just in case. */
1104 ovr_refresh();
1105 return 0;
1106}
1107
1114static int diff_patchHunk( UniHunk_t *hunk )
1115{
1116 Spob *p;
1117 StarSystem *ssys;
1118 int a, b;
1119
1120 switch (hunk->type) {
1121
1122 /* Adding an spob. */
1123 case HUNK_TYPE_SPOB_ADD:
1124 spob_luaInit( spob_get(hunk->u.name) );
1126 return system_addSpob( system_get(hunk->target.u.name), hunk->u.name );
1127 /* Removing an spob. */
1128 case HUNK_TYPE_SPOB_REMOVE:
1130 return system_rmSpob( system_get(hunk->target.u.name), hunk->u.name );
1131
1132 /* Adding an spob. */
1133 case HUNK_TYPE_VSPOB_ADD:
1135 return system_addVirtualSpob( system_get(hunk->target.u.name), hunk->u.name );
1136 /* Removing an spob. */
1137 case HUNK_TYPE_VSPOB_REMOVE:
1139 return system_rmVirtualSpob( system_get(hunk->target.u.name), hunk->u.name );
1140
1141 /* Adding a Jump. */
1142 case HUNK_TYPE_JUMP_ADD:
1144 return system_addJumpDiff( system_get(hunk->target.u.name), hunk->node );
1145 /* Removing a jump. */
1146 case HUNK_TYPE_JUMP_REMOVE:
1148 return system_rmJump( system_get(hunk->target.u.name), hunk->u.name );
1149
1150 /* Changing system background. */
1151 case HUNK_TYPE_SSYS_BACKGROUND:
1152 ssys = system_get(hunk->target.u.name);
1153 hunk->o.name = ssys->background;
1154 ssys->background = hunk->u.name;
1155 return 0;
1156 case HUNK_TYPE_SSYS_BACKGROUND_REVERT:
1157 ssys = system_get(hunk->target.u.name);
1158 ssys->background = (char*)hunk->o.name;
1159 return 0;
1160
1161 /* Changing system features designation. */
1162 case HUNK_TYPE_SSYS_FEATURES:
1163 ssys = system_get(hunk->target.u.name);
1164 hunk->o.name = ssys->features;
1165 ssys->features = hunk->u.name;
1166 return 0;
1167 case HUNK_TYPE_SSYS_FEATURES_REVERT:
1168 ssys = system_get(hunk->target.u.name);
1169 ssys->features = (char*)hunk->o.name;
1170 return 0;
1171
1172 /* Adding a tech. */
1173 case HUNK_TYPE_TECH_ADD:
1174 return tech_addItem( hunk->target.u.name, hunk->u.name );
1175 /* Removing a tech. */
1176 case HUNK_TYPE_TECH_REMOVE:
1177 return tech_rmItem( hunk->target.u.name, hunk->u.name );
1178
1179 /* Changing spob faction. */
1180 case HUNK_TYPE_SPOB_FACTION:
1181 p = spob_get( hunk->target.u.name );
1182 if (p==NULL)
1183 return -1;
1184 if (p->presence.faction<0)
1185 hunk->o.name = NULL;
1186 else
1187 hunk->o.name = faction_name( p->presence.faction );
1189 return spob_setFaction( p, faction_get(hunk->u.name) );
1190 case HUNK_TYPE_SPOB_FACTION_REMOVE:
1191 p = spob_get( hunk->target.u.name );
1192 if (p==NULL)
1193 return -1;
1195 if (hunk->o.name==NULL)
1196 return spob_setFaction( p, -1 );
1197 else
1198 return spob_setFaction( p, faction_get(hunk->o.name) );
1199
1200 /* Changing spob population. */
1201 case HUNK_TYPE_SPOB_POPULATION:
1202 p = spob_get( hunk->target.u.name );
1203 if (p==NULL)
1204 return -1;
1205 hunk->o.data = p->population;
1206 p->population = hunk->u.data;
1207 return 0;
1208 case HUNK_TYPE_SPOB_POPULATION_REMOVE:
1209 p = spob_get( hunk->target.u.name );
1210 if (p==NULL)
1211 return -1;
1212 p->population = hunk->o.data;
1213 return 0;
1214
1215 /* Changing spob displayname. */
1216 case HUNK_TYPE_SPOB_DISPLAYNAME:
1217 p = spob_get( hunk->target.u.name );
1218 if (p==NULL)
1219 return -1;
1220 hunk->o.name = p->display;
1221 p->display = hunk->u.name;
1222 return 0;
1223 case HUNK_TYPE_SPOB_DISPLAYNAME_REVERT:
1224 p = spob_get( hunk->target.u.name );
1225 if (p==NULL)
1226 return -1;
1227 p->display = (char*)hunk->o.name;
1228 return 0;
1229
1230 /* Changing spob description. */
1231 case HUNK_TYPE_SPOB_DESCRIPTION:
1232 p = spob_get( hunk->target.u.name );
1233 if (p==NULL)
1234 return -1;
1235 hunk->o.name = p->description;
1236 p->description = hunk->u.name;
1237 return 0;
1238 case HUNK_TYPE_SPOB_DESCRIPTION_REVERT:
1239 p = spob_get( hunk->target.u.name );
1240 if (p==NULL)
1241 return -1;
1242 p->description = (char*)hunk->o.name;
1243 return 0;
1244
1245 /* Changing spob bar description. */
1246 case HUNK_TYPE_SPOB_BAR:
1247 p = spob_get( hunk->target.u.name );
1248 if (p==NULL)
1249 return -1;
1250 hunk->o.name = p->bar_description;
1251 p->bar_description = hunk->u.name;
1252 return 0;
1253 case HUNK_TYPE_SPOB_BAR_REVERT:
1254 p = spob_get( hunk->target.u.name );
1255 if (p==NULL)
1256 return -1;
1257 p->bar_description = (char*)hunk->o.name;
1258 return 0;
1259
1260 /* Modifying spob services. */
1261 case HUNK_TYPE_SPOB_SERVICE_ADD:
1262 p = spob_get( hunk->target.u.name );
1263 if (p==NULL)
1264 return -1;
1265 if (spob_hasService( p, hunk->u.data ))
1266 return -1;
1267 spob_addService( p, hunk->u.data );
1269 return 0;
1270 case HUNK_TYPE_SPOB_SERVICE_REMOVE:
1271 p = spob_get( hunk->target.u.name );
1272 if (p==NULL)
1273 return -1;
1274 if (!spob_hasService( p, hunk->u.data ))
1275 return -1;
1276 spob_rmService( p, hunk->u.data );
1278 return 0;
1279
1280 /* Modifying mission spawn. */
1281 case HUNK_TYPE_SPOB_NOMISNSPAWN_ADD:
1282 p = spob_get( hunk->target.u.name );
1283 if (p==NULL)
1284 return -1;
1285 if (spob_isFlag( p, SPOB_NOMISNSPAWN ))
1286 return -1;
1287 spob_setFlag( p, SPOB_NOMISNSPAWN );
1288 return 0;
1289 case HUNK_TYPE_SPOB_NOMISNSPAWN_REMOVE:
1290 p = spob_get( hunk->target.u.name );
1291 if (p==NULL)
1292 return -1;
1293 if (!spob_isFlag( p, SPOB_NOMISNSPAWN ))
1294 return -1;
1295 spob_rmFlag( p, SPOB_NOMISNSPAWN );
1296 return 0;
1297
1298 /* Modifying tech stuff. */
1299 case HUNK_TYPE_SPOB_TECH_ADD:
1300 p = spob_get( hunk->target.u.name );
1301 if (p==NULL)
1302 return -1;
1303 if (p->tech == NULL)
1304 p->tech = tech_groupCreate();
1305 tech_addItemTech( p->tech, hunk->u.name );
1306 return 0;
1307 case HUNK_TYPE_SPOB_TECH_REMOVE:
1308 p = spob_get( hunk->target.u.name );
1309 if (p==NULL)
1310 return -1;
1311 tech_rmItemTech( p->tech, hunk->u.name );
1312 return 0;
1313
1314 /* Modifying tag stuff. */
1315 case HUNK_TYPE_SPOB_TAG_ADD:
1316 p = spob_get( hunk->target.u.name );
1317 if (p==NULL)
1318 return -1;
1319 if (p->tech == NULL)
1320 p->tech = tech_groupCreate();
1321 if (p->tags==NULL)
1322 p->tags = array_create( char* );
1323 array_push_back( &p->tags, strdup( hunk->u.name ) );
1324 return 0;
1325 case HUNK_TYPE_SPOB_TAG_REMOVE:
1326 p = spob_get( hunk->target.u.name );
1327 if (p==NULL)
1328 return -1;
1329 a = -1;
1330 for (int i=0; i<array_size(p->tags); i++) {
1331 if (strcmp(p->tags[i], hunk->u.name )==0) {
1332 a = i;
1333 break;
1334 }
1335 }
1336 if (a<0)
1337 return -1; /* Didn't find tag! */
1338 free( p->tags[a] );
1339 array_erase( &p->tags, &p->tags[a], &p->tags[a+1] );
1340 return 0;
1341
1342 /* Changing spob space graphics. */
1343 case HUNK_TYPE_SPOB_SPACE:
1344 p = spob_get( hunk->target.u.name );
1345 if (p==NULL)
1346 return -1;
1347 hunk->o.name = p->gfx_spaceName;
1348 p->gfx_spaceName = hunk->u.name;
1350 return 0;
1351 case HUNK_TYPE_SPOB_SPACE_REVERT:
1352 p = spob_get( hunk->target.u.name );
1353 if (p==NULL)
1354 return -1;
1355 p->gfx_spaceName = (char*)hunk->o.name;
1357 return 0;
1358
1359 /* Changing spob exterior graphics. */
1360 case HUNK_TYPE_SPOB_EXTERIOR:
1361 p = spob_get( hunk->target.u.name );
1362 if (p==NULL)
1363 return -1;
1364 hunk->o.name = p->gfx_exterior;
1365 p->gfx_exterior = hunk->u.name;
1366 return 0;
1367 case HUNK_TYPE_SPOB_EXTERIOR_REVERT:
1368 p = spob_get( hunk->target.u.name );
1369 if (p==NULL)
1370 return -1;
1371 p->gfx_exterior = (char*)hunk->o.name;
1372 return 0;
1373
1374 /* Change Lua stuff. */
1375 case HUNK_TYPE_SPOB_LUA:
1376 p = spob_get( hunk->target.u.name );
1377 if (p==NULL)
1378 return -1;
1379 hunk->o.name = p->lua_file;
1380 p->lua_file = hunk->u.name;
1381 spob_luaInit( p );
1383 return 0;
1384 case HUNK_TYPE_SPOB_LUA_REVERT:
1385 p = spob_get( hunk->target.u.name );
1386 if (p==NULL)
1387 return -1;
1388 p->lua_file = (char*)hunk->o.name;
1389 spob_luaInit( p );
1391 return 0;
1392
1393 /* Making a faction visible. */
1394 case HUNK_TYPE_FACTION_VISIBLE:
1395 return faction_setInvisible( faction_get(hunk->target.u.name), 0 );
1396 /* Making a faction invisible. */
1397 case HUNK_TYPE_FACTION_INVISIBLE:
1398 return faction_setInvisible( faction_get(hunk->target.u.name), 1 );
1399 /* Making two factions allies. */
1400 case HUNK_TYPE_FACTION_ALLY:
1401 a = faction_get( hunk->target.u.name );
1402 b = faction_get( hunk->u.name );
1403 if (areAllies(a, b))
1404 hunk->o.data = 'A';
1405 else if (areEnemies(a, b))
1406 hunk->o.data = 'E';
1407 else
1408 hunk->o.data = 0;
1409 faction_addAlly( a, b );
1410 faction_addAlly( b, a );
1411 return 0;
1412 /* Making two factions enemies. */
1413 case HUNK_TYPE_FACTION_ENEMY:
1414 a = faction_get( hunk->target.u.name );
1415 b = faction_get( hunk->u.name );
1416 if (areAllies(a, b))
1417 hunk->o.data = 'A';
1418 else if (areEnemies(a, b))
1419 hunk->o.data = 'E';
1420 else
1421 hunk->o.data = 0;
1422 faction_addEnemy( a, b );
1423 faction_addEnemy( b, a );
1424 return 0;
1425 /* Making two factions neutral (removing enemy/ally statuses). */
1426 case HUNK_TYPE_FACTION_NEUTRAL:
1427 a = faction_get( hunk->target.u.name );
1428 b = faction_get( hunk->u.name );
1429 if (areAllies(a, b))
1430 hunk->o.data = 'A';
1431 else if (areEnemies(a, b))
1432 hunk->o.data = 'E';
1433 else
1434 hunk->o.data = 0;
1435 faction_rmAlly( a, b );
1436 faction_rmAlly( b, a );
1437 faction_rmEnemy( a, b );
1438 faction_rmEnemy( b, a );
1439 return 0;
1440 /* Resetting the alignment state of two factions. */
1441 case HUNK_TYPE_FACTION_REALIGN:
1442 a = faction_get( hunk->target.u.name );
1443 b = faction_get( hunk->u.name );
1444 if (hunk->o.data == 'A') {
1445 faction_rmEnemy(a, b);
1446 faction_rmEnemy(b, a);
1447 faction_addAlly(a, b);
1448 faction_addAlly(b, a);
1449 }
1450 else if (hunk->o.data == 'E') {
1451 faction_rmAlly(a, b);
1452 faction_rmAlly(b, a);
1453 faction_addEnemy(a, b);
1454 faction_addAlly(b, a);
1455 }
1456 else {
1457 faction_rmAlly( a, b );
1458 faction_rmAlly( b, a );
1459 faction_rmEnemy( a, b );
1460 faction_rmEnemy( b, a );
1461 }
1462 return 0;
1463
1464 default:
1465 WARN(_("Unknown hunk type '%d'."), hunk->type);
1466 break;
1467 }
1468
1469 return -1;
1470}
1471
1478static void diff_hunkFailed( UniDiff_t *diff, UniHunk_t *hunk )
1479{
1480 if (diff == NULL)
1481 return;
1482 if (diff->failed == NULL)
1483 diff->failed = array_create( UniHunk_t );
1484 array_grow( &diff->failed ) = *hunk;
1485}
1486
1493static void diff_hunkSuccess( UniDiff_t *diff, UniHunk_t *hunk )
1494{
1495 if (diff == NULL)
1496 return;
1497 if (diff->applied == NULL)
1498 diff->applied = array_create( UniHunk_t );
1499 array_grow( &diff->applied ) = *hunk;
1500}
1501
1507void diff_remove( const char *name )
1508{
1509 /* Check if already applied. */
1510 UniDiff_t *diff = diff_get(name);
1511 if (diff == NULL)
1512 return;
1513
1514 diff_removeDiff(diff);
1515
1517}
1518
1522void diff_clear (void)
1523{
1524 while (array_size(diff_stack) > 0)
1527 diff_stack = NULL;
1528
1530}
1531
1535void diff_free (void)
1536{
1537 diff_clear();
1538 for (int i = 0; i < array_size(diff_available); i++) {
1540 free( d->name );
1541 free( d->filename );
1542 }
1544 diff_available = NULL;
1545}
1546
1553{
1554 /* Check if needs initialization. */
1555 if (diff_stack == NULL)
1557 return &array_grow(&diff_stack);
1558}
1559
1566static int diff_removeDiff( UniDiff_t *diff )
1567{
1568 for (int i=0; i<array_size(diff->applied); i++) {
1569 UniHunk_t hunk = diff->applied[i];
1570 /* Invert the type for reverting. */
1571 switch (hunk.type) {
1572 case HUNK_TYPE_SPOB_ADD:
1573 hunk.type = HUNK_TYPE_SPOB_REMOVE;
1574 break;
1575 case HUNK_TYPE_SPOB_REMOVE:
1576 hunk.type = HUNK_TYPE_SPOB_ADD;
1577 break;
1578
1579 case HUNK_TYPE_VSPOB_ADD:
1580 hunk.type = HUNK_TYPE_VSPOB_REMOVE;
1581 break;
1582 case HUNK_TYPE_VSPOB_REMOVE:
1583 hunk.type = HUNK_TYPE_VSPOB_ADD;
1584 break;
1585
1586 case HUNK_TYPE_JUMP_ADD:
1587 hunk.type = HUNK_TYPE_JUMP_REMOVE;
1588 break;
1589 case HUNK_TYPE_JUMP_REMOVE:
1590 hunk.type = HUNK_TYPE_JUMP_ADD;
1591 break;
1592
1593 case HUNK_TYPE_SSYS_BACKGROUND:
1594 hunk.type = HUNK_TYPE_SSYS_BACKGROUND_REVERT;
1595 break;
1596 case HUNK_TYPE_SSYS_FEATURES:
1597 hunk.type = HUNK_TYPE_SSYS_FEATURES_REVERT;
1598 break;
1599
1600 case HUNK_TYPE_TECH_ADD:
1601 hunk.type = HUNK_TYPE_TECH_REMOVE;
1602 break;
1603 case HUNK_TYPE_TECH_REMOVE:
1604 hunk.type = HUNK_TYPE_TECH_ADD;
1605 break;
1606
1607 case HUNK_TYPE_SPOB_FACTION:
1608 hunk.type = HUNK_TYPE_SPOB_FACTION_REMOVE;
1609 break;
1610
1611 case HUNK_TYPE_SPOB_POPULATION:
1612 hunk.type = HUNK_TYPE_SPOB_POPULATION_REMOVE;
1613 break;
1614
1615 case HUNK_TYPE_SPOB_DISPLAYNAME:
1616 hunk.type = HUNK_TYPE_SPOB_DISPLAYNAME_REVERT;
1617 break;
1618
1619 case HUNK_TYPE_SPOB_DESCRIPTION:
1620 hunk.type = HUNK_TYPE_SPOB_DESCRIPTION_REVERT;
1621 break;
1622
1623 case HUNK_TYPE_SPOB_BAR:
1624 hunk.type = HUNK_TYPE_SPOB_BAR_REVERT;
1625 break;
1626
1627 case HUNK_TYPE_SPOB_SERVICE_ADD:
1628 hunk.type = HUNK_TYPE_SPOB_SERVICE_REMOVE;
1629 break;
1630 case HUNK_TYPE_SPOB_SERVICE_REMOVE:
1631 hunk.type = HUNK_TYPE_SPOB_SERVICE_ADD;
1632 break;
1633
1634 case HUNK_TYPE_SPOB_NOMISNSPAWN_ADD:
1635 hunk.type = HUNK_TYPE_SPOB_NOMISNSPAWN_REMOVE;
1636 break;
1637 case HUNK_TYPE_SPOB_NOMISNSPAWN_REMOVE:
1638 hunk.type = HUNK_TYPE_SPOB_NOMISNSPAWN_ADD;
1639 break;
1640
1641 case HUNK_TYPE_SPOB_TECH_ADD:
1642 hunk.type = HUNK_TYPE_SPOB_TECH_REMOVE;
1643 break;
1644 case HUNK_TYPE_SPOB_TECH_REMOVE:
1645 hunk.type = HUNK_TYPE_SPOB_TECH_ADD;
1646 break;
1647
1648 case HUNK_TYPE_SPOB_TAG_ADD:
1649 hunk.type = HUNK_TYPE_SPOB_TAG_REMOVE;
1650 break;
1651 case HUNK_TYPE_SPOB_TAG_REMOVE:
1652 hunk.type = HUNK_TYPE_SPOB_TAG_ADD;
1653 break;
1654
1655 case HUNK_TYPE_SPOB_SPACE:
1656 hunk.type = HUNK_TYPE_SPOB_SPACE_REVERT;
1657 break;
1658
1659 case HUNK_TYPE_SPOB_EXTERIOR:
1660 hunk.type = HUNK_TYPE_SPOB_EXTERIOR_REVERT;
1661 break;
1662
1663 case HUNK_TYPE_SPOB_LUA:
1664 hunk.type = HUNK_TYPE_SPOB_LUA_REVERT;
1665 break;
1666
1667 case HUNK_TYPE_FACTION_VISIBLE:
1668 hunk.type = HUNK_TYPE_FACTION_INVISIBLE;
1669 break;
1670 case HUNK_TYPE_FACTION_INVISIBLE:
1671 hunk.type = HUNK_TYPE_FACTION_VISIBLE;
1672 break;
1673
1674 case HUNK_TYPE_FACTION_ALLY:
1675 hunk.type = HUNK_TYPE_FACTION_REALIGN;
1676 break;
1677 case HUNK_TYPE_FACTION_ENEMY:
1678 hunk.type = HUNK_TYPE_FACTION_REALIGN;
1679 break;
1680 case HUNK_TYPE_FACTION_NEUTRAL:
1681 hunk.type = HUNK_TYPE_FACTION_REALIGN;
1682 break;
1683
1684 default:
1685 WARN(_("Unknown Hunk type '%d'."), hunk.type);
1686 continue;
1687 }
1688
1689 if (diff_patchHunk(&hunk))
1690 WARN(_("Failed to remove hunk type '%d'."), hunk.type);
1691 }
1692
1693 diff_cleanup(diff);
1694 array_erase( &diff_stack, diff, &diff[1] );
1695 return 0;
1696}
1697
1703static void diff_cleanup( UniDiff_t *diff )
1704{
1705 free(diff->name);
1706 for (int i=0; i<array_size(diff->applied); i++)
1707 diff_cleanupHunk(&diff->applied[i]);
1708 array_free(diff->applied);
1709 for (int i=0; i<array_size(diff->failed); i++)
1710 diff_cleanupHunk(&diff->failed[i]);
1711 array_free(diff->failed);
1712 memset(diff, 0, sizeof(UniDiff_t));
1713}
1714
1720static void diff_cleanupHunk( UniHunk_t *hunk )
1721{
1722 free(hunk->target.u.name);
1723 hunk->target.u.name = NULL;
1724
1725 switch (hunk->type) { /* TODO: Does it really matter? */
1726 case HUNK_TYPE_SPOB_ADD:
1727 case HUNK_TYPE_SPOB_REMOVE:
1728 case HUNK_TYPE_VSPOB_ADD:
1729 case HUNK_TYPE_VSPOB_REMOVE:
1730 case HUNK_TYPE_JUMP_ADD:
1731 case HUNK_TYPE_JUMP_REMOVE:
1732 case HUNK_TYPE_SSYS_BACKGROUND:
1733 case HUNK_TYPE_SSYS_FEATURES:
1734 case HUNK_TYPE_TECH_ADD:
1735 case HUNK_TYPE_TECH_REMOVE:
1736 case HUNK_TYPE_SPOB_FACTION:
1737 case HUNK_TYPE_SPOB_FACTION_REMOVE:
1738 case HUNK_TYPE_SPOB_DISPLAYNAME:
1739 case HUNK_TYPE_SPOB_DISPLAYNAME_REVERT:
1740 case HUNK_TYPE_SPOB_DESCRIPTION:
1741 case HUNK_TYPE_SPOB_DESCRIPTION_REVERT:
1742 case HUNK_TYPE_SPOB_TECH_ADD:
1743 case HUNK_TYPE_SPOB_TECH_REMOVE:
1744 case HUNK_TYPE_SPOB_TAG_ADD:
1745 case HUNK_TYPE_SPOB_TAG_REMOVE:
1746 case HUNK_TYPE_SPOB_BAR:
1747 case HUNK_TYPE_SPOB_BAR_REVERT:
1748 case HUNK_TYPE_SPOB_SPACE:
1749 case HUNK_TYPE_SPOB_SPACE_REVERT:
1750 case HUNK_TYPE_SPOB_EXTERIOR:
1751 case HUNK_TYPE_SPOB_EXTERIOR_REVERT:
1752 case HUNK_TYPE_SPOB_LUA:
1753 case HUNK_TYPE_SPOB_LUA_REVERT:
1754 case HUNK_TYPE_FACTION_VISIBLE:
1755 case HUNK_TYPE_FACTION_INVISIBLE:
1756 case HUNK_TYPE_FACTION_ALLY:
1757 case HUNK_TYPE_FACTION_ENEMY:
1758 case HUNK_TYPE_FACTION_NEUTRAL:
1759 case HUNK_TYPE_FACTION_REALIGN:
1760 free(hunk->u.name);
1761 hunk->u.name = NULL;
1762 break;
1763
1764 default:
1765 break;
1766 }
1767 memset( hunk, 0, sizeof(UniHunk_t) );
1768}
1769
1776int diff_save( xmlTextWriterPtr writer )
1777{
1778 xmlw_startElem(writer,"diffs");
1779 if (diff_stack != NULL) {
1780 for (int i=0; i<array_size(diff_stack); i++) {
1781 UniDiff_t *diff = &diff_stack[i];
1782
1783 xmlw_elem(writer, "diff", "%s", diff->name);
1784 }
1785 }
1786 xmlw_endElem(writer); /* "diffs" */
1787 return 0;
1788
1789}
1790
1797int diff_load( xmlNodePtr parent )
1798{
1799 xmlNodePtr node;
1800 int defer = diff_universe_defer;
1801
1802 /* Don't update universe here. */
1805 diff_clear();
1806 diff_universe_defer = defer;
1807
1808 node = parent->xmlChildrenNode;
1809 do {
1810 if (xml_isNode(node,"diffs")) {
1811 xmlNodePtr cur = node->xmlChildrenNode;
1812 do {
1813 if ( xml_isNode( cur, "diff" ) ) {
1814 char *diffName = xml_get( cur );
1815 if ( diffName == NULL ) {
1816 WARN( _( "Expected node \"diff\" to contain the name of a unidiff. Was empty." ) );
1817 continue;
1818 }
1819 diff_applyInternal( diffName, 0 );
1820 }
1821 } while (xml_nextNode(cur));
1822 }
1823 } while (xml_nextNode(node));
1824
1825 /* Update as necessary. */
1827
1828 return 0;
1829}
1830
1835{
1836 Pilot *const* pilots;
1837
1839 return 0;
1840
1841 /* Update presences, then safelanes. */
1844
1845 /* Re-compute the economy. */
1848
1849 /* Have to update planet graphics if necessary. */
1850 if (cur_system != NULL) {
1853 }
1854
1855 /* Have to pilot targetting just in case. */
1856 pilots = pilot_getAll();
1857 for (int i=0; i<array_size(pilots); i++) {
1858 Pilot *p = pilots[i];
1859 p->nav_spob = -1;
1860 p->nav_hyperspace = -1;
1861
1862 /* Hack in case the pilot was actively jumping, this won't run the hook,
1863 * but I guess it's too much effort to properly fix for a situation that
1864 * will likely never happen. */
1865 if (!pilot_isWithPlayer(p) && pilot_isFlag( p, PILOT_HYPERSPACE ))
1866 pilot_delete(p);
1867 else
1868 pilot_rmFlag( p, PILOT_HYPERSPACE ); /* Corner case player, just have it not crash and randomly stop the jump. */
1869
1870 /* Have to reset in the case of starting. */
1871 if (pilot_isFlag( p, PILOT_HYP_BEGIN ) ||
1872 pilot_isFlag( p, PILOT_HYP_BRAKE ) ||
1873 pilot_isFlag( p, PILOT_HYP_PREP ))
1875 }
1876
1877 /* Player has to update the GUI so we send again. */
1880
1882 return 1;
1883}
1884
1890void unidiff_universeDefer( int enable )
1891{
1892 int defer = diff_universe_defer;
1893 diff_universe_defer = enable;
1894 if (defer && !enable)
1896}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition array.h:102
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:140
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:119
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
Definition array.h:149
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:129
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void economy_initialiseCommodityPrices(void)
Initialises commodity prices for the sinusoidal economy model.
Definition economy.c:859
int economy_execQueued(void)
Calls economy_refresh if an economy update is queued.
Definition economy.c:483
void faction_rmAlly(int f, int o)
Removes an ally from the faction's allies list.
Definition faction.c:703
void faction_rmEnemy(int f, int o)
Removes an enemy from the faction's enemies list.
Definition faction.c:610
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition faction.c:1227
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition faction.c:306
int faction_setInvisible(int id, int state)
Sets the faction's invisible state.
Definition faction.c:258
void faction_addAlly(int f, int o)
Adds an ally to the faction's allies list.
Definition faction.c:657
void faction_addEnemy(int f, int o)
Adds an enemy to the faction's enemies list.
Definition faction.c:564
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:184
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition faction.c:1253
Header file with generic functions and naev-specifics.
#define PATH_MAX
Definition naev.h:50
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition ndata.c:231
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition nxml.c:75
void pilot_hyperspaceAbort(Pilot *p)
Stops the pilot from hyperspacing.
Definition pilot.c:2857
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
Definition pilot.c:94
void pilot_delete(Pilot *p)
Deletes a pilot.
Definition pilot.c:2687
void player_targetHyperspaceSet(int id, int nomsg)
Sets the player's hyperspace target.
Definition player.c:1821
void player_targetSpobSet(int id)
Sets the player's target spob.
Definition player.c:1485
static const double d[]
Definition rng.c:273
void safelanes_recalculate(void)
Update the safe lane locations in response to the universe changing (e.g., diff applied).
Definition safelanes.c:252
void space_reconstructPresences(void)
Reset the presence of all systems.
Definition space.c:4263
int system_addJumpDiff(StarSystem *sys, xmlNodePtr node)
Adds a jump point to a star system from a diff.
Definition space.c:2606
void space_gfxUnload(StarSystem *sys)
Unloads all the graphics for a star system.
Definition space.c:2127
int spob_luaInit(Spob *spob)
Updatse the spob's internal Lua stuff.
Definition space.c:1997
int spob_getService(const char *name)
Converts name to spob service flag.
Definition space.c:186
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition space.c:1051
int system_addVirtualSpob(StarSystem *sys, const char *spobname)
Adds a virtual spob to a system.
Definition space.c:2545
int system_rmJump(StarSystem *sys, const char *jumpname)
Removes a jump point from a star system.
Definition space.c:2625
int spob_setFaction(Spob *p, int faction)
Changes the spobs faction.
Definition space.c:349
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition space.c:960
int spob_rmService(Spob *p, int service)
Removes a service from a spob.
Definition space.c:418
StarSystem * cur_system
Definition space.c:106
int system_addSpob(StarSystem *sys, const char *spobname)
Adds a spob to a star system.
Definition space.c:2452
int system_rmVirtualSpob(StarSystem *sys, const char *spobname)
Removes a virtual spob from a system.
Definition space.c:2569
int spob_addService(Spob *p, int service)
Removes a service from a spob.
Definition space.c:376
const char * spob_getServiceName(int service)
Gets the (English) name for a service code.
Definition space.c:167
void space_gfxLoad(StarSystem *sys)
Loads all the graphics for a star system.
Definition space.c:2116
int system_rmSpob(StarSystem *sys, const char *spobname)
Removes a spob from a star system.
Definition space.c:2493
The representation of an in-game pilot.
Definition pilot.h:217
int devmode
Definition conf.h:157
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:89
Universe diff filepath list.
Definition unidiff.c:36
char * name
Definition unidiff.c:37
char * filename
Definition unidiff.c:38
Represents each Universe Diff.
Definition unidiff.c:147
UniHunk_t * failed
Definition unidiff.c:150
char * name
Definition unidiff.c:148
UniHunk_t * applied
Definition unidiff.c:149
Represents the hunk's target.
Definition unidiff.c:60
UniHunkTargetType_t type
Definition unidiff.c:61
union UniHunkTarget_t::@16 u
char * name
Definition unidiff.c:63
Represents a single hunk in the diff.
Definition unidiff.c:127
UniHunkType_t type
Definition unidiff.c:130
xmlNodePtr node
Definition unidiff.c:131
union UniHunk_t::@17 u
UniHunkTarget_t target
Definition unidiff.c:128
int tech_rmItemTech(tech_group_t *tech, const char *value)
Removes an item from a tech.
Definition tech.c:488
tech_group_t * tech_groupCreate(void)
Creates a tech group.
Definition tech.c:176
int tech_rmItem(const char *name, const char *value)
Removes a tech item.
Definition tech.c:507
int tech_addItemTech(tech_group_t *tech, const char *value)
Adds an item to a tech.
Definition tech.c:468
int tech_addItem(const char *name, const char *value)
Adds an item to a tech.
Definition tech.c:434
static UniDiffData_t * diff_available
Definition unidiff.c:40
static int diff_checkUpdateUniverse(void)
Checks and updates the universe if necessary.
Definition unidiff.c:1834
UniHunkType_t
Represents the different type of hunk actions.
Definition unidiff.c:72
static UniDiff_t * diff_get(const char *name)
Gets a diff by name.
Definition unidiff.c:270
static UniDiff_t * diff_stack
Definition unidiff.c:156
int diff_load(xmlNodePtr parent)
Loads the diffs.
Definition unidiff.c:1797
void unidiff_universeDefer(int enable)
Sets whether or not to defer universe change stuff.
Definition unidiff.c:1890
static int diff_patchTech(UniDiff_t *diff, xmlNodePtr node)
Patches a tech.
Definition unidiff.c:492
static UniDiff_t * diff_newDiff(void)
Creates a new UniDiff_t for usage.
Definition unidiff.c:1552
static int diff_patchHunk(UniHunk_t *hunk)
Applies a hunk and adds it to the diff.
Definition unidiff.c:1114
int diff_apply(const char *name)
Applies a diff to the universe.
Definition unidiff.c:284
void diff_remove(const char *name)
Removes a diff from the universe.
Definition unidiff.c:1507
static int diff_patch(xmlNodePtr parent)
Actually applies a diff in XML node form.
Definition unidiff.c:910
static void diff_cleanup(UniDiff_t *diff)
Cleans up a diff.
Definition unidiff.c:1703
void diff_clear(void)
Removes all active diffs. (Call before economy_destroy().)
Definition unidiff.c:1522
static int diff_applyInternal(const char *name, int oneshot)
Applies a diff to the universe.
Definition unidiff.c:296
int diff_loadAvailable(void)
Loads available universe diffs.
Definition unidiff.c:199
static void diff_cleanupHunk(UniHunk_t *hunk)
Cleans up a hunk.
Definition unidiff.c:1720
static int diff_patchFaction(UniDiff_t *diff, xmlNodePtr node)
Patches a faction.
Definition unidiff.c:811
static int diff_patchSpob(UniDiff_t *diff, xmlNodePtr node)
Patches a spob.
Definition unidiff.c:561
static int diff_universe_changed
Definition unidiff.c:159
static void diff_hunkSuccess(UniDiff_t *diff, UniHunk_t *hunk)
Adds a hunk to the applied list.
Definition unidiff.c:1493
static int diff_patchSystem(UniDiff_t *diff, xmlNodePtr node)
Patches a system.
Definition unidiff.c:344
static int diff_universe_defer
Definition unidiff.c:160
void diff_free(void)
Clean up after diff_loadAvailable().
Definition unidiff.c:1535
static int diff_removeDiff(UniDiff_t *diff)
Removes a diff.
Definition unidiff.c:1566
int diff_save(xmlTextWriterPtr writer)
Saves the active diffs.
Definition unidiff.c:1776
int diff_isApplied(const char *name)
Checks if a diff is currently applied.
Definition unidiff.c:257
UniHunkTargetType_t
Represents the possible hunk targets.
Definition unidiff.c:47
static void diff_hunkFailed(UniDiff_t *diff, UniHunk_t *hunk)
Adds a hunk to the failed list.
Definition unidiff.c:1478