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 }