Pristine Ack-5.5
[Ack-5.5.git] / modules / src / em_code / insert.c
1 /* $Id: insert.c,v 1.9 1994/06/24 11:11:14 ceriel Exp $ */
2
3 /* Implementation of C_insertpart, C_beginpart, and C_endpart.
4    Basic methodology: place the parts either in memory or on a temporary
5    file, in the order received, and remember this order. Then, in a second
6    "pass", write out the code.
7    An optimization is possible: as long as the order in which the parts
8    are received corresponds to the order in which they must be written,
9    they can be written immediately.
10 */
11
12 #include <em_path.h>
13 #include <alloc.h>
14 #include "insert.h"
15
16 char            *C_tmpdir = TMP_DIR;
17 static Part     *C_stable[TABSIZ];
18
19 static char     *C_old_top;
20 static char     *C_old_opp;
21
22 #ifndef INCORE
23 static File     *C_old_ofp;
24
25 static int
26 getbyte(b)
27         long b;
28 {
29         /*      Get the byte at offset "b" from the start of the
30                 temporary file, and try to do so in an efficient way.
31         */
32         static long     start_core, curr_pos;
33
34         if (b < start_core || b >= curr_pos) {
35                 /* the block wanted is not in core, so get it */
36                 long nb = (b & ~(BUFSIZ - 1));
37                 int n;
38
39                 C_flush();
40                 if (nb != curr_pos) {
41                         if (sys_seek(C_tfr, nb, 0, &curr_pos) == 0) {
42                                 C_failed();
43                         }
44                 }
45                 if (! C_ibuf) {
46                         C_ibuf = Malloc(BUFSIZ);
47                 }
48                 if (sys_read(C_tfr, C_ibuf, BUFSIZ, &n) == 0) {
49                         C_failed();
50                 }
51                 curr_pos += n;
52                 start_core = nb;
53         }
54
55         return C_ibuf[(int) (b - start_core)];
56 }
57 #endif
58
59 static C_out_parts();
60 static Part *C_findpart();
61
62 static
63 outpart(id)
64         int id;
65 {
66         /*      Output part "id", if present.
67         */
68         Part *p = C_findpart(id);
69
70         if (p) {
71                 C_out_parts(p->p_parts);
72                 p->p_parts = 0;
73         }
74 }
75
76 static
77 C_out_parts(pp)
78         register PartOfPart *pp;
79 {
80         /*      Output the list of chunks started by "pp".
81                 The list is build in reverse order, so this routine is
82                 recursive.
83         */
84         PartOfPart *prev = 0, *next;
85
86         while (pp) {
87                 next = pp->pp_next;
88                 pp->pp_next = prev;
89                 prev = pp;
90                 pp = next;
91         }
92         pp = prev;
93
94         while (pp) {
95                 if (pp->pp_type == INSERT) {
96                         (*C_outpart)(pp->pp_id);
97                 }
98                 else {
99                         /* copy the chunk to output */
100 #ifdef INCORE
101                         register char *s = C_BASE + pp->pp_begin;
102                         char *se = C_BASE + pp->pp_end;
103
104                         while (s < se) {
105                                 put(*s++);
106                         }
107 #else
108                         register long b = pp->pp_begin;
109
110                         while (b < pp->pp_end) {
111                                 put(getbyte(b++));
112                         }
113 #endif
114                 }
115                 prev = pp;
116                 pp = pp->pp_next;
117                 free((char *) prev);
118         }
119 }
120
121 static Part *
122 C_findpart(part)
123         int part;
124 {
125         /*      Look for part "part" in the table.
126                 Return 0 if not present,
127         */
128         register Part *p = C_stable[part % TABSIZ];
129
130         while (p && p->p_id != part) {
131                 p = p->p_next;
132         }
133         return p;
134 }
135
136 extern char     *strcpy(), *strcat(), *mktemp();
137
138 static
139 swttmp()
140 {
141 #ifndef INCORE
142         if (C_tmpfile == 0) {
143                 static char tmpbuf[64];
144                 register char *p = tmpbuf;
145
146                 strcpy(p, C_tmpdir);
147                 strcat(p, "/CodeXXXXXX");
148                 C_tmpfile = mktemp(p);
149                 if (! sys_open(p, OP_WRITE, &C_old_ofp)) {
150                         C_failed();
151                 }
152                 if (! sys_open(p, OP_READ, &C_tfr)) {
153                         C_failed();
154                 }
155         }
156         if (! C_ontmpfile) {
157                 File *p = C_ofp;
158
159                 C_flush();
160                 C_ofp = C_old_ofp;
161                 C_old_ofp = p;
162                 C_ontmpfile = 1;
163         }
164 #else
165         if (! C_ontmpfile) {
166                 char *p;
167
168                 p = C_opp;
169                 C_opp = C_old_opp;
170                 C_old_opp = p;
171
172                 p = C_top;
173                 C_top = C_old_top;
174                 C_old_top = p;
175                 C_ontmpfile = 1;
176         }
177 #endif
178 }
179
180 static
181 swtout()
182 {
183 #ifndef INCORE
184         if (C_ontmpfile) {
185                 File *p = C_ofp;
186
187                 C_flush();
188                 C_ofp = C_old_ofp;
189                 C_old_ofp = p;
190                 C_ontmpfile = 0;
191         }
192 #else
193         if (C_ontmpfile) {
194                 char *p;
195
196                 p = C_opp;
197                 C_opp = C_old_opp;
198                 C_old_opp = p;
199
200                 p = C_top;
201                 C_top = C_old_top;
202                 C_old_top = p;
203                 C_ontmpfile = 0;
204         }
205 #endif
206 }
207
208 static int
209 available(part)
210         int part;
211 {
212         /*      See if part "part", and all the parts it consists of,
213                 are available. Return 1 if they are, 0 otherwize
214         */
215         register Part *p = C_findpart(part);
216         register PartOfPart *pp;
217         int retval = 1;
218
219         if (p == 0) return 0;
220
221         if (p->p_flags & BUSY) {
222                 /* recursive call ends up here, and this just should
223                    not happen. It is an error of the programmer using
224                    this module.
225                 */
226                 C_internal_error();
227         }
228
229         p->p_flags |= BUSY;
230
231         pp = p->p_parts;
232         while (pp) {
233                 if (pp->pp_type == INSERT && ! available(pp->pp_id)) {
234                         retval = 0;
235                         break;
236                 }
237                 else    pp = pp->pp_next;
238         }
239         p->p_flags &= ~BUSY;
240         return retval;
241 }
242
243 static Part *
244 mkpart(part)
245         int part;
246 {
247         /*      Create a Part structure with id "part", and return a
248                 pointer to it, after checking that is does not exist
249                 already.
250         */
251         register Part *p = C_findpart(part);
252         register int index = part % TABSIZ;
253         
254         if (p != 0) {
255                 /* multiple defined part ... */
256                 C_internal_error();
257         }
258
259         p = (Part *) Malloc(sizeof(Part));
260         p->p_id = part;
261         p->p_next = C_stable[index];
262         C_stable[index] = p;
263         p->p_parts = 0;
264         p->p_flags = 0;
265         p->p_prevpart = 0;
266         return p;
267 }
268
269 static
270 end_partofpart(p)
271         register Part *p;
272 {
273         /*      End the current chunk of part *p.
274         */
275
276         if (p) {
277                 register PartOfPart *pp = p->p_parts;
278
279                 pp->pp_end = C_current_out - C_BASE;
280                 if (pp->pp_begin == pp->pp_end) {
281                         /* nothing in this chunk, so give it back */
282                         p->p_parts = pp->pp_next;
283                         free((char *) pp);
284                 }
285         }
286 }
287
288 static
289 resume(p)
290         register Part *p;
291 {
292         /*      Resume part "p", by creating a new PartOfPart structure
293                 for it.
294         */
295         register PartOfPart *pp = (PartOfPart *) Malloc(sizeof(PartOfPart));
296
297         swttmp();
298         C_curr_part = p;
299         pp->pp_next = p->p_parts;
300         p->p_parts = pp;
301         pp->pp_type = TEXT;
302         pp->pp_begin = C_current_out - C_BASE;
303 }
304
305 void
306 C_insertpart(part)
307         int part;
308 {
309         /*      Insert part "part" in the current part. If C_sequential is
310                 still set and the part to be inserted is available now,
311                 just write it out.
312         */
313         register Part *p;
314         register PartOfPart *pp;
315
316         C_outpart = outpart;
317         C_swttmp = swttmp;
318         C_swtout = swtout;
319         if (C_sequential && available(part)) {
320                 outpart(part);
321                 return;
322         }
323
324         if (C_sequential) {
325                 /* stop the sequential stuff, by creating a part */
326                 C_sequential = 0;
327                 p = mkpart(0);
328                 C_curr_part = p;
329         }
330         else {
331                 p = C_curr_part;
332                 end_partofpart(p);
333         }
334
335         /* Now, add the insertion of "part" to the current part.  */
336         pp = (PartOfPart *) Malloc(sizeof(PartOfPart));
337         pp->pp_next = p->p_parts;
338         p->p_parts = pp;
339         pp->pp_type = INSERT;
340         pp->pp_id = part;
341         resume(p);
342 }
343
344 void
345 C_beginpart(part)
346         int part;
347 {
348         /*      Now follows the definition for part "part".
349                 Suspend the current part, and add part "part" to the
350                 table.
351         */
352         register Part *p = mkpart(part);
353
354         C_outpart = outpart;
355         C_swttmp = swttmp;
356         C_swtout = swtout;
357
358         end_partofpart(C_curr_part);
359
360         p->p_prevpart = C_curr_part;
361         resume(p);
362 }
363
364 void
365 C_endpart(part)
366         int part;
367 {
368         /*      End the current part. The parameter "part" is just there
369                 for the checking. Do we really need it ???
370         */
371         register Part *p = C_curr_part;
372
373         if (p->p_id != part) {
374                 /* illegal C_endpart ... */
375                 C_internal_error();
376         }
377
378         end_partofpart(p);
379         if (p->p_prevpart) resume(p->p_prevpart);
380         else {
381                 C_curr_part = 0;
382                 swtout();
383         }
384 }