Mercurial > repo
comparison interps/cfunge/cfunge-src/src/input.c @ 996:859f9b4339e6
<Gregor> tar xf egobot.tar.xz
author | HackBot |
---|---|
date | Sun, 09 Dec 2012 19:30:08 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
995:6883f5911eb7 | 996:859f9b4339e6 |
---|---|
1 /* -*- mode: C; coding: utf-8; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- | |
2 * | |
3 * cfunge - A standard-conforming Befunge93/98/109 interpreter in C. | |
4 * Copyright (C) 2008-2009 Arvid Norlander <anmaster AT tele2 DOT se> | |
5 * | |
6 * This program is free software: you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation, either version 3 of the License, or | |
9 * (at the proxy's option) any later version. Arvid Norlander is a | |
10 * proxy who can decide which future versions of the GNU General Public | |
11 * License can be used. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 */ | |
21 | |
22 #include "global.h" | |
23 #include "input.h" | |
24 | |
25 #include <assert.h> | |
26 #include <ctype.h> /* isdigit, isxdigit */ | |
27 #include <stdbool.h> | |
28 #include <stddef.h> /* ptrdiff_t */ | |
29 #include <stdlib.h> | |
30 | |
31 // We use static buffer for input to save input | |
32 // from one read to the next if there was any | |
33 // left. | |
34 static char* lastline = NULL; | |
35 static size_t linelength = 0; | |
36 // Pointer to how far we consumed the current line. | |
37 static char* lastline_current = NULL; | |
38 | |
39 FUNGE_ATTR_FAST FUNGE_ATTR_WARN_UNUSED | |
40 static inline bool get_line(void) | |
41 { | |
42 if (!lastline || !lastline_current || (*lastline_current == '\0')) { | |
43 ssize_t retval; | |
44 fflush(stdout); | |
45 retval = cf_getline(&lastline, &linelength, stdin); | |
46 if (retval == -1) | |
47 return false; | |
48 lastline_current = lastline; | |
49 } | |
50 return true; | |
51 } | |
52 FUNGE_ATTR_FAST static inline void discard_line(void) | |
53 { | |
54 if (lastline != NULL) | |
55 cf_free(lastline); | |
56 lastline = NULL; | |
57 lastline_current = NULL; | |
58 } | |
59 | |
60 | |
61 FUNGE_ATTR_FAST bool input_getchar(funge_cell * restrict chr) | |
62 { | |
63 unsigned char tmp; | |
64 if (!get_line()) | |
65 return false; | |
66 tmp = *((unsigned char*)lastline_current); | |
67 lastline_current++; | |
68 if (lastline_current && (*lastline_current == '\0')) | |
69 discard_line(); | |
70 *chr = (funge_cell)tmp; | |
71 return true; | |
72 } | |
73 | |
74 FUNGE_ATTR_FAST bool input_getline(unsigned char ** str) | |
75 { | |
76 unsigned char * tmp; | |
77 if (!get_line()) | |
78 return false; | |
79 tmp = (unsigned char*)cf_strdup(lastline_current); | |
80 *str = tmp; | |
81 discard_line(); | |
82 return true; | |
83 } | |
84 | |
85 | |
86 static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; | |
87 | |
88 // Start of s as if it is in base. | |
89 // Unlike strtoll this does not clamp on overflow but stop reading just before | |
90 // a overflow would happen. | |
91 // Converted value is returned in *value. | |
92 // Return value is last index used in string. | |
93 FUNGE_ATTR_FAST FUNGE_ATTR_NONNULL FUNGE_ATTR_WARN_UNUSED | |
94 static inline ptrdiff_t parse_int(const char * restrict s, | |
95 funge_cell * restrict value, funge_cell base) | |
96 { | |
97 funge_cell result = 0; | |
98 size_t i; | |
99 size_t length = strlen(s); | |
100 | |
101 assert(s != NULL); | |
102 assert(value != NULL); | |
103 | |
104 for (i = 0; i <= length; i++) { | |
105 // Will it overflow? | |
106 if (result > (FUNGECELL_MAX / base)) { | |
107 break; | |
108 } else { | |
109 funge_cell tmp; | |
110 char c = s[i]; | |
111 // Pointer into digits. | |
112 const char * p = strchr(digits, c); | |
113 // Still a digit? | |
114 if (!p || ((p - digits) >= (ptrdiff_t)base)) | |
115 break; | |
116 | |
117 tmp = (funge_cell)(p - digits); | |
118 // Break if it will overflow! | |
119 if ((result * base) > (FUNGECELL_MAX - tmp)) | |
120 break; | |
121 result = (result * base) + tmp; | |
122 } | |
123 } | |
124 *value = result; | |
125 return (ptrdiff_t)i; | |
126 } | |
127 | |
128 // Note, no need to optimise really, this is user input | |
129 // bound anyway. | |
130 FUNGE_ATTR_FAST ret_getint input_getint(funge_cell * restrict value, int base) | |
131 { | |
132 bool found = false; | |
133 char * endptr = NULL; | |
134 assert(value != NULL); | |
135 | |
136 if (!get_line()) | |
137 return rgi_eof; | |
138 // Find first char that is a number, then convert number. | |
139 do { | |
140 if (base == 10) { | |
141 if (!isdigit(*lastline_current)) | |
142 continue; | |
143 } else if (base == 16) { | |
144 if (!isxdigit(*lastline_current)) | |
145 continue; | |
146 } else { | |
147 const char * p = strchr(digits, *lastline_current); | |
148 if (!p || ((p - digits) >= (ptrdiff_t)base)) | |
149 continue; | |
150 } | |
151 found = true; | |
152 // Ok, we found it, lets convert it. | |
153 endptr = lastline_current + parse_int(lastline_current, value, | |
154 (funge_cell)base); | |
155 break; | |
156 } while (*(lastline_current++) != '\0'); | |
157 // Discard rest of line if it is just newline, otherwise keep it. | |
158 if (endptr && ((*endptr == '\n') || (*endptr == '\r') || (*endptr == '\0'))) | |
159 discard_line(); | |
160 else | |
161 lastline_current = endptr; | |
162 return found ? rgi_success : rgi_noint; | |
163 } |