~ubuntu-branches/ubuntu/utopic/simh/utopic

« back to all changes in this revision

Viewing changes to TOOLS/crossassemblers/macro11/stream2.c

  • Committer: Bazaar Package Importer
  • Author(s): Vince Mulhollon
  • Date: 2004-04-20 20:01:26 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040420200126-ehsuleda8xcgi51h
Tags: 3.2.0-1
New upstream 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* functions for managing a stack of file and buffer input streams. */
 
2
 
 
3
/*
 
4
 
 
5
Copyright (c) 2001, Richard Krehbiel
 
6
All rights reserved.
 
7
 
 
8
Redistribution and use in source and binary forms, with or without
 
9
modification, are permitted provided that the following conditions are
 
10
met:
 
11
 
 
12
o Redistributions of source code must retain the above copyright
 
13
  notice, this list of conditions and the following disclaimer.
 
14
 
 
15
o Redistributions in binary form must reproduce the above copyright
 
16
  notice, this list of conditions and the following disclaimer in the
 
17
  documentation and/or other materials provided with the distribution.
 
18
 
 
19
o Neither the name of the copyright holder nor the names of its
 
20
  contributors may be used to endorse or promote products derived from
 
21
  this software without specific prior written permission.
 
22
 
 
23
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
24
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
25
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
26
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
27
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 
28
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 
29
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 
30
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
31
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 
32
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 
33
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 
34
DAMAGE.
 
35
 
 
36
*/
 
37
 
 
38
#include <stdio.h>
 
39
#include <stddef.h>
 
40
#include <stdlib.h>
 
41
#include <string.h>
 
42
#include <ctype.h>
 
43
#include <stdarg.h>
 
44
 
 
45
#include "macro11.h"
 
46
 
 
47
#include "stream2.h"
 
48
 
 
49
/* BUFFER functions */
 
50
 
 
51
/* new_buffer allocates a new buffer */
 
52
 
 
53
BUFFER *new_buffer(void)
 
54
{
 
55
        BUFFER *buf = memcheck(malloc(sizeof(BUFFER)));
 
56
        buf->length = 0;
 
57
        buf->size = 0;
 
58
        buf->use = 1;
 
59
        buf->buffer = NULL;
 
60
        return buf;
 
61
}
 
62
 
 
63
/* buffer_resize makes the buffer at least the requested size. */
 
64
/* If the buffer is already larger, then it will attempt */
 
65
/* to shrink it. */
 
66
 
 
67
void buffer_resize(BUFFER *buff, int size)
 
68
{
 
69
        buff->size = size;
 
70
        buff->length = size;
 
71
 
 
72
        if(size == 0)
 
73
        {
 
74
                free(buff->buffer);
 
75
                buff->buffer = NULL;
 
76
        }
 
77
        else
 
78
        {
 
79
                if(buff->buffer == NULL)
 
80
                        buff->buffer = memcheck(malloc(buff->size));
 
81
                else
 
82
                        buff->buffer = memcheck(realloc(buff->buffer, buff->size));
 
83
        }
 
84
}
 
85
 
 
86
/* buffer_clone makes a copy of a buffer */
 
87
/* Basically it increases the use count */
 
88
 
 
89
BUFFER *buffer_clone(BUFFER *from)
 
90
{
 
91
        if(from)
 
92
                from->use++;
 
93
        return from;
 
94
}
 
95
 
 
96
/* buffer_free frees a buffer */
 
97
/* It decreases the use count, and if zero, */
 
98
/* frees the memory. */
 
99
 
 
100
void buffer_free(BUFFER *buf)
 
101
{
 
102
        if(buf)
 
103
        {
 
104
                if(--(buf->use) == 0)
 
105
                {
 
106
                        free(buf->buffer);
 
107
                        free(buf);
 
108
                }
 
109
        }
 
110
}
 
111
 
 
112
/* Append characters to the buffer. */
 
113
 
 
114
void buffer_appendn(BUFFER *buf, char *str, int len)
 
115
{
 
116
        int needed = buf->length + len + 1;
 
117
 
 
118
        if(needed >= buf->size)
 
119
        {
 
120
                buf->size = needed + GROWBUF_INCR;
 
121
 
 
122
                if(buf->buffer == NULL)
 
123
                        buf->buffer = memcheck(malloc(buf->size));
 
124
                else
 
125
                        buf->buffer = memcheck(realloc(buf->buffer, buf->size));
 
126
        }
 
127
 
 
128
        memcpy(buf->buffer + buf->length, str, len);
 
129
        buf->length += len;
 
130
        buf->buffer[buf->length] = 0;
 
131
}
 
