summaryrefslogtreecommitdiffstats
path: root/stream.c
Commit message (Collapse)AuthorAgeFilesLines
* cygwin: environment-related fixes.Kaz Kylheku2021-10-051-2/+2
| | | | | | | * stream.c (run): replace_env takes only one argument. * tests/018/process.tl: *child-env* tests are reporting some extra environment variables on Windows; let's just disable them.
* New variable: *child-env*.Kaz Kylheku2021-09-261-3/+20
| | | | | | | | | | | | | | | | | | | | | | | | | | This specifies the environment to be used for executing programs. * stream.c (open_subprocess, run): Check *child-env* variable and if other than t, then install the environment before execvp. In the spawn-based version of run, we save and restore the environment around the spawn call, if *child-env* is in effect. * sysif.c (child_env_s): New symbol variable. (exec_wrap): If *child-env* is other than t, then save the environment in a list, and install the specified environment before calling execvp. If that function returns, restore the environbment. * sysif.h (child_env_s): Declared. (child_env): New macro. * tests/018/process.tl: New tests. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* path-search: rewrite in C with saner semantics.Kaz Kylheku2021-09-251-2/+30
| | | | | | | | | | | | | | | | | | | | | | | | | | The new function: - just returns the name if it contains path name components. - returns nil if the name is "." or "..". - tests for existence only, not permission to execute. * lisplib.c (path_test_set_entries): Do not auto-load path-test module on the path-search symbol, since it is no longer implemented there. * stdlib/path-test.tl (path-search): Function removed. * stream.c (path_var_sep_char): New global variable. (path_search): New function. (detect_path_separators): Also set path_var_sep_char to semicolon on Cygnal. (stream-init): Register path-search intrinsic here now. * stream.h (path_var_sep_char, path_search): Declared. * tests/018/path-test.tl: New tests. * txr.1: Documentation revised for path-search.
* exceptions: hack to store errno in string object.Kaz Kylheku2021-09-071-47/+47
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Basic idea: when we throw an exception that pertains to a system error which has an errno code, we can stick the errno into the memory area of the character string, into the wchar_t that immediately follows the null terminator. We can do this because strings track their actual allocation size. A pair of setter/getter functions to set and retrieve this value are provided, and all functions in the code which can set such a code are updated to do so, simply by calling the newly added uw_ethrowf that drop-in replaces for uw_throwf. * lib.[ch] (string_set_code, string_get_code): New functions. * unwind.[ch] (uw_ethrowf): New function. * eval.c (eval_init): Register string-set-code and string-get-code intrinsics. * ftw.c (ftw_wrap): Switch to uw_ethrowf. * parser.c (open_txr_file): Likewise. * socket.c (dgram_overflow): Store the ENOBUFS error in errno, and use uw_ethrowf instead uw_throwf. (dgram_get_byte_callback, dgram_flush, sock_bind, to_connect, open_sockfd, sock_connect, sock_listen, sock_accept, sock_shutdown, sock_timeout, socketpair_wrap): Switch to uw_ethrowf. * stream.c (dev_null_get_fd, stdio_maybe_read_error, stdio_maybe_error, stdio_close, pipe_close, open_directory, open_file, open_fileno, open_tail, fds_subst, open_subprocess, open_command, remove_path, rename_path, tmpfile_wrap, mkdtemp_wrap, mkstemp_wrap): Switch to uw_ethrowf. * sysif.c (mkdir_wrap, ensure_dir, chdir_wrap, getcwd_wrap, rmdir_wrap, mknod_wrap, mkfifo_wrap, chmod_wrap, do_chown, symlink_wrap, link_wrap, readlink_wrap, close_wrap, val exec_wrap, stat_impl, do_utimes, pipe_wrap, poll_wrap, getgroups_wrap, setuid_wrap, seteuid_wrap, setgid_wrap, setegid_wrap, setgroups_wrap, getresuid_wrap, setresuid_wrap, setresgid_wrap, crypt_wrap, uname_wrap, opendir_wrap, getrlimit_wrap, setrlimit_wrap): Likewise. * termios.c (tcgetattr_wrap, tcsetattr_wrap, tcsendbreak_wrap, tcdrain_wrap, tcflush_wrap, tcflow_wrap): Likewise. * tests/018/errno.tl: New file. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* open-file: improvement: "a" mode sets create flag.Kaz Kylheku2021-08-291-2/+2
| | | | | | | * stream.c (w_fopen_mode): Only test the m.create flag as the basis for O_CREAT, not m.append. (do_parse_mode): In the 'a' case, set m.create = 1, since all variants of append mode create the file.
* open-file: add mode option "x".Paul A. Patience2021-08-291-1/+11
| | | | | | | | | | | | * stream.h (struct stdio_mode): New member, excl flag. (stdio_mode_init_blank, stdio_mode_init_r, stdio_mode_init_rpb): Add initializer for excl flag. * stream.c (do_parse_mode): Handle 'x' in mode string. (w_fopen_mode): Add O_EXCL flag if m.excl is set. Throw an error if we don't HAVE_FCNTL and m.excl is set. * txr.1: Document mode option "x".
* open-file: fix broken file-creation modes.Paul A. Patience2021-08-291-2/+3
| | | | | | | | The "w+", "m+" and "a+" modes wouldn't create the file. * stream.c (w_fopen_mode): Add O_TRUNC and O_CREAT flags if m.create or m.append is set, rather than if m.read is unset and m.write is set.
* open-file: fix broken "+" mode string.Paul A. Patience2021-08-281-2/+1
| | | | | | | | The "+" mode string should be equivalent to "r+", according to the manual, but before this change it was equivalent to "r". * stream.c (do_parse_mode): Unconditionally set m.write to 1 when "+" is present in the mode string.
* license: reformat to fit 80 columns.Kaz Kylheku2021-08-161-12/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * Makefile, alloca.h, args.c, args.h, arith.c, arith.h, buf.c, buf.h, chksum.c, chksum.h, chksums/crc32.c, chksums/crc32.h, combi.c, combi.h, debug.c, debug.h, eval.c, eval.h, ffi.c, ffi.h, filter.c, filter.h, ftw.c, ftw.h, gc.c, gc.h, glob.c, glob.h, hash.c, hash.h, itypes.c, itypes.h, jmp.S, lib.c, lib.h, lisplib.c, lisplib.h, match.c, match.h, parser.c, parser.h, parser.l, parser.y, rand.c, rand.h, regex.c, regex.h, signal.c, signal.h, socket.c, socket.h, stdlib/asm.tl, stdlib/awk.tl, stdlib/build.tl, stdlib/compiler.tl, stdlib/constfun.tl, stdlib/conv.tl, stdlib/copy-file.tl, stdlib/debugger.tl, stdlib/defset.tl, stdlib/doloop.tl, stdlib/each-prod.tl, stdlib/error.tl, stdlib/except.tl, stdlib/ffi.tl, stdlib/getopts.tl, stdlib/getput.tl, stdlib/hash.tl, stdlib/ifa.tl, stdlib/keyparams.tl, stdlib/match.tl, stdlib/op.tl, stdlib/optimize.tl, stdlib/package.tl, stdlib/param.tl, stdlib/path-test.tl, stdlib/pic.tl, stdlib/place.tl, stdlib/pmac.tl, stdlib/quips.tl, stdlib/save-exe.tl, stdlib/socket.tl, stdlib/stream-wrap.tl, stdlib/struct.tl, stdlib/tagbody.tl, stdlib/termios.tl, stdlib/trace.tl, stdlib/txr-case.tl, stdlib/type.tl, stdlib/vm-param.tl, stdlib/with-resources.tl, stdlib/with-stream.tl, stdlib/yield.tl, stream.c, stream.h, struct.c, struct.h, strudel.c, strudel.h, sysif.c, sysif.h, syslog.c, syslog.h, termios.c, termios.h, time.c, time.h, tree.c, tree.h, txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h, vm.c, vm.h, vmop.h: License reformatted. * lex.yy.c.shipped, y.tab.c.shipped, y.tab.h.shipped: Updated.
* format: bug: sign not reset before each conversion.Kaz Kylheku2021-08-161-11/+8
| | | | | | | | | | | | | | | | | | For instance, this bad output is produced: (pic "+0####.## <<<<<" 123 1) -> "+00123.00 +1 " The second argument should not have any leading + sign. * stream.c (formatv): For each new conversion specifier introduced by ~, reset the sign variable to zero also. That's the semantic change here, occluded by the fact that I'm rearranging the declaration of the variables, adding comments, and condensing the assignments while also getting them into the same order as the declarations, in order that this sort of bug does not creep in in the future, should another such variable be added. * tests/018/format.tl: Adding correct version of above test case.
* close-stream: make idemponent.Kaz Kylheku2021-08-041-5/+11
| | | | | | | | | | | | | | | | | | * stream.c (strm_base_init): Add new element to the initializer to initialize the close_result member to nao, indicating that the close operation has not been invoked. (strm_base_mark): Mark the close_result value, if it isn't nao. This is just in case it is a heap object. The structure delegate mechanism opens the possibility that the stream is actually user code that can return anything so we have to be careful. (close_stream): Only call ops->close if close_result is nao, indicating that close had never been called (or possibly that it had been called bu threw an exception) and store the return value in close_result, otherwise return the previously stored value. * stream.h (struct strm_base): New member, close_result. * txr.1: Documented.
* streams: bad argument defaulting in close-stream.Kaz Kylheku2021-08-021-3/+3
| | | | | | | | | | | | | | | * stream.c (stdio_close, pipe_close): Fix throw_on_error argument not being defaulted correctly, so that errors are thrown even when the argument is omitted. * strudel.c (strudel_close): Here, we also must default the argument. The corresponding close method does not have an optional argument; it is mandatory. The documentation is bungled for it, though. * txr.1: Fix documentation of structure delegate streams with regard to the close method. It does not take offs and whence parametrs, but throw-on-error-p, which is mandatory.
* pure-rel-path-p: rewrite without regex.Kaz Kylheku2021-07-221-15/+21
| | | | | | | | * stream.c (volume_name_p): New static function. (plp_regex): Static variable removed. (pure_rel_path_p): Rewrite using lower-level string manipulation, and using volume_name_p instead of a cached regex. (stream_init): Remove reference to plp_regex.
* compat: fix glaringly broken init-time handling.Kaz Kylheku2021-07-211-3/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We are doing numerous compat_ver checks in various init functions, to enact alternative symbol registrations. Only problem is, compat_ver is always zero during initialization; it is not set until the -C option is processed in txr_main. Registrations must be fixed up after initialization; that's what the compat_fixup mechanism is for. This is an long-standing problem which affects compatibility operation going back over 150 versions. * arith.c (arith_init): Move compat logic to arith_compat_fixup. (arith_compat_fixup): New function. * arith.h (arith_compat_fixup): Declared. * eval.c (eval_init): Move compat logic to eval_compat_fixup. * ffi.c (ffi_init): Move compat logic to ffi_compat_fixup. (ffi_compat_fixup): New function. * ffi.h (ffi_compat_fixup): Declared. * regex.c (regex_init): Move compat logic to regex_compat_fixup. (regex_compat_fixup): New function. * regex.h (regex_compat_fixup): Declared. * stream.c (stream_init): Move compat logic to stream_compat_fixup. (stream_compat_fixup): New function. * stream.h (stream_compat_fixup): Declared. * struct.c (struct_init): Move compat logic to struct_compat_fixup. (struct_compat_fixup): New function. * struct.h (stream_compat_fixup): Declared. * lib.c (compat_fixup): Call arith_compat_fixup, ffi_compat_fixup, regex_compat_fixup, stream_compat_fixup and struct_compat_fixup.
* abs-path-p: rewrite in lower-level C.Kaz Kylheku2021-07-151-23/+34
| | | | | | | | | * stream.c (ap_regex): Static variable removed. (volume_prefix_p): New function. (abs_path_p, portable_abs_path_p): Get wchar_t * string from path and manipulate using C idioms. Use volume_prefix_p function for testing for drive letter or UNC prefix. (stream_init): Remove reference to ap_regex.
* New function: add-suffix.Kaz Kylheku2021-07-101-0/+48
| | | | | | | | | | | * stream.c, stream.h (add_suffix): New function. (stream_init): add-suffix intrinsic registered. * tests/018/path.tl: Tests. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* New functions: trim-short-suffix, trim-long-suffix.Kaz Kylheku2021-07-101-0/+64
| | | | | | | | | | | | | | | * lib.c, lib.h (chk_substrdup): New function. * stream.c, stream.h (trim_short_suffix, trim_long_suffix): New functions. (stream_init): trim-short-suffix and trim-long-suffix intrinsics registered. * tests/018/path.tl: New tests. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* type: disallow structs using built-in type names.Kaz Kylheku2021-07-081-55/+60
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This is a big commit motivated by the need to clean up the situation with built-in type symbols, COBJ objects and structs. The struct type system allows struct types to be defined for symbols like regex or str, which are used by built-in or cobj types. This is a bad thing. What is worse, structure instances are COBJ types which identify their type using the COBJ class symbol mechanism. There are places in the C implementation which assume that when a COBJ has a certain class symbol, it is of a certain expected type, which is totally different from and incompatible form a struct instance. User code can define a structure object which will fool that code. There are multiple things going on in this patch. The major theme is that the COBJ representation is changing. Instead of a class symbol, COBJ instances now carry a "struct cobj_class *" pointer. This pointer is obtained by registration via the cobj_register function. All modules must register their class symbols to obtain these class handles, which are then used in cobj() calls for instantiation. The CPTR type was identical to COBJ until now, except for the type tag. This is changing; CPTR objects will keep the old representation with the class symbol. commit 20fdfc6008297001491308849c17498c006fe7b4 Author: Kaz Kylheku <kaz@kylheku.com> Date: Thu Jul 8 19:17:39 2021 -0700 * ffi.h (carray_cls): Declared. * hash.h (hash_cls): Declared. (hash_early_init): Declared. * lib.h (struct cobj_class): New struct. (struct cobj): cls member changing to struct cobj_class *. (struct cptr): New struct, same as previous struct cobj. (union obj): New member cp of type struct cptr, for CPTR. (builtin_type): Declared. (class_check): Declaration moved closer to COBJ-related functions and updated. (cobj_register, cobj_register_super, cobj_class_exists): New functions declared. (cobjclassp, cobj_handle, cobj_ops): Declarations updated. * parser.h (parser_cls): Declared. * rand.h (random_state_cls): Declared. * regex.h (regex_cls): Declared. * stream.h (stream_cls, stdio_stream_cls): Declared. * struct.h (struct_cls): Declared. * tree.h (tree_cls, tree_iter_cls): Declared. * vm.h (vm_desc_cls): Declared. * buf.c (buf_strm, make_buf_stream): Pass stream_cls functions instead of stream_s class symbol. * chksum.c (sha256_ctx_cls, md5_ctx_cls): New static class handles. (sha256_begin, sha256_hash, sha256_end, md5_begin, md5_hash, md5_end): Pass class handles to instead of class symbols. (chksum_init): Initialize class handle variables. * ffi.c (ffi_type_cls, ffi_call_desc_cls, ffi_closure_cls, union_cls): New static class handles. (carray_cls): New global variable. (ffi_type_struct_checked, ffi_type_print_op, ffi_closure_struct_checked, ffi_closure_print_op, make_ffi_type_builtin, make_ffi_type_pointer, make_ffi_type_struct, make_ffi_type_union, make_ffi_type_array, make_ffi_type_enum, ffi_call_desc_checked, ffi_call_desc_print_op, ffi_make_call_desc, ffi_make_closure, carray_struct_checked, carray_print_op, make_carray, cptr_getobj, cptr_out, uni_struct_checked, make_union_common): Pass class handles instead of class symbols. (ffi_init): Initialize class handle variables. * filter.c (regex_from_trie): Use hash_cls class handle instead of hash_s. * gc.c (mark_obj): Split COBJ and CPTR cases since the representation is different. * hash.c (hash_cls, hash_iter_cls): New class handles. (make_similar_hash, copy_hash, gethash_c, gethash_e, remhash, clearhash, hash_count, get_hash_userdata, set_hash_userdata, hashp, hash_iter_init, hash_begin, hash_next, hash_peek, hash_reset, hash_reset, hash_uni, hash_diff, hash_symdiff, hash_isec): Pass class handles instead of class symbols. (hash_early_init): New function. (hash_init): Set the class symbols in the class handles that were created in hash_early_init at a time when these symbols did not exist. * lib.c (nelem): New macro. (cobj_class): New static array. (cobj_ptr): New static pointer. (cobj_hash): New static hash. (seq_iter_cls): New static class handle. (builtin_type_p): New function. (typeof): Struct instances now all carry the same symbol, struct, as their COBJ class symbol. To get their type, we must call struct_type_name. (subtypep): Rearrangement of two cases: let's make the reflexive case first. Adjust code for different location of COBJ class symbol. (seq_iter_init_with_info, seq_begin, seq_next, seq_reset, iter_begin, iter_more, iter_item, iter_step, iter_reset, make_like, list_collect, do_generic_funcall): Use class handles instead of class symbols. (class_check, cobj, cobjclassp, cobj_handle, cobj_ops): Take class handle argument instead of class symbol. (cobj_register, cobj_register_super, cobj_class_exists): New functions. (cobj_populate_hash): New static function. (cobj_print_op): Adjust for different location of class (cptr_print_op, cptr_typed, cptr_type, cptr_handle, cptr_get): cptr functions now refer to obj->cp rather than obj->co. (copy, length, sub, ref, refset, replace, dwim_set, dwim_del, obj_print): Use class handles for various COBJ types rather than class symbols. (obj_init): gc-protect cobj_hash. Initialize seq_iter_cls class symbol and cobj_hash. Populate cobj_hash as the last initialization step. (init): Call hash_early_init immediately after gc_init. diff --git a/lib.c b/lib.c * match.c (do_match_line): Refer to regex_cls class handle instead of regex_s.. * parser.c (parser_cls): New global class handle. (parse, parser_get_impl, lisp_parse_impl, txr_parse, parser_errors): Use class handles instead of class symbols. (parse_init): Initialize parser_cls. * rand.c (random_state_cls): New global class handle. (make_state, random_state_p, make_random_state, random_state_get_vec, random_fixnum, random_float, random): Use class handles instead of class symbols. (rand_init): Initialize random_state_cls. * regex.c (regex_cls): New global class handle. (chset_cls): New static class handle. (reg_compile_csets, reg_derivative, regex_compile, regexp, regex_source, regex_print, regex_run, regex_machine_init): Use class handles instead of class symbols. (regex_init): Initialize regex_cls and chset_cls. * socket.c (make_dgram_sock_stream): Use stream_cls class symbol instead of stream_s. * stream.c (stream_cls, stdio_stream_cls): New class handles. (make_null_stream, stdio_get_fd, make_stdio_stream_common, stream_fd, sock_family, sock_type, sock_peer, sock_set_peer, make_dir_stream, make_string_input_stream, make_string_byte_input_stream, make_strlist_input_stream, make_string_output_stream, make_strlist_output_stream, get_list_from_stream, make_catenated_stream, make_delegate_stream, make_delegate_stream, stream_set_prop, stream_get_prop, close_stream, get_error, get_error_str, clear_error, get_line, get_char, get_byte, get_bytes, unget_char, unget_byte, put_buf, fill_buf, fill_buf_adjust, get_line_as_buf, format, put_string, put_char, put_byte, flush_stream, seek_stream, truncate_stream, get_indent_mode, test_set_indent_mode, test_neq_set_indent_mode, set_indent_mode, get_indent, set_indent, inc_indent, width_check, force_break, set_max_length, set_max_depth): Use class handle instead of symbol. (stream_init): Initialize stream_cls and stdio_stream_cls. * struct.c (struct_type_cls, struct_cls): New class handles. (struct_init): Initialize struct_type_cls and struct_cls. (struct_handle): Static function moved to avoid forward declaration. (stype_handle): Refer to struct_type_cls class handle instead of struct_type_s symbol. Handle instance objects in addition to types. (make_struct_type): Throw error if a built-in type is being defined as a struct type. Refer to class handle instead of class symbol. (find_struct_type, allocate_struct, make_struct_impl, make_lazy_struct, copy_struct): Refer to class handle instead of class symbol. * strudel.c (make_struct_delegate_stream): Refer to stream_cls class handle instead of stream_s symbol. * sysif.c (dir_cls): New class handle. (poll_wrap): Use typep instead of subtypep, eliminating access to class symbol. (opendir_wrap, closedir_wrap, readdir_wrap): Use class handles instead of class symbols. (sysif_init): Initialize dir_cls. * syslog.c (make_syslog_stream): Refer to stream_cls class handle instead of stream_s symbol. * tree.c (tree_cls, tree_iter_cls): New class handles. (tree_insert_node, tree_lookup_node, tree_delete_node, tree_root, tree_equal_op, tree, copy_search_tree, make_similar_tree, treep, tree_begin, copy_tree_iter, replace_tree_iter, tree_reset, tree_next, tree_peek, tree_clear): Use class handle instead of class symbol. (tree_init): Initialize tree_cls and tree_iter_cls. * unwind.c (sys_cont_cls): New static class handle. (revive_cont, capture_cont): Use class handle instead of class symbol. (uw_late_init): Initialize sys_cont_cls. * vm.c (vm_desc_cls): New global class handle. (vm_closure_cls): New static class handle. (vm_desc_struct, vm_make_desc, vm_closure_struct, vm_make_closure, vm_copy_closure): Use class handle instead of class symbol. (vm_init): Initialize vm_desc_cls and vm_closure_cls.
* streams: put-string, put-char: missing type check.Kaz Kylheku2021-07-071-2/+4
| | | | | | | * stream.c (put_string, put_char): Use cobj_handle to validate the object, rather than directly accessing stream->co.handle. This was reported as a (put-line "foo" nil) crash reported by Paul A. Patience.
* sh: reduce scope of variables.Kaz Kylheku2021-07-061-1/+1
| | | | | * streamc (shell, shell_arg): External variables become internal.
* streams: do not close stderr.Kaz Kylheku2021-07-061-1/+1
| | | | | | | * stream.c (stdio_close): Recognize stderr, not only stdin and stdout, as one of the streams not to be closed. This fixes situations when stderr is closed and exception handling tries to use it.
* unwind: refer to top-level *stderr* stream.Kaz Kylheku2021-07-061-1/+4
| | | | | | | | | | | | | | | | | | | | | Exception processing should refer to the original, top-level value of *stderr* rather than the current dynamic value, even if unwinding has not yet taken place. Using the dynamic value can not only cause critical output to disappear, but it leads to a false positive identification of the "unhandled exception in early initialization" situation, a diagnostic which is emitted on the C stderr if the Lisp one is unavailable, which is assumed to be due to initialization not having yet completed. * stream.c (top_stderr): New global variable. (stream_init): GC-protect top_stderr, and initialize it with the same object that goes into the *stderr* top-level binding. * stream.h (top_stderr): Declared. * unwind.c (uw_unwind_to_exit_point, uw_rthrow): Use top_stderr instead of std_error macro.
* suffix functions: ignore trailing slashes.Kaz Kylheku2021-07-031-3/+4
| | | | | | | | | | | | | | | | Another requirements tweak to short-suffix and long-suffix: ignore one or more trailing slashes, instead of just one. This harmonizes with base-name, which does same, that requirement being copies from the POSIX basename utility. * stream.c (short_suffix, long_suffix): If sl points to a trailing slash which is the start of a suffix that consists of nothing but trailing slashes, then we pretend it isn't there. * tests/018/path.tl: Adjusted two existing test cases, and added more. * txr.1: Documented.
* streams: tightening sloppy argument defaulting.Kaz Kylheku2021-07-011-23/+26
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Numerous functions in TXR Lisp treat a nil argument for an optional parameter as if it were omitted. In the case of streams, this can cause problems. An accidental nil passed to an input function can cause it to read from standard input and hang. In this patch, argument defaulting is tighented for functions that perform I/O. It's mostly stream parameters, but not exclusively. * eval.c (prinl, pprinl): Use default_arg_strict to default the stream argument, and also re-use that value for the put_char call. * lib.c (lazy_stream_cons, print, pprint, put_json): Use default_arg_strict rather than default_arg. * parser.c (regex_parse, lisp_parse_impl, txr_parse): Tighten the defaulting of the input stream and error stream arguments, streamlining the logic at the same time. * stream.c (do_parse_mode): Use default_arg_strict for the mode string argument. (record_adapter, get_line, get_char, get_byte, get_bytes, unget_byte, put_buf, fill_buf, fill_buf_adjust, get_line_as_buf, put_string, put_char, put_byte, put_line, flush_stream, get_string): Use strict defaulting for stream argument. (mkstemp_wrap): Use strict defaulting for suffix.
* path-cat: becomes variadic.Kaz Kylheku2021-06-291-1/+20
| | | | | | | | | | | | | * stream.c (path_vcat): New static function. (stream_init): Register path-cat instrinsic to path_vcat rather than path_cat. * tests/018/path.tl: path-cat tests: all examples from documentation, plus others. * txr.1: Documented existing behaviors that were not clear, like when inputs are empty. Documented new variadic semantics. Examples added.
* path-cat: error if arguments are not strings.Kaz Kylheku2021-06-291-2/+2
| | | | | * stream.c (path_cat): Use length_str to enforce a type check. Otherwise, for instance, (path-cat #() "foo") will return "foo".
* base-name: bug with empty string suffix.Kaz Kylheku2021-06-261-1/+1
| | | | | | | | * stream.c (base_name): We must check for a zero length suffix, otherwise sub(base, zero, neg(length(suff))) produces an empty string. * tests/018/path.tl: Test cases for base-name.
* suffix functions: requirements change.Kaz Kylheku2021-06-261-4/+4
| | | | | | | | | | | | | | | | | The short-suffix and long-suffix functions will now return the suffix including the leading period. This was a suggestion from user Paul A. Patience, which is a good requirement. Since these functions were newly introduced just the last release, I'm not going to provide backwards compatibility switching for them. * stream.c (short_suffix, long_suffix): Duplicate the suffix starting at the dot, not dot + 1. * tests/018/path.tl: Test cases updated. * txr.1: Documentation updated.
* suffix functions: leading dot is not delimiterKaz Kylheku2021-06-261-2/+5
| | | | | | | | | | * stream.c (short_suffix, long_suffix): Do not treat the starting dot of the last componet as a suffix delimiter. * tests/018/path.tl: Test cases edited to reflect requirements change; new tests added. * txr.1: Updated.
* long-suffix: fix crash reproducing on Cygwin.Kaz Kylheku2021-06-231-3/+1
| | | | | | * stream.c (long_suffix): Remove stray wcspbrk(dot, psc) call from the body of loop, which sometimes occurs when dot is null. It may have been optimized away, so I didn't notice.
* c_str now takes a self argument.Kaz Kylheku2021-06-231-47/+69
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Adding a self parameter to c_str so that when a non-string occurs, the error is reported against a function. Legend: A - Pass existing self to c_str. B - Define self and pass to c_str and possibly other functions. C - Take new self parameter and pass to c_str and possibly other functions. D - Pass existing self to c_str and/or other functions. E - Define self and pass to other functions, not c_str. X - Pass nil to c_str. * buf.c (buf_strm_put_string, buf_str): B. * chksum.c (sha256_str, md5_str): C. (sha256_hash, md5_hash): D. * eval.c (load): D. * ffi.c (ffi_varray_dynsize, ffi_str_put, ffi_wstr_put, ffi_bstr_put): A. (ffi_char_array_put, ffi_wchar_array_put): C. (ffi_bchar_array_put): A. (ffi_array_put, ffi_array_out, ffi_varray_put): D. * ftw.c (ftw_wrap): A. * glob.c (glob_wrap): A. * lib.c (copy_str, length_str, coded_length,split_str_set, list_str, cmp_str, num_str, out_json_str, out_json_rec, display_width): B. (upcase_str, downcase_str, string_extend, search_str, do_match_str, do_rmatch_str, sub_str, replace_str, cat_str_append, split_str_keep, trim_str, int_str, chr_str, span_str, compl_span_str, break_str, length_str_gt, length_str_ge, length_str_lt, length_str_le, find, rfind, pos, rpos, mismatch, rmismatch): A. (c_str): Add self parameter and use in type mismatch diagnostic. If the parameter is nil, use "internal error". (flo_str): B, and correction to "flot-str" typo. (out_lazy_str, out_quasi_str, obj_print_impl): D. * lib.h (c_str): Declaration updated. * match.c (dump_var): X. (v_load): D. * parser.c (open_txr_file): C. (load_rcfile): E. (find_matching_syms, provide_atom): X. (hist_save, repl): B. * parser.h (open_txr_file): Declaration updated. * parser.y (chrlit): X. * regex.c (search_regex): A. * socket.c (getaddrinfo_wrap, sockaddr_pack): A. (dgram_put_string): B. (open_sockfd): D. (sock_connect): E. * stream.c (stdio_put_string, tail_strategy, vformat_str, open_directory, open_file, open_tail, remove_path, rename_path, tmpfile_wrap, mkdtemp_wrap, mkstemp_wrap): B. (do_parse_mode, parse_mode, make_string_byte_input_stream): B. (normalize_mode, normalize_mode_no_bin): E. (string_out_put_string, formatv, put_string, open_fileno, open_subprocess, open_command, base_name, dir_name, short_suffix, long_suffix): A. (run): D. (win_escape_cmd, win_escape_arg): X. * stream.h (parse_mode, normalize_mode, normalize_mode_no_bin): Declarations updated. * sysif.c (mkdir_wrap, do_utimes, dlopen_wrap, dlsym_wrap, dlvsym_wrap): A. (do_stat, do_lstat): C. (mkdir_nothrow_exists, ensure_dir): E. (chdir_wrap, rmdir_wrap, mkfifo_wrap, chmod_wrap, symlink_wrap, link_wrap, readlink_wrap, exec_wrap, getenv_wrap, setenv_wrap, unsetenv_wrap, getpwnam_wrap, getgrnam_wrap, crypt_wrap, fnmatch_wrap, realpath_wrap, opendir_wrap): B. (stat_impl): statfn pointer-to-function argument now takes self parameter. When calling it, we pass name. * syslog.c (openlog_wrap, syslog_wrapv): A. * time.c (time_string_local, time_string_utc, time_string_meth, time_parse_meth): A. (strptime_wrap): B. * txr.c (txr_main): D. * y.tab.c.shipped: Updated.
* short-suffix, long-suffix: no match across slash.Kaz Kylheku2021-06-221-2/+30
| | | | | | | | | | | * stream.c (short_suffix, long_suffix): Take path separator characters into account; the suffix must not span across separators. The trailing separator must also not appear in the suffix. * tests/018/path.tl: Test cases added. * txr.1: Redocumented.
* New functions: long-suffix, short-suffix.Kaz Kylheku2021-06-221-0/+16
| | | | | | | | | | | | | | * stream.c (short_suffix, long_suffix): New functions. (stream_init): short-suffix and long-suffix intrinsics registered. * stream.c (short_suffix, long_suffix): Declared. * tests/018/path.tl: New file. * txr.1: Documented. * share/txr/stdlib/doc-syms.tl: Updated.
* subprocesses: cygwin fixes.Kaz Kylheku2021-06-201-2/+2
| | | | | | | | | | | | | | * stream.c (fds_subst, fds_swizzle, fds_restore): These functions are used on Cygwin by some functions that are based on spawn, and so must be avaiable. * tests/018/process.tl: Two fixes here. Firstly, the 1>&1 redirection in one of the tests should be 1>&2 on all platforms. That a temporary edit left behind from massaging the tests and the code. Secondly, some weird results are observed on Cygwin. The communication with the child sees an extra carriage return and space sneak in. I'm just codifying this as Cygwin's way of passing the test case; it's likely unfixable at the application level.
* streams: pipe streams not needed if we have fork.Kaz Kylheku2021-06-191-3/+5
| | | | | | | | | | * stream.c (se_pclose, make_pipe_stream): define only if !HAVE_FORK_STUFF. (pipe_close): Don't call se_pclose in HAVE_FORK_STUFF build. The pipe_ops are no longer shared between popen pipes and open-process pipes. * stream.h (make_pipe_stream): Conditionally declare.
* system: stop using popen if we have fork.Kaz Kylheku2021-06-191-35/+58
| | | | | | | | | | | | | | | | | | | | | | | | On all the platforms on which TXR is regularly built, there is fork, including the Windows port via Cygwin. We therefore don't have to be using popen for the open-command function. The handling the stream redirection will be more efficient if we implement open-command in terms of open-process, and the special mode string extensions for redirection like ">21" will work, too. * stream.c (fds_subst, fds_swizzle): Define these functions only for !HAVE_FORK_STUFF platforms. (open_command): popen-based implementation moved down into a section of code for !HAVE_FORK_STUFF platforms. A separate implementation is written for HAVE_FORK_STUFF platforms which passes the command to an appropriate Windows native or POSIX interpreter. * utf8.c (w_popen): Nothing but open-command calls this function, so we don't need it on HAVE_FORK_STUFF platforms. Wrap with #if. * utf8.h (w_popen): wrap with #if.
* subprocesses: don't bother saving descriptors.Kaz Kylheku2021-06-151-2/+21
| | | | | | | | | | * stream.c (fds_subst_nosave): New static function. (fds_clobber): New static function. Like fds_swizzle, without the saving. (open_subprocess, run): Use fds_clobber instead of fds_swizzle in the child process. It makes no sense to use fds_swizzle, which saves duplicates of the old descriptors, if fds_restore is not going to be called.
* subprocesses: move fds_swizzle to child process.Kaz Kylheku2021-06-151-29/+41
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In all cases in which we control fork and exec, we should be doing the fds_swizzle setup in the child process. This has several benefits. We do not disturb the file descriptor layout of the parent. We don't have to set up a catch to do the cleanup. We don't have to do the clean-up in the child either; but just let it terminate. * stream.c (struct save_fds): New members subin, subout and suberr to hold the substitute file descriptors. The reason for this is so that we can calculate these in the parent process so that all the error checking is done in the parent and and carry them over to the child somehow. This structure is the natural place for that. (fds_getfd): New static function: just does the job of fetching and validating the file descriptor from the given stream: the first part of fds_subst. This will be done in the parent. (fds_subst): Now just does the substitution using a given file descriptor. Done in the child. Some variable renaming here; a better name for fd_orig is fd_sub, the substitute descriptor. (fds_prepare): New function: called in the parent process, it obtains the three file descriptors from the streams. (fds_swizzle): Just do fd_subst with the ready-made file descriptors, not dealing with the streams. Called in the child. (open_command): Add fds_prepare call that is now needed. (open_subprocess, run): Get rid of catch frame. Just call fds_prepare where fds_swizzle was previously called, and only call fds_swizzle in the child process.
* subprocesses: diagnose streams with no fileno.Kaz Kylheku2021-06-151-3/+9
| | | | | | | | * stream.c (fds_subst): Check that stream_fd returns a non-integer; if so, put out a more meaningful diagnostic, rather than allowing c_num to generate a "nil is not an integer" error. Also, let's incorporate the self string into the existing failed dup diagnostic.
* streams: *stdnull* lazily opens /dev/nullKaz Kylheku2021-06-141-6/+45
| | | | | | | | | | | | | | | | | | | | | The *stdnull* stream has been purely a stream-level abstraction. To make it useful for redirecting real file descriptors around the execution of external programs, we endow it with the ability to open /dev/null when it is asked to provide its file descriptor. * stream.c (struct dev_null): New structure. (dev_null_close, dev_null_get_fd, dev_null_get_prop): New static functions. (null_ops): Wire in the above functions instead of null_close, null_get_fd and null_get_prop. We need new functions because null_close and others do not belong to just the null stream; they are base operations used by other streams as default implementations for some kinds of unimplemented functions. (make_null_stream): Alocate a struct dev_null instead of a struct strm_base. Set the fd to -1. * txr.1: Documented.
* format: revise numeric handling.Kaz Kylheku2021-06-141-8/+24
| | | | | | | | | | | | | | | | | | | | | | | There are a number of issues, such as left adjustment not working and such. This needs a better treatment from the requirements level, through to a set of test cases. * stream.c (max, min): Macros macros added, in their usual form. (vformat_num): Implement new rules which suppress the zero and space characters used in place of a sign if they overflow the field width. (formatv): Clamp integer precision field to width - 1 for integers, for consistency with floating-point handling. For floating-point values under ~a and ~s, do not force the second stage precision to width - 1; only clamp it if it is greater. * format.tl: Numerous new tests. * txr.1: Significant redocumenting of this area. The handling of numbers is described as a two stage process, clarifying the changing role of "precision" in the two stages.
* format: new precision - character for zero.Kaz Kylheku2021-06-141-0/+3
| | | | | | | | | | | * stream.c (formatv): The - precision option character produces a "sign" that is a zero. If this is used with leading zeros, it will avoid generating a space. The requirements can use improvement here, but one step at a time. * tests/018/format.tl: Some tests. * txr.1: Documented.
* format: fix precision field leading zero problems.Kaz Kylheku2021-06-101-2/+9
| | | | | | | | | | | | | | | | | * stream.c (formatv): Do not recognize multiple leading zeros as a single one; once the zero flag is set, if another zero is seen, it must be treated as one of the digits specifying the precision value. New requirement: before processing a format specifier, check for the situation that the leading zero has been specified, but no precision. Convert this situation to that of a precision of zero being given, with no leading zero. * txr.1: Document the ambiguity around the leading zero and how it is being handled when only the leading zero flag is given, and no actual precision. Add a note about what happens when zero precision is specified in ~a in conjunction with a floating-point value. Misspelled "pas" word fixed.
* solaris: unbundle mkstemp and mkdtemp.Kaz Kylheku2021-06-021-3/+9
| | | | | | | | | | | | | * configure: Solaris 10 doesn't have mkdtemp, so we detect it separately from mkstemp, which Solaris 10 does have, producing HAVE_MKSTEMP and MAKE_MKDTEMP config.h symbols. * stream.c (mkdtemp_wrap): Separately surround with #if HAVE_MKDTEMP. (mkstemp_wrap): Reduce scope of #if HAVE_MKSTEMP only around this function. Bugfix here: in the #else case of #if HAVE_MKSTEMPS, we are calling the mkstemps function instead of mkstemp.
* Pre-release C++ upkeep.Kaz Kylheku2021-06-011-4/+4
| | | | | | | | * stream.c (mkdtemp_wrap): Rename template argument to prefix, because template is a C++ keyword. (mkstemp_wrap): Rename local variable from template to templ. * stream.h (mkdtemp_wrap): Rename template argument.
* json: wrap up: test cases, fixes, tweaks.Kaz Kylheku2021-05-311-1/+1
| | | | | | | | | | | | | | | | | | | | | * /share/txr/stdlib/getput.tl (get-jsons): If the s parameter is a string, convert it to a byte input stream so that. (put-jsons): Add missing t return value. (file-put-json, file-append-json, file-put-jsons, file-append-jsons, command-put-jsons, command-put-jsons): Add missing object argument to all these functions, and a missing "w" open-file mode to several of them. * stream.c (mkstemp_wrap): Calculate length of suff the defaulted argument, not the raw suffix argument. * test/010/json.tl: New file, providing tests that touch every area of the new JSON functionality. * tests/common.tl (mstest, with-temp-file): New macros. * txr.1: Document that get-jsons takes a source which could be a string.
* New: mkdtemp and mkstemp functions.Kaz Kylheku2021-05-311-0/+55
| | | | | | | | | | | | | | | | * configure: check for mkstemp and mkdtemp. * stream.c (stdio_set_prop): Implement setting the :name property. We need this in mkstemp_wrap in order to punch in the temporary name, so that the application can retrieve it. (mkdtemp_wrap, mkstemp_wrap): New functions. (stream_init): Register mkdtemp and mkstemp intrinsics. * stream.h (mkdtemp_wrap, mkstemp_wrap): Declared. * txr.1: Documented. * share/txr/stdlib/doc-syms.tl: Updated.
* New function: tmpfile.Kaz Kylheku2021-05-311-0/+12
| | | | | | | | | | | * stream.c (tmpfile_wrap): New static function. (stream_init): Register tmpfile intrinsic. * stream.h (tmpfile_wrap): Declared. * txr.1: Documented. * share/txr/stdlib/doc-syms.tl: Updated.
* format: use self variable in error messages.Kaz Kylheku2021-05-041-6/+6
| | | | | * stream.c (formatv): Replace hard-coded "format:" with ~a and self argument. Several error messages are revised.
* format: ~x/~X specifiers support buffers.Kaz Kylheku2021-05-041-13/+35
| | | | | | | | | | | | | * buf.c (buf_hex): New function. * buf.h (buf_hex): Declared. * stream.c (formatv): Support printing of buffers in hex via temporary buffer containing hex characters, similarly to how bignums are handled. * tests/018/format.tl: New file, providing some coverage over new and affected code.