chiark / gitweb /
hostside: hidrawconv: break out dispatch()
[trains.git] / hostside / trackloc.c
1 /*
2  */
3
4 #include <assert.h>
5
6 #include "realtime.h"
7
8 /*---------- constructors/initialisers ----------*/
9
10 void trackloc_set_maxinto(TrackLocation *tloc, Segment *seg, int backwards) {
11   tloc->seg= seg;
12   tloc->backwards= backwards;
13   tloc->remain= 0;
14 }
15
16 int trackloc_set_exactinto(TrackLocation *t, TrackAdvanceContext *c,
17                            Segment *seg, int backwards, int into) {
18   const SegPosCombInfo *pci;
19   int r;
20
21   t->seg= seg;
22   t->backwards= backwards;
23   t->remain= 0;
24
25   r= trackloc_getlink(t,c,&pci,0,-1);
26   if (r) return r;
27   assert(pci);
28   
29   t->remain= pci->dist - into;
30   return 0;
31 }
32
33 /*---------- enquirers ----------*/
34
35 int trackloc_getlink(TrackLocation *t, TrackAdvanceContext *c,
36                      const SegPosCombInfo **pci_r,
37                      const SegmentLinkInfo **link_r,
38                      MovPosComb mpc) {
39   const SegPosCombInfo *pci;
40   int r;
41
42   if (mpc<0)
43     mpc= t->seg->movposcomb;
44
45   if (c && c->getmovpos) {
46     r= c->getmovpos(t,c,&mpc);
47     if (r) return r;
48   }
49   if (mpc<0) {
50     if (pci_r) *pci_r=0;
51     if (link_r) *link_r=0;
52     return 0;
53   }
54   assert(mpc >= 0);
55   assert(mpc < t->seg->i->n_poscombs);
56 //fprintf(stderr,"trackloc_getlink returning %s %d %d\n",t->seg->i->pname,mpc,
57 //      t->backwards);
58   pci= &t->seg->i->poscombs[mpc];
59 //fprintf(stderr,"trackloc_getlink returning  %s\n",pci->pname);
60   if (pci_r) *pci_r= pci;
61   if (link_r) *link_r= &pci->link[t->backwards];
62   return 0;
63 }
64
65 /*---------- mutator ----------*/
66
67 static int nextseg(TrackLocation *t, TrackAdvanceContext *c,
68                    const SegPosCombInfo **pci_r,
69                    const SegmentLinkInfo **link_r,
70                    const TrackLocation *leaving) {
71   MovPosComb mpc_nego;
72   int r;
73
74   mpc_nego= t->seg->movposcomb;
75
76   if (c->nextseg) {
77     r= c->nextseg(t,c, &mpc_nego, leaving);
78     if (r) return r;
79   }
80
81   r= trackloc_getlink(t,c, pci_r,link_r, mpc_nego);
82   return r;
83 }
84
85 int trackloc_advance(TrackLocation *t, TrackAdvanceContext *c) {
86   Segment *next;
87   SegmentNum nextnum;
88   const SegPosCombInfo *pci;
89   const SegmentLinkInfo *link;
90   TrackLocation leaving;
91   int r;
92
93   r= nextseg(t,c, &pci,&link, 0);
94   if (r) return r;
95
96 //fprintf(stderr,"advance start getlink %s%s/%s -> %s\n",
97 //      t->backwards?"-":"", t->seg->i->pname,
98 //      pci ? pci->pname : "?",
99 //      link && SOMEP(link->next) ? info_segments[link->next].pname : "?");
100
101   for (;;) {
102     if (!c->distance) return 0;
103
104     if (t->remain) {
105       int use= t->remain < c->distance ? t->remain : c->distance;
106       t->remain -= use;
107       c->distance -= use;
108       continue;
109     }
110
111     nextnum= link->next;
112
113     if (!SOMEP(nextnum)) {
114       if (c->trackend) return c->trackend(t,c);
115       return 0;
116     }
117     next= &segments[nextnum];
118
119     leaving= *t;
120
121     t->seg= next;
122     t->backwards ^= link->next_backwards;
123     t->remain= -1;
124
125     r= nextseg(t,c, &pci,&link, &leaving);
126     if (r) { *t= leaving; return r; }
127
128 //fprintf(stderr,"advance ran getlink %s/%s -> %s\n",leaving->i->pname,
129 //      pci ? pci->pname : "?",
130 //      link && SOMEP(link->next) ? info_segments[link->next].pname : "?");
131
132     t->remain= pci->dist;
133   }
134 }
135
136 Segment *segment_interferer(Segment *base) {
137   SegmentNum intern= base->i->interferes;
138   if (!SOMEP(intern)) return 0;
139   return &segments[intern];
140 }
141
142 static ErrorCode interfering_movposcomb(TrackAdvanceContext *c, Segment *seg,
143                                         int *does_r) {
144   MovPosComb mpc;
145   int r;
146
147   mpc= seg->movposcomb;
148   if (c && c->getmovpos) {
149     TrackLocation t;
150     t.seg= seg;
151     t.backwards= 0;
152     t.remain= 0;
153
154     r= c->getmovpos(&t,c,&mpc);
155     if (r) return r;
156   }
157
158   *does_r= !SOMEP(mpc) || seg->i->interferes_movposcomb_map & (1u << mpc);
159   return 0;
160 }
161
162 ErrorCode segment_interferer_does(TrackAdvanceContext *c, Segment *base,
163                                   Segment *inter, int *does_r) {
164   ErrorCode ec;
165   int does;
166
167   if (!inter) goto doesnt;
168
169   ec= interfering_movposcomb(c,base, &does);  if (ec) return ec;
170   if (!does) goto doesnt;
171
172   assert(base->i == &info_segments[inter->i->interferes]);
173   ec= interfering_movposcomb(c,inter, &does);  if (ec) return ec;
174   if (!does) goto doesnt;
175
176   *does_r= 1;
177   return 0;
178
179  doesnt:
180   *does_r= 0;
181   return 0;
182 }
183
184 Segment *segment_interferes_simple(TrackAdvanceContext *c, Segment *base) {
185   Segment *inter= segment_interferer(base);
186   if (!inter) return 0;
187
188   int does;
189   ErrorCode ec= segment_interferer_does(c,base,inter,&does);
190   assert(!ec);
191
192   return does ? inter : 0;
193 }
194
195 int trackloc_reverse_exact(TrackLocation *t, TrackAdvanceContext *c) {
196   const SegPosCombInfo *pci;
197   int r;
198   
199   r= trackloc_getlink(t,c,&pci,0,-1);
200   if (r) return r;
201   assert(pci);
202   t->remain= pci->dist - t->remain;
203   t->backwards ^= 1;
204   return 0;
205 }