132
 
 
133
/* append a text line (zero or newline-delimited) */
 
134
 
 
135
void buffer_append_line(BUFFER *buf, char *str)
 
136
{
 
137
        char *nl;
 
138
        if((nl = strchr(str, '\n')) != NULL)
 
139
                buffer_appendn(buf, str, nl - str + 1);
 
140
        else
 
141
                buffer_appendn(buf, str, strlen(str));
 
142
}
 
143
 
 
144
/* Base STREAM class methods */
 
145
 
 
146
/* stream_construct initializes a newly allocated STREAM */
 
147
 
 
148
void stream_construct(STREAM *str, char *name)
 
149
{
 
150
        str->line = 0;
 
151
        str->name = memcheck(strdup(name));
 
152
        str->next = NULL;
 
153
        str->vtbl = NULL;
 
154
}
 
155
 
 
156
/* stream_delete destroys and deletes (frees) a STREAM */
 
157
 
 
158
void stream_delete(STREAM *str)
 
159
{
 
160
        free(str->name);
 
161
        free(str);
 
162
}
 
163
 
 
164
/* *** class BUFFER_STREAM implementation */
 
165
 
 
166
/* STREAM::gets for a buffer stream */
 
167
 
 
168
char *buffer_stream_gets(STREAM *str)
 
169
{
 
170
        char *nl;
 
171
        char *cp;
 
172
        BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
 
173
        BUFFER *buf = bstr->buffer;
 
174
 
 
175
        if(buf == NULL)
 
176
                return NULL;            /* No buffer */
 
177
        
 
178
        if(bstr->offset >= buf->length)
 
179
                return NULL;
 
180
 
 
181
        cp = buf->buffer + bstr->offset;
 
182
 
 
183
        /* Find the next line in preparation for the next call */
 
184
 
 
185
        nl = memchr(cp, '\n', buf->length - bstr->offset);
 
186
 
 
187
        if(nl)
 
188
                nl++;
 
189
 
 
190
        bstr->offset = nl - buf->buffer;
 
191
        str->line++;
 
192
 
 
193
        return cp;
 
194
}
 
195
 
 
196
/* STREAM::close for a buffer stream */
 
197
 
 
198
void buffer_stream_delete(STREAM *str)
 
199
{
 
200
        BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
 
201
        buffer_free(bstr->buffer);
 
202
        stream_delete(str);
 
203
}
 
204
 
 
205
/* STREAM::rewind for a buffer stream */
 
206
 
 
207
void buffer_stream_rewind(STREAM *str)
 
208
{
 
209
        BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
 
210
        bstr->offset = 0;
 
211
        str->line = 0;
 
212
}
 
213
 
 
214
/* BUFFER_STREAM vtbl */
 
215
 
 
216
STREAM_VTBL buffer_stream_vtbl = { buffer_stream_delete,
 
217
                                                                   buffer_stream_gets,
 
218
                                                                   buffer_stream_rewind };
 
219
 
 
220
void buffer_stream_construct(BUFFER_STREAM *bstr, BUFFER *buf, char *name)
 
221
{
 
222
        bstr->stream.vtbl = &buffer_stream_vtbl;
 
223
        
 
224
        bstr->stream.name = memcheck(strdup(name));
 
225
 
 
226
        bstr->buffer = buffer_clone(buf);
 
227
        bstr->offset = 0;
 
228
        bstr->stream.line = 0;
 
229
}
 
230
 
 
231
void buffer_stream_set_buffer(BUFFER_STREAM *bstr, BUFFER *buf)
 
232
{
 
233
        if(bstr->buffer)
 
234
                buffer_free(bstr->buffer);
 
235
        bstr->buffer = buffer_clone(buf);
 
236
        bstr->offset = 0;
 
237
}
 
238
 
 
239
/* new_buffer_stream clones the given buffer, gives it the name, */
 
240
/* and creates a BUFFER_STREAM to reference it */
 
241
 
 
242
STREAM *new_buffer_stream(BUFFER *buf, char *name)
 
243
{
 
244
        BUFFER_STREAM *bstr = memcheck(malloc(sizeof(BUFFER_STREAM)));
 
245
 
 
246
        buffer_stream_construct(bstr, buf, name);
 
247
        return &bstr->stream;
 
248
}
 
249
 
 
250
/* *** FILE_STREAM implementation */
 
251
 
 
252
/* Implement STREAM::gets for a file stream */
 
253
 
 
254
static char *file_gets(STREAM *str)
 
