00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <plang/term.h>
00021 #include <plang/errors.h>
00022 #include <stdio.h>
00023 #include <stdarg.h>
00024 #include <string.h>
00025 #include "term-priv.h"
00026 #include "database-priv.h"
00027 #include "context-priv.h"
00028 #include "parser-priv.h"
00029
00030
00031 static int p_builtin_validate_var_list
00032 (p_context *context, p_term *vars, p_term **error)
00033 {
00034 p_term *save_vars = vars;
00035 p_term *head;
00036 p_term *name;
00037 if (!vars || (vars->header.type & P_TERM_VARIABLE) != 0) {
00038 *error = p_create_instantiation_error(context);
00039 return 0;
00040 }
00041 while (vars && vars->header.type == P_TERM_LIST) {
00042 head = p_term_deref(vars->list.head);
00043 if (!head || head->header.type != P_TERM_FUNCTOR ||
00044 head->header.size != 2 ||
00045 head->functor.functor_name != context->unify_atom) {
00046 *error = p_create_type_error
00047 (context, "variable_names", save_vars);
00048 return 0;
00049 }
00050 name = p_term_deref(p_term_arg(head, 0));
00051 if (!name || (name->header.type != P_TERM_ATOM &&
00052 name->header.type != P_TERM_STRING)) {
00053 *error = p_create_type_error
00054 (context, "variable_names", save_vars);
00055 return 0;
00056 }
00057 vars = p_term_deref(vars->list.tail);
00058 }
00059 if (vars != context->nil_atom) {
00060 *error = p_create_type_error
00061 (context, "variable_names", save_vars);
00062 return 0;
00063 }
00064 return 1;
00065 }
00066
00067
00068 static p_goal_result p_builtin_print
00069 (p_context *context, p_term **args, p_term **error)
00070 {
00071 p_term *term = p_term_deref_member(context, args[1]);
00072 if (p_term_integer_value(args[0]) == 1) {
00073 p_term_print_with_vars
00074 (context, term, p_term_stdio_print_func, stdout, 0);
00075 } else {
00076 p_term_print_with_vars
00077 (context, term, p_term_stdio_print_func, stderr, 0);
00078 }
00079 return P_RESULT_TRUE;
00080 }
00081 static p_goal_result p_builtin_print_3
00082 (p_context *context, p_term **args, p_term **error)
00083 {
00084 p_term *term = p_term_deref_member(context, args[1]);
00085 p_term *vars = p_term_deref_member(context, args[2]);
00086 if (!p_builtin_validate_var_list(context, vars, error))
00087 return P_RESULT_ERROR;
00088 if (p_term_integer_value(args[0]) == 1) {
00089 p_term_print_with_vars
00090 (context, term, p_term_stdio_print_func, stdout, vars);
00091 } else {
00092 p_term_print_with_vars
00093 (context, term, p_term_stdio_print_func, stderr, vars);
00094 }
00095 return P_RESULT_TRUE;
00096 }
00097 static p_goal_result p_builtin_print_byte
00098 (p_context *context, p_term **args, p_term **error)
00099 {
00100 p_term *term = p_term_deref_member(context, args[1]);
00101 if (!term || (term->header.type & P_TERM_VARIABLE) != 0) {
00102 *error = p_create_instantiation_error(context);
00103 return P_RESULT_ERROR;
00104 } else if (term->header.type != P_TERM_INTEGER) {
00105 *error = p_create_type_error(context, "byte", term);
00106 return P_RESULT_ERROR;
00107 } else {
00108 int value = p_term_integer_value(term);
00109 if (value < 0 || value > 255) {
00110 *error = p_create_type_error(context, "byte", term);
00111 return P_RESULT_ERROR;
00112 }
00113 if (p_term_integer_value(args[0]) == 1)
00114 putc(value, stdout);
00115 else
00116 putc(value, stderr);
00117 }
00118 return P_RESULT_TRUE;
00119 }
00120 static p_goal_result p_builtin_print_flush
00121 (p_context *context, p_term **args, p_term **error)
00122 {
00123 if (p_term_integer_value(args[0]) == 1)
00124 fflush(stdout);
00125 else
00126 fflush(stderr);
00127 return P_RESULT_TRUE;
00128 }
00129 static p_goal_result p_builtin_print_string
00130 (p_context *context, p_term **args, p_term **error)
00131 {
00132 p_term *term = p_term_deref_member(context, args[1]);
00133 if (!term || (term->header.type & P_TERM_VARIABLE) != 0) {
00134 *error = p_create_instantiation_error(context);
00135 return P_RESULT_ERROR;
00136 } else if (term->header.type != P_TERM_STRING) {
00137 *error = p_create_type_error(context, "string", term);
00138 return P_RESULT_ERROR;
00139 } else if (p_term_integer_value(args[0]) == 1) {
00140 p_term_print_unquoted
00141 (context, term, p_term_stdio_print_func, stdout);
00142 } else {
00143 p_term_print_unquoted
00144 (context, term, p_term_stdio_print_func, stderr);
00145 }
00146 return P_RESULT_TRUE;
00147 }
00148
00150 struct p_write_term_data
00151 {
00152 p_context *context;
00153 p_term *stream;
00154 char buffer[512];
00155 size_t buflen;
00156 p_term *error;
00157 p_term *writeString;
00158 p_goal_result result;
00159 };
00162 static void p_write_term_flush(struct p_write_term_data *data)
00163 {
00164 p_term *str = p_term_create_string_n
00165 (data->context, data->buffer, data->buflen);
00166 p_term *call = p_term_create_functor
00167 (data->context, data->context->call_member_atom, 2);
00168 p_term *args = p_term_create_functor
00169 (data->context, data->context->call_args_atom, 2);
00170 p_term_bind_functor_arg(args, 0, data->stream);
00171 p_term_bind_functor_arg(args, 1, str);
00172 p_term_bind_functor_arg
00173 (call, 0, p_term_create_member_variable
00174 (data->context, data->stream, data->writeString, 0));
00175 p_term_bind_functor_arg(call, 1, args);
00176 data->buflen = 0;
00177 data->result = p_context_call_once
00178 (data->context, call, &(data->error));
00179 }
00180
00181 static void p_write_term_func(void *_data, const char *format, ...)
00182 {
00183 struct p_write_term_data *data = (struct p_write_term_data *)_data;
00184 va_list va;
00185 va_start(va, format);
00186 while (*format != '\0') {
00187 if (data->result != P_RESULT_TRUE)
00188 break;
00189 if (*format == '%') {
00190 ++format;
00191 if (*format == '\0') {
00192 break;
00193 } else if (*format == 's') {
00194 const char *str = va_arg(va, const char *);
00195 size_t len = strlen(str);
00196 size_t temp_len;
00197 while (len > 0) {
00198 if (data->buflen >= sizeof(data->buffer)) {
00199 p_write_term_flush(data);
00200 if (data->result != P_RESULT_TRUE)
00201 break;
00202 }
00203 temp_len = sizeof(data->buffer) - data->buflen;
00204 if (temp_len > len)
00205 temp_len = len;
00206 memcpy(data->buffer + data->buflen, str, temp_len);
00207 str += temp_len;
00208 len -= temp_len;
00209 data->buflen += temp_len;
00210 }
00211 } else if (*format == 'c') {
00212 int ch = va_arg(va, int);
00213 if (data->buflen >= sizeof(data->buffer))
00214 p_write_term_flush(data);
00215 data->buffer[(data->buflen)++] = (char)ch;
00216 } else {
00217
00218
00219 if (data->buflen >= (sizeof(data->buffer) - 64))
00220 p_write_term_flush(data);
00221 #if defined(HAVE_VSNPRINTF)
00222 vsnprintf(data->buffer + data->buflen,
00223 sizeof(data->buffer) - data->buflen,
00224 format - 1, va);
00225 #elif defined(HAVE__VSNPRINTF)
00226 _vsnprintf(data->buffer + data->buflen,
00227 sizeof(data->buffer) - data->buflen,
00228 format - 1, va);
00229 #else
00230 vsprintf(data->buffer + data->buflen, format - 1, va);
00231 #endif
00232 data->buflen += strlen(data->buffer + data->buflen);
00233 va_end(va);
00234 return;
00235 }
00236 } else {
00237 if (data->buflen >= sizeof(data->buffer))
00238 p_write_term_flush(data);
00239 data->buffer[(data->buflen)++] = *format;
00240 }
00241 ++format;
00242 }
00243 va_end(va);
00244 }
00245
00246
00247 static p_goal_result p_builtin_iostream_writeTerm
00248 (p_context *context, p_term **args, p_term **error)
00249 {
00250 p_term *stream = p_term_deref_member(context, args[0]);
00251 p_term *term = p_term_deref_member(context, args[1]);
00252 p_term *vars = p_term_deref_member(context, args[2]);
00253 struct p_write_term_data data;
00254 if (!p_builtin_validate_var_list(context, vars, error))
00255 return P_RESULT_ERROR;
00256 data.context = context;
00257 data.stream = stream;
00258 data.buflen = 0;
00259 data.error = 0;
00260 data.writeString = p_term_create_atom(context, "writeString");
00261 data.result = P_RESULT_TRUE;
00262 p_term_print_with_vars
00263 (context, term, p_write_term_func, &data, vars);
00264 if (data.buflen > 0 && data.result == P_RESULT_TRUE)
00265 p_write_term_flush(&data);
00266 *error = data.error;
00267 return data.result;
00268 }
00269
00270 static p_term *p_input_concat_string
00271 (p_context *context, p_term *str, const char *buf, size_t len)
00272 {
00273 p_term *str2 = p_term_create_string_n(context, buf, len);
00274 if (!str)
00275 return str2;
00276 return p_term_concat_string(context, str, str2);
00277 }
00278
00279
00280 static p_goal_result p_builtin_stdin_read_byte
00281 (p_context *context, p_term **args, p_term **error)
00282 {
00283 int ch = getc(stdin);
00284 if (ch == EOF)
00285 return P_RESULT_FAIL;
00286 if (p_term_unify(context, args[0],
00287 p_term_create_integer(context, ch),
00288 P_BIND_DEFAULT))
00289 return P_RESULT_TRUE;
00290 else
00291 return P_RESULT_FAIL;
00292 }
00293 static p_goal_result p_builtin_stdin_read_bytes
00294 (p_context *context, p_term **args, p_term **error)
00295 {
00296 int len = p_term_integer_value(args[1]);
00297 char buffer[512];
00298 size_t buflen = 0;
00299 p_term *str = 0;
00300 int ch;
00301 if (!len)
00302 str = p_term_create_string(context, "");
00303 while (len > 0) {
00304 ch = getc(stdin);
00305 if (ch == EOF)
00306 break;
00307 buffer[buflen++] = (char)ch;
00308 if (buflen >= sizeof(buffer)) {
00309 str = p_input_concat_string
00310 (context, str, buffer, buflen);
00311 buflen = 0;
00312 }
00313 --len;
00314 }
00315 if (ch == EOF && !str && buflen == 0)
00316 return P_RESULT_FAIL;
00317 str = p_input_concat_string(context, str, buffer, buflen);
00318 if (p_term_unify(context, args[0], str, P_BIND_DEFAULT))
00319 return P_RESULT_TRUE;
00320 else
00321 return P_RESULT_FAIL;
00322 }
00323 static p_goal_result p_builtin_stdin_read_line
00324 (p_context *context, p_term **args, p_term **error)
00325 {
00326 char buffer[512];
00327 size_t buflen = 0;
00328 p_term *str = 0;
00329 int ch;
00330 while ((ch = getc(stdin)) != EOF) {
00331 if (ch == '\n') {
00332 break;
00333 } else if (ch != '\r') {
00334 buffer[buflen++] = (char)ch;
00335 if (buflen >= sizeof(buffer)) {
00336 str = p_input_concat_string
00337 (context, str, buffer, buflen);
00338 buflen = 0;
00339 }
00340 }
00341 }
00342 if (ch == EOF && !str && buflen == 0)
00343 return P_RESULT_FAIL;
00344 str = p_input_concat_string(context, str, buffer, buflen);
00345 if (p_term_unify(context, args[0], str, P_BIND_DEFAULT))
00346 return P_RESULT_TRUE;
00347 else
00348 return P_RESULT_FAIL;
00349 }
00350
00351 int p_context_consult(p_context *context, p_input_stream *stream);
00352 int p_string_read_func(p_input_stream *stream, char *buf, size_t max_size);
00353
00355 struct p_read_term_stream
00356 {
00357 p_input_stream parent;
00358 p_term *stream;
00359 p_term *error;
00360 p_term *lines;
00361 p_term *readLine;
00362 };
00365 static p_goal_result p_read_term_line
00366 (p_context *context, struct p_read_term_stream *stream,
00367 p_term **line)
00368 {
00369 p_term *call = p_term_create_functor
00370 (context, context->call_member_atom, 2);
00371 p_term *args = p_term_create_functor
00372 (context, context->call_args_atom, 2);
00373 *line = p_term_create_variable(context);
00374 p_term_bind_functor_arg(args, 0, stream->stream);
00375 p_term_bind_functor_arg(args, 1, *line);
00376 p_term_bind_functor_arg
00377 (call, 0, p_term_create_member_variable
00378 (context, stream->stream, stream->readLine, 0));
00379 p_term_bind_functor_arg(call, 1, args);
00380 return p_context_call_once(context, call, &(stream->error));
00381 }
00382
00383 static int p_ends_in_dot(const p_term *term)
00384 {
00385 const char *name = p_term_name(term);
00386 size_t len = p_term_name_length(term);
00387 while (len > 0) {
00388 --len;
00389 if (name[len] == '.')
00390 return 1;
00391 else if (name[len] != ' ' && name[len] != '\t' &&
00392 name[len] != '\f' && name[len] != '\v')
00393 break;
00394 }
00395 return len == 0 ? -1 : 0;
00396 }
00397
00398 static p_goal_result p_builtin_read_term
00399 (p_context *context, struct p_read_term_stream *stream)
00400 {
00401 p_goal_result result;
00402 int first = 1;
00403 int end;
00404 p_term *line;
00405 p_term *nl = p_term_create_string(context, "\n");
00406
00407
00408
00409 stream->lines = p_term_create_string(context, "\?\?- ");
00410 while ((result = p_read_term_line(context, stream, &line))
00411 == P_RESULT_TRUE) {
00412 stream->lines = p_term_concat_string
00413 (context, stream->lines, line);
00414 stream->lines = p_term_concat_string
00415 (context, stream->lines, nl);
00416 end = p_ends_in_dot(line);
00417 if (end > 0)
00418 break;
00419 else if (!end)
00420 first = 0;
00421 }
00422 if (result == P_RESULT_FAIL && !first) {
00423
00424 stream->error = p_create_syntax_error
00425 (context, p_term_create_string
00426 (context, "eof reached; expecting '.' to terminate term"));
00427 return P_RESULT_ERROR;
00428 }
00429 if (result != P_RESULT_TRUE)
00430 return result;
00431
00432
00433 stream->parent.buffer = p_term_name(stream->lines);
00434 stream->parent.buffer_len = p_term_name_length(stream->lines);
00435 if (p_context_consult(context, &(stream->parent)) != 0) {
00436 stream->error = p_create_syntax_error
00437 (context, p_term_create_string
00438 (context, "syntax error while reading term"));
00439 return P_RESULT_ERROR;
00440 }
00441 return P_RESULT_TRUE;
00442 }
00443
00444
00445 static p_goal_result p_builtin_iostream_readTerm
00446 (p_context *context, p_term **args, p_term **error)
00447 {
00448 struct p_read_term_stream stream;
00449 p_goal_result result;
00450 memset(&stream, 0, sizeof(stream));
00451 stream.parent.context = context;
00452 stream.parent.read_func = p_string_read_func;
00453 stream.stream = p_term_deref_member(context, args[0]);
00454 stream.readLine = p_term_create_atom(context, "readLine");
00455 result = p_builtin_read_term(context, &stream);
00456 if (stream.error)
00457 *error = stream.error;
00458 if (result == P_RESULT_TRUE) {
00459 if (!p_term_unify
00460 (context, args[1], stream.parent.read_term,
00461 P_BIND_DEFAULT))
00462 return P_RESULT_FAIL;
00463 }
00464 return result;
00465 }
00466 static p_goal_result p_builtin_iostream_readTerm_3
00467 (p_context *context, p_term **args, p_term **error)
00468 {
00469 struct p_read_term_stream stream;
00470 p_goal_result result;
00471 memset(&stream, 0, sizeof(stream));
00472 stream.parent.context = context;
00473 stream.parent.read_func = p_string_read_func;
00474 stream.parent.generate_vars = 1;
00475 stream.stream = p_term_deref_member(context, args[0]);
00476 stream.readLine = p_term_create_atom(context, "readLine");
00477 result = p_builtin_read_term(context, &stream);
00478 if (stream.error)
00479 *error = stream.error;
00480 if (result == P_RESULT_TRUE) {
00481 if (!p_term_unify
00482 (context, args[1], stream.parent.read_term,
00483 P_BIND_DEFAULT))
00484 return P_RESULT_FAIL;
00485 if (!p_term_unify
00486 (context, args[2], stream.parent.vars,
00487 P_BIND_DEFAULT))
00488 return P_RESULT_FAIL;
00489 }
00490 return result;
00491 }
00492
00493 void _p_db_init_io(p_context *context)
00494 {
00495 static struct p_builtin const builtins[] = {
00496 {"$$iostream_readTerm", 2, p_builtin_iostream_readTerm},
00497 {"$$iostream_readTerm", 3, p_builtin_iostream_readTerm_3},
00498 {"$$iostream_writeTerm", 3, p_builtin_iostream_writeTerm},
00499 {"$$print", 2, p_builtin_print},
00500 {"$$print", 3, p_builtin_print_3},
00501 {"$$print_byte", 2, p_builtin_print_byte},
00502 {"$$print_flush", 1, p_builtin_print_flush},
00503 {"$$print_string", 2, p_builtin_print_string},
00504 {"$$stdin_read_byte", 1, p_builtin_stdin_read_byte},
00505 {"$$stdin_read_bytes", 2, p_builtin_stdin_read_bytes},
00506 {"$$stdin_read_line", 1, p_builtin_stdin_read_line},
00507 {0, 0, 0}
00508 };
00509 _p_db_register_builtins(context, builtins);
00510 }