1 /*
2  * Copyright (c) 2003
3  *      David Leonard.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of David Leonard nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #if HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #if STDC_HEADERS
36 # include <stdio.h>
37 #endif
38 
39 #include <see/type.h>
40 #include <see/input.h>
41 #include <see/mem.h>
42 
43 /*
44  * an n-character lookahead input filter
45  */
46 
47 static SEE_unicode_t la_next(struct SEE_input *);
48 static void	    la_close(struct SEE_input *);
49 
50 static struct SEE_inputclass la_inputclass = {
51 	la_next,
52 	la_close
53 };
54 
55 struct lookahead {
56 	struct SEE_input    input;
57 	struct SEE_input *	sub;
58 	int		max, ptr;
59 	struct {
60 		SEE_unicode_t ch;
61 		int	     eof;
62 	} buf[1];
63 };
64 
65 static SEE_unicode_t
la_next(inp)66 la_next(inp)
67 	struct SEE_input *inp;
68 {
69 	struct lookahead *la = (struct lookahead *)inp;
70 	SEE_unicode_t next = inp->lookahead;
71 	struct SEE_input *sub = la->sub;
72 
73 	inp->lookahead = la->buf[la->ptr].ch;
74 	inp->eof = la->buf[la->ptr].eof;
75 	la->buf[la->ptr].ch = sub->lookahead;
76 	la->buf[la->ptr].eof = sub->eof;
77 	if (!sub->eof)
78 		SEE_INPUT_NEXT(sub);
79 	la->ptr = (la->ptr + 1) % la->max;
80 	return next;
81 }
82 
83 /*
84  * Return the lookahead buffer that we have available
85  */
86 int
SEE_input_lookahead_copy(inp,buf,buflen)87 SEE_input_lookahead_copy(inp, buf, buflen)
88 	struct SEE_input *inp;
89 	SEE_unicode_t *buf;
90 	int buflen;
91 {
92 	struct lookahead *la = (struct lookahead *)inp;
93 	int i;
94 
95 	if (buflen <= 0 || inp->eof)
96 		return 0;
97 	buf[0] = inp->lookahead;
98 	for (i = 0; i < la->max && i + 1 < buflen &&
99 	    !la->buf[(la->ptr + i) % la->max].eof; i++)
100 		buf[i+1] = la->buf[(la->ptr + i) % la->max].ch;
101 	return i + 1;
102 }
103 
104 static void
la_close(inp)105 la_close(inp)
106 	struct SEE_input *inp;
107 {
108 	struct lookahead *la = (struct lookahead *)inp;
109 
110 	SEE_INPUT_CLOSE(la->sub);
111 }
112 
113 struct SEE_input *
SEE_input_lookahead(sub,max)114 SEE_input_lookahead(sub, max)
115 	struct SEE_input *sub;
116 	int max;
117 {
118 	struct lookahead *la;
119 	int i;
120 
121 	la = (struct lookahead *)SEE_malloc(sub->interpreter,
122 	    sizeof (struct lookahead) + (max - 1) * sizeof la->buf[0]);
123 	la->input.inputclass = &la_inputclass;
124 	la->input.filename = sub->filename;
125 	la->input.first_lineno = sub->first_lineno;
126 	la->input.interpreter = sub->interpreter;
127 	la->sub = sub;
128 	la->ptr = 0;
129 	la->max = max;
130 	for (i = 0; i < max + 1; i++)
131 		la_next((struct SEE_input *)la);
132 	return (struct SEE_input *)la;
133 }
134