255
{
 
256
        int i, c;
 
257
        FILE_STREAM *fstr = (FILE_STREAM *)str;
 
258
 
 
259
        if(fstr->fp == NULL)
 
260
                return NULL;
 
261
 
 
262
        if(feof(fstr->fp))
 
263
                return NULL;
 
264
 
 
265
        /* Read single characters, end of line when '\n' or '\f' hit */
 
266
 
 
267
        i = 0;
 
268
        while(c = fgetc(fstr->fp),
 
269
                c != '\n' && c != '\f' && c != EOF)
 
270
        {
 
271
                if(c == 0)
 
272
                        continue;                               /* Don't buffer zeros */
 
273
                if(c == '\r')
 
274
                        continue;                               /* Don't buffer carriage returns either */
 
275
                if(i < STREAM_BUFFER_SIZE - 2)
 
276
                        fstr->buffer[i++] = c;
 
277
        }
 
278
 
 
279
        fstr->buffer[i++] = '\n';               /* Silently transform formfeeds
 
280
                                                                           into newlines */
 
281
        fstr->buffer[i] = 0;
 
282
 
 
283
        if(c == '\n')
 
284
                fstr->stream.line++;            /* Count a line */
 
285
 
 
286
        return fstr->buffer;
 
287
}
 
288
 
 
289
/* Implement STREAM::destroy for a file stream */
 
290
 
 
291
void file_destroy(STREAM *str)
 
292
{
 
293
        FILE_STREAM *fstr = (FILE_STREAM *)str;
 
294
        fclose(fstr->fp);
 
295
        free(fstr->buffer);
 
296
        stream_delete(str);
 
297
}
 
298
 
 
299
/* Implement STREAM::rewind for a file stream */
 
300
 
 
301
void file_rewind(STREAM *str)
 
302
{
 
303
        FILE_STREAM *fstr = (FILE_STREAM *)str;
 
304
        rewind(fstr->fp);
 
305
        str->line = 0;
 
306
}
 
307
 
 
308
static STREAM_VTBL file_stream_vtbl = { file_destroy, file_gets,
 
309
                                                                                file_rewind };
 
310
 
 
311
/* Prepare and open a stream from a file. */
 
312
 
 
313
STREAM *new_file_stream(char *filename)
 
314
{
 
315
        FILE *fp;
 
316
        FILE_STREAM *str;
 
317
 
 
318
        fp = fopen(filename, "r");
 
319
        if(fp == NULL)
 
320
                return NULL;
 
321
 
 
322
        str = memcheck(malloc(sizeof(FILE_STREAM)));
 
323
 
 
324
        str->stream.vtbl = &file_stream_vtbl;
 
325
        str->stream.name = memcheck(strdup(filename));
 
326
        str->buffer = memcheck(malloc(STREAM_BUFFER_SIZE));
 
327
        str->fp = fp;
 
328
        str->stream.line = 0;
 
329
 
 
330
        return &str->stream;
 
331
}
 
332
 
 
333
/* STACK functions */
 
334
 
 
335
/* stack_init prepares a stack */
 
336
 
 
337
void stack_init(STACK *stack)
 
338
{
 
339
        stack->top = NULL;                      /* Too simple */
 
340
}
 
341
 
 
342
/* stack_pop removes and deletes the topmost STRAM on the stack */
 
343
 
 
344
void stack_pop(STACK *stack)
 
345
{
 
346
        STREAM *top = stack->top;
 
347
        STREAM *next = top->next;
 
348
 
 
349
        top->vtbl->delete(top);
 
350
        stack->top = next;
 
351
}
 
352
 
 
353
/* stack_push pushes a STREAM onto the top of the stack */
 
354
 
 
355
void stack_push(STACK *stack, STREAM *str)
 
356
{
 
357
        str->next = stack->top;
 
358
        stack->top = str;
 
359
}
 
360
 
 
361
/* stack_gets calls vtbl->gets for the topmost stack entry.  When
 
362
   topmost streams indicate they're exhausted, they are popped and
 
363
   deleted, until the stack is exhausted. */
 
364
 
 
365
char *stack_gets(STACK *stack)
 
366
{
 
367
        char *line;
 
368
 
 
369
        if(stack->top == NULL)
 
370
                return NULL;
 
371
 
 
372
        while((line = stack->top->vtbl->gets(stack->top)) == NULL)
 
373
        {
 
374
                stack_pop(stack);
 
375
                if(stack->top == NULL)
 
376
                        return NULL;
 
377
        }
 
378
 
 
379
        return line;
 
380
}