source: git/src/netartic.c @ 36efb03

RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-data
Last change on this file since 36efb03 was 36efb03, checked in by Olly Betts <olly@…>, 9 years ago

src/: Add more TRANSLATORS comments.

  • Property mode set to 100644
File size: 14.5 KB
RevLine 
[ff6cfe1]1/* netartic.c
[e2152f6]2 * Split up network at articulation points
[736f7df]3 * Copyright (C) 1993-2003,2005,2012,2014 Olly Betts
[846746e]4 *
[89231c4]5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
[846746e]9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[89231c4]12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
[846746e]14 *
[89231c4]15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
[ecbc6c18]17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
[e2152f6]18 */
19
[1db9f16]20#if 0
21# define DEBUG_INVALID 1
22# define DEBUG_ARTIC
23#endif
24
[e2152f6]25#ifdef HAVE_CONFIG_H
26# include <config.h>
27#endif
28
29#include "debug.h"
30#include "cavern.h"
31#include "filename.h"
[335f37a]32#include "listpos.h"
[e2152f6]33#include "message.h"
[e329f0f]34#include "netartic.h"
[e2152f6]35#include "netbits.h"
36#include "matrix.h"
37#include "out.h"
38
[1db9f16]39/* We want to split station list into a list of components, each of which
40 * consists of a list of "articulations" - the first has all the fixed points
41 * in that component, and the others attach sequentially to produce the whole
42 * component
43 */
44
45typedef struct articulation {
46   struct articulation *next;
47   node *stnlist;
48} articulation;
49
50typedef struct component {
51   struct component *next;
52   articulation *artic;
53} component;
54
55static component *component_list;
56
57static articulation *articulation_list;
58
59static node *artlist;
60
[36246b7]61static node *fixedlist;
[e2152f6]62
[84c60fc]63static long colour;
[e2152f6]64
65/* The goto iter/uniter avoids using recursion which could lead to stack
[1db9f16]66 * overflow.  Instead we use 5 bytes of memory per iteration in malloc-ed
67 * blocks which will probably use an awful lot less memory on most platforms.
[e2152f6]68 */
69
[84c60fc]70/* This is the number of station in stnlist which is a ceiling on how
[5cfa42c]71 * deep visit will recurse */
[84c60fc]72static unsigned long cMaxVisits;
73
[0d56f62]74static unsigned char *dirn_stack = NULL;
[1db9f16]75static long *min_stack = NULL;
[028c6db]76
[67508f0]77static unsigned long
[028c6db]78visit(node *stn, int back)
[421b7d2]79{
[eb18f4d]80   long min_colour;
[e2152f6]81   int i;
[0d56f62]82   unsigned long tos = 0;
[4c07c51]83   SVX_ASSERT(dirn_stack && min_stack);
[1db9f16]84#ifdef DEBUG_ARTIC
85   printf("visit(%p, %d) called\n", stn, back);
86#endif
[028c6db]87
[e2152f6]88iter:
[0d56f62]89   min_colour = stn->colour = ++colour;
[1db9f16]90#ifdef DEBUG_ARTIC
91   printf("visit: stn [%p] ", stn);
92   print_prefix(stn->name);
[4bed003]93   printf(" set to colour %ld -> min\n", colour);
[1db9f16]94#endif
[028c6db]95   for (i = 0; i <= 2 && stn->leg[i]; i++) {
[4bed003]96      if (i != back) {
[8c2ffa4]97         node *to = stn->leg[i]->l.to;
[0d56f62]98         long col = to->colour;
99         if (col == 0) {
[4c07c51]100            SVX_ASSERT(tos < cMaxVisits);
[b9ef0d8]101            dirn_stack[tos] = back;
[0d56f62]102            min_stack[tos] = min_colour;
103            tos++;
[b9ef0d8]104            back = reverse_leg_dirn(stn->leg[i]);
[0d56f62]105            stn = to;
106            goto iter;
[e2152f6]107uniter:
[4c07c51]108            SVX_ASSERT(tos > 0);
[0d56f62]109            --tos;
[4bed003]110            i = reverse_leg_dirn(stn->leg[back]);
[b9ef0d8]111            to = stn;
112            stn = to->leg[back]->l.to;
113            back = dirn_stack[tos];
[0d56f62]114            if (min_stack[tos] < min_colour) min_colour = min_stack[tos];
[1db9f16]115
116#ifdef DEBUG_ARTIC
[b9ef0d8]117            printf("unwind: stn [%p] ", stn);
[1db9f16]118            print_prefix(stn->name);
[b9ef0d8]119            printf(" colour %d, min %d, station after %d\n", stn->colour,
120                   min_colour, to->colour);
121            printf("Putting stn ");
122            print_prefix(to->name);
[1db9f16]123            printf(" on artlist\n");
124#endif
[b9ef0d8]125            remove_stn_from_list(&stnlist, to);
126            add_stn_to_list(&artlist, to);
[421b7d2]127
[b9ef0d8]128            if (to->colour <= min_colour) {
[1db9f16]129               articulation *art;
130
[b9ef0d8]131               min_colour = to->colour;
[421b7d2]132
[0d56f62]133               /* FIXME: note down leg (<-), remove and replace:
134                *                 /\   /        /\
135                * [fixed point(s)]  *-*  -> [..]  )
136                *                 \/   \        \/
[b9ef0d8]137                *                 stn to
[0d56f62]138                */
139               /* flag leg as an articulation for loop error reporting */
[b9ef0d8]140               to->leg[dirn_stack[tos]]->l.reverse |= FLAG_ARTICULATION;
141               stn->leg[i]->l.reverse |= FLAG_ARTICULATION;
[1db9f16]142
143               /* start new articulation */
144               art = osnew(articulation);
145               art->stnlist = artlist;
146               art->next = articulation_list;
147               articulation_list = art;
148               artlist = NULL;
149
150#ifdef DEBUG_ARTIC
151               printf("Articulate *-");
152               print_prefix(stn->name);
[b9ef0d8]153               printf("-");
154               print_prefix(to->name);
[1db9f16]155               printf("-...\n");
156#endif
[0d56f62]157            }
158         } else {
159            /* back edge case */
160            if (col < 0) {
161               /* we've found a fixed point */
162               col = -col;
163               to->colour = col;
[21c226e]164#if 0
165               /* Removing this solves Graham Mullan's problem and makes more
166                * sense since it means we'll recheck this point for further
167                * legs. */
[1db9f16]168#ifdef DEBUG_ARTIC
169               printf("Putting FOUND FIXED stn ");
170               print_prefix(to->name);
171               printf(" on artlist\n");
172#endif
[0d56f62]173               remove_stn_from_list(&fixedlist, to);
[1db9f16]174               add_stn_to_list(&artlist, to);
[21c226e]175#endif
[0d56f62]176            }
[421b7d2]177
[0d56f62]178            if (col < min_colour) min_colour = col;
[421b7d2]179         }
[e2152f6]180      }
181   }
[b9ef0d8]182
[4c07c51]183   SVX_ASSERT(!stn->leg[0] || stn->leg[0]->l.to->colour > 0);
184   SVX_ASSERT(!stn->leg[1] || stn->leg[1]->l.to->colour > 0);
185   SVX_ASSERT(!stn->leg[2] || stn->leg[2]->l.to->colour > 0);
[421b7d2]186
[0d56f62]187   if (tos > 0) goto uniter;
[402c753]188
[1db9f16]189#ifdef DEBUG_ARTIC
190   printf("Putting stn ");
191   print_prefix(stn->name);
192   printf(" on artlist\n");
193#endif
194   remove_stn_from_list(&stnlist, stn);
195   add_stn_to_list(&artlist, stn);
[eb18f4d]196   return min_colour;
[e2152f6]197}
198
199extern void
200articulate(void)
201{
202   node *stn, *stnStart;
[6876c8a]203   int i;
[402c753]204   long cFixed;
[c30a8f3]205
[1db9f16]206   component_list = NULL;
207   articulation_list = NULL;
208   artlist = NULL;
[36246b7]209   fixedlist = NULL;
[cb3d1e2]210
[e2152f6]211   /* find articulation points and components */
212   colour = 0;
213   stnStart = NULL;
[84c60fc]214   cMaxVisits = 0;
[e2152f6]215   FOR_EACH_STN(stn, stnlist) {
216      if (fixed(stn)) {
217         remove_stn_from_list(&stnlist, stn);
218         add_stn_to_list(&fixedlist, stn);
[0d56f62]219         colour++;
220         stn->colour = -colour;
[1db9f16]221#ifdef DEBUG_ARTIC
222         printf("Putting stn ");
223         print_prefix(stn->name);
224         printf(" on fixedlist\n");
225#endif
[e2152f6]226      } else {
[0d56f62]227         cMaxVisits++;
[e2152f6]228         stn->colour = 0;
229      }
230   }
[0d56f62]231   dirn_stack = osmalloc(cMaxVisits);
232   min_stack = osmalloc(cMaxVisits * sizeof(long));
[84c60fc]233
[f5627353]234   /* fixedlist can be NULL here if we've had a *solve followed by survey
235    * which is all hanging. */
[e2152f6]236   cFixed = colour;
[f5627353]237   while (fixedlist) {
[6876c8a]238      int c;
[f5627353]239      stnStart = fixedlist;
[e2152f6]240      stn = stnStart;
[028c6db]241
[39882a3e]242      /* see if this is a fresh component - it may not be, we may be
243       * processing the other way from a fixed point cut-line */
[cb3d1e2]244      if (stn->colour < 0) {
[1db9f16]245#ifdef DEBUG_ARTIC
246         printf("new component\n");
247#endif
[028c6db]248         stn->colour = -stn->colour; /* fixed points are negative until we colour from them */
249         cComponents++;
[1db9f16]250
251         /* FIXME: logic to count components isn't the same as the logic
252          * to start a new one - we should start a new one for a fixed point
253          * cut-line (see below) */
254         if (artlist) {
255             component *comp;
256             articulation *art;
257
258             art = osnew(articulation);
259             art->stnlist = artlist;
260             art->next = articulation_list;
261             articulation_list = art;
262             artlist = NULL;
263
264             comp = osnew(component);
265             comp->next = component_list;
266             comp->artic = articulation_list;
267             component_list = comp;
268             articulation_list = NULL;
269         }
270
271#ifdef DEBUG_ARTIC
272         print_prefix(stn->name);
273         printf(" [%p] is root of component %ld\n", stn, cComponents);
274         printf(" and colour = %d/%d\n", stn->colour, cFixed);
275#endif
[647407d]276      }
[028c6db]277
[6876c8a]278      c = 0;
279      for (i = 0; i <= 2 && stn->leg[i]; i++) {
280         node *stn2 = stn->leg[i]->l.to;
[028c6db]281         if (stn2->colour < 0) {
282            stn2->colour = -stn2->colour;
283         } else if (stn2->colour == 0) {
284            /* Special case to check if start station is an articulation point
285             * which it is iff we have to colour from it in more than one dirn
[402c753]286             *
287             * We're looking for articulation legs - these are those where
288             * colouring from here doesn't reach a fixed point (including
289             * stn - the fixed point we've started from)
[ded4ba4]290             *
291             * FIXME: this is a "fixed point cut-line" case where we could
292             * start a new component.
[028c6db]293             */
[402c753]294            long col = visit(stn2, reverse_leg_dirn(stn->leg[i]));
[1db9f16]295#ifdef DEBUG_ARTIC
296            print_prefix(stn->name);
297            printf(" -> ");
298            print_prefix(stn2->name);
299            printf(" col %d cFixed %d\n", col, cFixed);
300#endif
[4f5a35a]301            if (col > cFixed) {
[1db9f16]302                /* start new articulation - FIXME - overeager */
303                articulation *art = osnew(articulation);
304                art->stnlist = artlist;
305                art->next = articulation_list;
306                articulation_list = art;
307                artlist = NULL;
[4f5a35a]308                c |= 1 << i;
309            }
[402c753]310         }
311      }
[84c60fc]312
[1db9f16]313      switch (c) {
314       /* had to colour in 2 or 3 directions from start point */
315       case 3: case 5: case 6: case 7:
316#ifdef DEBUG_ARTIC
317         print_prefix(stn->name);
318         printf(" is a special case start articulation point [%d]\n", c);
319#endif
[5cfa42c]320         for (i = 0; i <= 2 && stn->leg[i]; i++) {
[402c753]321            if (TSTBIT(c, i)) {
[5cfa42c]322               /* flag leg as an articulation for loop error reporting */
[402c753]323               stn->leg[i]->l.reverse |= FLAG_ARTICULATION;
[1db9f16]324#ifdef DEBUG_ARTIC
325               print_prefix(stn->leg[i]->l.to->name);
326               putnl();
327#endif
328               reverse_leg(stn->leg[i])->l.reverse |= FLAG_ARTICULATION;
[402c753]329            }
330         }
[6876c8a]331      }
[028c6db]332
[1db9f16]333#ifdef DEBUG_ARTIC
334      printf("Putting FIXED stn ");
335      print_prefix(stn->name);
336      printf(" on artlist\n");
337#endif
[028c6db]338      remove_stn_from_list(&fixedlist, stn);
[1db9f16]339      add_stn_to_list(&artlist, stn);
[5cfa42c]340
[1db9f16]341      if (stnStart->colour == 1) {
342#ifdef DEBUG_ARTIC
343         printf("%ld components\n",cComponents);
344#endif
345         break;
346      }
[e2152f6]347   }
[cb3d1e2]348
[e6cfe52]349   osfree(dirn_stack);
350   dirn_stack = NULL;
351   osfree(min_stack);
352   min_stack = NULL;
353
[1db9f16]354   if (artlist) {
355      articulation *art = osnew(articulation);
356      art->stnlist = artlist;
357      art->next = articulation_list;
358      articulation_list = art;
359      artlist = NULL;
360   }
361   if (articulation_list) {
362      component *comp = osnew(component);
363      comp->next = component_list;
364      comp->artic = articulation_list;
365      component_list = comp;
366      articulation_list = NULL;
367   }
[421b7d2]368
[e6cfe52]369   if (stnlist) {
[a2c33ae]370      /* Any stations still in stnlist are unfixed, which is means we have
371       * one or more hanging surveys.
372       *
373       * The cause of the problem is pretty likely to be a typo, so run the
[335f37a]374       * checks which report errors and warnings about issues which such a
375       * typo is likely to result in.
376       */
377      check_node_stats();
378
[e6cfe52]379      /* Actually this error is fatal, but we want to list the survey
380       * stations which aren't connected, so we report it as an error
381       * and die after listing them...
382       */
383      bool fNotAttached = fFalse;
[36efb03]384      /* TRANSLATORS: At the end of processing (or if a *SOLVE command is used)
385       * cavern will issue this error if there are any sections of the survey
386       * network which are hanging. */
[e6cfe52]387      error(/*Survey not all connected to fixed stations*/45);
388      FOR_EACH_STN(stn, stnlist) {
[a2c33ae]389         /* Anonymous stations must be at the end of a trailing traverse (since
390          * the same anonymous station can't be referred to more than once),
391          * and trailing traverses have been removed at this point.
392          */
393         SVX_ASSERT(!TSTBIT(stn->name->sflags, SFLAGS_ANON));
[ff6cfe1]394         if (stn->name->ident) {
[e6cfe52]395            if (!fNotAttached) {
396               fNotAttached = fTrue;
[736f7df]397               /* TRANSLATORS: Here "station" is a survey station, not a train
398                * station. */
[e6cfe52]399               puts(msg(/*The following survey stations are not attached to a fixed point:*/71));
400            }
401            puts(sprint_prefix(stn->name));
402         }
403      }
404      exit(EXIT_FAILURE);
405   }
[b9ef0d8]406
407   {
408      component *comp;
409
410#ifdef DEBUG_ARTIC
411      printf("\nDump of %d components:\n", cComponents);
412#endif
413      for (comp = component_list; comp; comp = comp->next) {
414         node *list = NULL, *listend = NULL;
[fefd721]415         articulation *art;
[b9ef0d8]416#ifdef DEBUG_ARTIC
417         printf("Component:\n");
418#endif
[4c07c51]419         SVX_ASSERT(comp->artic);
[b9ef0d8]420         for (art = comp->artic; art; art = art->next) {
421#ifdef DEBUG_ARTIC
422            printf("  Articulation (%p):\n", art->stnlist);
423#endif
[4c07c51]424            SVX_ASSERT(art->stnlist);
[b9ef0d8]425            if (listend) {
426               listend->next = art->stnlist;
427               art->stnlist->prev = listend;
[421b7d2]428            } else {
[b9ef0d8]429               list = art->stnlist;
430            }
[421b7d2]431
[b9ef0d8]432            FOR_EACH_STN(stn, art->stnlist) {
433#ifdef DEBUG_ARTIC
434               printf("    %d %p (", stn->colour, stn);
435               print_prefix(stn->name);
436               printf(")\n");
437#endif
438               listend = stn;
[421b7d2]439            }
440         }
[b9ef0d8]441#ifdef DEBUG_ARTIC
442         putnl();
443         FOR_EACH_STN(stn, list) {
444            printf("MX: %c %p (", fixed(stn)?'*':' ', stn);
445            print_prefix(stn->name);
446            printf(")\n");
447         }
448#endif
449         solve_matrix(list);
450#ifdef DEBUG_ARTIC
451         putnl();
452         FOR_EACH_STN(stn, list) {
453            printf("%c %p (", fixed(stn)?'*':' ', stn);
454            print_prefix(stn->name);
455            printf(")\n");
456         }
457#endif
458         listend->next = stnlist;
459         if (stnlist) stnlist->prev = listend;
460         stnlist = list;
461      }
462#ifdef DEBUG_ARTIC
463      printf("done articulating\n");
464#endif
465   }
466
[64d37a3]467#ifdef DEBUG_ARTIC
[5cfa42c]468   /* test articulation */
469   FOR_EACH_STN(stn, stnlist) {
470      int d;
471      int f;
[c23c626]472      if (stn->name->ident && TSTBIT(stn->name->sflags, SFLAGS_FIXED)) {
[5cfa42c]473         stn->colour = 1;
474      } else {
475         stn->colour = 0;
476      }
477      f = 0;
478      for (d = 0; d < 3; d++) {
479         if (stn->leg[d]) {
480            if (f) {
481               printf("awooga - gap in legs\n");
482            }
483            if (stn->leg[d]->l.reverse & FLAG_ARTICULATION) {
484               if (!(reverse_leg(stn->leg[d])->l.reverse & FLAG_ARTICULATION)) {
485                  printf("awooga - bad articulation (one way art)\n");
486               }
[eb18f4d]487            } else {
[5cfa42c]488               if (reverse_leg(stn->leg[d])->l.reverse & FLAG_ARTICULATION) {
489                  printf("awooga - bad articulation (one way art)\n");
490               }
[eb18f4d]491            }
[5cfa42c]492         } else {
493            f = 1;
494         }
495      }
496   }
[eb18f4d]497
[5cfa42c]498   colour = 2;
499
500   while (1) {
501      int c;
[421b7d2]502      int f;
[5cfa42c]503      do {
504         c = 0;
505         FOR_EACH_STN(stn, stnlist) {
506            int d;
507            f = 0;
508            for (d = 0; d < 3; d++) {
509               if (stn->leg[d]) {
510                  node *stn2 = stn->leg[d]->l.to;
511                  if (f) {
512                     printf("awooga - gap in legs\n");
513                  }
514                  if (stn2->colour) {
515                     if (!(stn->leg[d]->l.reverse & FLAG_ARTICULATION)) {
516                        if (stn->colour == 0) {
517                           stn->colour = stn2->colour;
518                           c++;
519                        }
520                     }
521                  }
522               } else {
523                  f = 1;
524               }
[eb18f4d]525            }
526         }
[5cfa42c]527      } while (c);
[421b7d2]528
[5cfa42c]529      /* colour bits */
530      FOR_EACH_STN(stn, stnlist) {
531         if (stn->colour == 0) break;
[eb18f4d]532      }
[5cfa42c]533      if (!stn) break; /* all coloured */
[b57ec70]534
[5cfa42c]535      stn->colour = colour++;
536   }
[84c60fc]537
[c30a8f3]538   FOR_EACH_STN(stn, stnlist) {
[5cfa42c]539      int d;
540      int f;
541      f = 0;
542      for (d = 0; d < 3; d++) {
543         if (stn->leg[d]) {
544            if (f) {
545               printf("awooga - gap in legs\n");
546            }
[1db9f16]547#ifdef DEBUG_ARTIC
[5cfa42c]548            if (stn->leg[d]->l.reverse & FLAG_ARTICULATION) {
549               node *stn2 = stn->leg[d]->l.to;
[1db9f16]550               printf("art: %ld %ld [%p] ", stn->colour, stn2->colour, stn);
[5cfa42c]551               print_prefix(stn->name);
552               printf(" - [%p] ", stn2);
553               print_prefix(stn2->name);
554               printf("\n");
555            }
[1db9f16]556#endif
[5cfa42c]557         } else {
558            f = 1;
559         }
[e2152f6]560      }
561   }
562#endif
[4bed003]563   FOR_EACH_STN(stn, stnlist) {
[4c07c51]564      SVX_ASSERT(fixed(stn));
[4bed003]565   }
[e2152f6]566}
Note: See TracBrowser for help on using the repository browser.