/*************************************************************************** subr_file.c The file and input/output subroutines (c) 2000-2007 Benoit Minisini This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #include "gb_common.h" #include "gb_common_buffer.h" #include "gbx_subr.h" #include "gb_file.h" #include "gb_list.h" #include "gbx_stream.h" #include "gbx_archive.h" #include "gbx_api.h" #include "gbx_local.h" #include "gbx_regexp.h" #include "gbx_string.h" #include "gbx_c_file.h" #include "gbx_print.h" typedef struct _stream { struct _stream *next; CSTREAM *stream; } CSTREAM_NODE; static void *_default_in = NULL; static void *_default_out = NULL; static void *_default_err = NULL; static GB_ARRAY _result; static char *_pattern; static int _len_pattern; static int _ignore; static STREAM *_stream; static void push_stream(void **list, CSTREAM *stream) { CSTREAM_NODE *slot; ALLOC(&slot, sizeof(CSTREAM_NODE), "push_stream"); slot->stream = stream; //OBJECT_REF(stream, "push_stream"); slot->next = *list; *list = slot; } static CSTREAM *pop_stream(void **list) { CSTREAM *stream; CSTREAM_NODE *slot; if (!*list) return NULL; stream = ((CSTREAM_NODE *)*list)->stream; slot = *list; *list = slot->next; FREE(&slot, "pop_stream"); return stream; } static STREAM *get_default(intptr_t val) { static STREAM_MEMORY memory_stream; STREAM *stream; switch(val) { case 0: if (_default_in) stream = CSTREAM_stream(((CSTREAM_NODE *)_default_in)->stream); else stream = CSTREAM_stream(CFILE_in); break; case 1: if (_default_out) stream = CSTREAM_stream(((CSTREAM_NODE *)_default_out)->stream); else stream = CSTREAM_stream(CFILE_out); break; case 2: if (_default_err) stream = CSTREAM_stream(((CSTREAM_NODE *)_default_err)->stream); else stream = CSTREAM_stream(CFILE_err); break; default: memory_stream.common.type = &STREAM_memory; memory_stream.addr = (void *)val; memory_stream.pos = 0; stream = (STREAM *)&memory_stream; break; } return stream; } static STREAM *get_stream(VALUE *value, bool can_default) { STREAM *stream; if (TYPE_is_integer(value->type) && can_default) stream = get_default((intptr_t)value->_integer.value); #ifdef OS_64BITS else if (TYPE_is_long(value->type) && can_default) stream = get_default((intptr_t)value->_long.value); #endif else { if (VALUE_is_null(value)) THROW(E_NULL); if (TYPE_is_object(value->type) && OBJECT_class(value->_object.object)->is_stream) stream = CSTREAM_stream(value->_object.object); else { VALUE_conv(value, (TYPE)CLASS_Stream); stream = NULL; } } if (STREAM_is_closed(stream)) THROW(E_CLOSED); return stream; } static char *get_path(VALUE *param) { char *name; int len; SUBR_get_string_len(param, &name, &len); return STRING_conv_file_name(name, len); } void SUBR_open(void) { CFILE *file; STREAM stream; int mode; SUBR_ENTER_PARAM(2); SUBR_check_integer(&PARAM[1]); mode = PARAM[1]._integer.value; STREAM_open(&stream, get_path(PARAM), mode); file = CFILE_create(&stream, mode); OBJECT_put(RETURN, file); SUBR_LEAVE(); } void SUBR_close(void) { SUBR_ENTER_PARAM(1); STREAM_close(get_stream(PARAM, FALSE)); SUBR_LEAVE_VOID(); } void SUBR_flush(void) { SUBR_ENTER_PARAM(1); STREAM_flush(get_stream(PARAM, TRUE)); SUBR_LEAVE_VOID(); } /*static void print_it(char *addr, long len) { STREAM_write(_stream, addr, len); }*/ void SUBR_print(void) { int i; char *addr; int len; SUBR_ENTER(); if (NPARAM < 1) THROW(E_NEPARAM); _stream = get_stream(PARAM, TRUE); //PRINT_init(print_it, FALSE); for (i = 1; i < NPARAM; i++) { PARAM++; //PRINT_value(PARAM); VALUE_to_string(PARAM, &addr, &len); if (len == 1 && *addr == '\n') STREAM_write_eol(_stream); else STREAM_write(_stream, addr, len); } SUBR_LEAVE_VOID(); } void SUBR_linput(void) { STREAM *stream; char *addr; SUBR_ENTER_PARAM(1); stream = get_stream(PARAM, TRUE); STREAM_line_input(stream, &addr); RETURN->type = T_STRING; RETURN->_string.addr = addr; RETURN->_string.start = 0; RETURN->_string.len = STRING_length(addr); SUBR_LEAVE(); } void SUBR_input(void) { static STREAM *stream = NULL; char *addr; SUBR_ENTER(); if (NPARAM == 1) stream = get_stream(PARAM, TRUE); if (stream) { STREAM_input(stream, &addr); VALUE_from_string(RETURN, addr, STRING_length(addr)); if (RETURN->type == T_NULL) { RETURN->type = T_STRING; RETURN->_string.addr = addr; RETURN->_string.start = 0; RETURN->_string.len = STRING_length(addr); } } else RETURN->type = T_NULL; SUBR_LEAVE(); } void SUBR_eof(void) { STREAM *stream; SUBR_ENTER(); if (NPARAM == 1) stream = get_stream(PARAM, FALSE); else stream = get_default(0); //fprintf(stderr, "Eof(stream) = %d\n", STREAM_eof(stream)); RETURN->type = T_BOOLEAN; RETURN->_boolean.value = STREAM_eof(stream) ? -1 : 0; SUBR_LEAVE(); } void SUBR_lof(void) { STREAM *stream; SUBR_ENTER(); if (NPARAM == 1) stream = get_stream(PARAM, FALSE); else stream = get_default(0); RETURN->type = T_LONG; STREAM_lof(stream, &(RETURN->_long.value)); SUBR_LEAVE(); } void SUBR_seek(void) { STREAM *stream; int64_t pos; int64_t len; int whence = SEEK_SET; SUBR_ENTER(); stream = get_stream(PARAM, FALSE); if (NPARAM >= 2) { VALUE_conv(&PARAM[1], T_LONG); pos = PARAM[1]._long.value; if (NPARAM == 3) { VALUE_conv(&PARAM[2], T_INTEGER); whence = PARAM[2]._integer.value; if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) THROW(E_ARG); } else { if (pos < 0) { STREAM_lof(stream, &len); pos += len; } } STREAM_seek(stream, pos, (int)whence); RETURN->type = T_VOID; } else { RETURN->type = T_LONG; RETURN->_long.value = STREAM_tell(stream); } SUBR_LEAVE(); } void SUBR_read(void) { STREAM *stream; int len; bool do_not = FALSE; SUBR_ENTER(); stream = get_stream(PARAM, TRUE); if (NPARAM == 3) { VALUE_conv(&PARAM[2], T_INTEGER); len = PARAM[2]._integer.value; if (len == 0) do_not = TRUE; } else len = 0; if (do_not) RETURN->type = T_NULL; else STREAM_read_type(stream, PARAM[1].type, RETURN, len); SUBR_LEAVE(); } void SUBR_write(void) { STREAM *stream; int len; SUBR_ENTER(); stream = get_stream(PARAM, TRUE); if (NPARAM == 3) { VALUE_conv(&PARAM[2], T_INTEGER); len = PARAM[2]._integer.value; } else len = 0; STREAM_write_type(stream, PARAM[1].type, &PARAM[1], len); SUBR_LEAVE_VOID(); } void SUBR_stat(void) { const char *path; CSTAT *cstat; FILE_STAT info; bool follow = FALSE; SUBR_ENTER(); path = get_path(PARAM); if (NPARAM == 2) { VALUE_conv(&PARAM[1], T_BOOLEAN); follow = PARAM[1]._boolean.value; } FILE_stat(path, &info, follow); OBJECT_new((void **)(void *)&cstat, CLASS_Stat, NULL, NULL); OBJECT_UNREF_KEEP(cstat, "SUBR_stat"); cstat->info = info; STRING_new(&cstat->path, path, 0); OBJECT_put(RETURN, cstat); SUBR_LEAVE(); } void SUBR_exist(void) { bool exist; const char *path; SUBR_ENTER_PARAM(1); path = get_path(PARAM); exist = FILE_exist(path); RETURN->type = T_BOOLEAN; RETURN->_integer.value = exist ? -1 : 0; SUBR_LEAVE(); } void SUBR_dir() { GB_ARRAY array; const char *path; char *pattern; int len_pattern; char *str; int attr = 0; SUBR_ENTER(); path = get_path(PARAM); if (NPARAM >= 2) { pattern = SUBR_get_string(&PARAM[1]); if (NPARAM == 3) attr = SUBR_get_integer(&PARAM[2]); } else pattern = NULL; FILE_dir_first(path, pattern, attr); GB_ArrayNew(&array, T_STRING, 0); while (!FILE_dir_next(&pattern, &len_pattern)) { if (!LOCAL_is_UTF8) { if (STRING_conv(&str, pattern, len_pattern, LOCAL_encoding, "UTF-8", FALSE)) STRING_new(&str, pattern, len_pattern); else STRING_ref(str); } else STRING_new(&str, pattern, len_pattern); *((char **)GB_ArrayAdd(array)) = str; } RETURN->_object.class = OBJECT_class(array); RETURN->_object.object = array; SUBR_LEAVE(); } static void found_file(const char *path) { char *str; int len; path += _ignore; len = strlen(path); if (_pattern && !REGEXP_match(_pattern, _len_pattern, path, len)) return; if (!LOCAL_is_UTF8) { if (STRING_conv(&str, path, len, LOCAL_encoding, "UTF-8", FALSE)) STRING_new(&str, path, len); else STRING_ref(str); } else STRING_new(&str, path, len); *((char **)GB_ArrayAdd(_result)) = str; } void SUBR_rdir() { const char *path; int attr = 0; SUBR_ENTER(); path = get_path(PARAM); if (NPARAM >= 2) { SUBR_get_string_len(&PARAM[1], &_pattern, &_len_pattern); if (NPARAM == 3) attr = SUBR_get_integer(&PARAM[2]); } else _pattern = NULL; GB_ArrayNew(&_result, T_STRING, 0); if (!path || *path == 0) path = "."; _ignore = strlen(path); if (_ignore > 0 && path[_ignore - 1] != '/') _ignore++; FILE_recursive_dir(path, found_file, NULL, attr); RETURN->_object.class = OBJECT_class(_result); RETURN->_object.object = _result; SUBR_LEAVE(); } void SUBR_kill(void) { SUBR_ENTER_PARAM(1); FILE_unlink(get_path(PARAM)); SUBR_LEAVE_VOID(); } void SUBR_mkdir(void) { SUBR_ENTER_PARAM(1); FILE_mkdir(get_path(PARAM)); SUBR_LEAVE_VOID(); } void SUBR_rmdir(void) { SUBR_ENTER_PARAM(1); FILE_rmdir(get_path(PARAM)); SUBR_LEAVE_VOID(); } void SUBR_rename(void) { SUBR_ENTER_PARAM(2); FILE_rename(get_path(&PARAM[0]), get_path(&PARAM[1])); SUBR_LEAVE_VOID(); } void SUBR_temp(void) { char *temp; int len; SUBR_ENTER(); if (NPARAM == 0) temp = FILE_make_temp(&len, NULL); else temp = FILE_make_temp(&len, SUBR_get_string(PARAM)); STRING_new_temp_value(RETURN, temp, len); SUBR_LEAVE(); } void SUBR_isdir(void) { bool isdir; const char *path; SUBR_ENTER_PARAM(1); path = get_path(PARAM); isdir = FILE_isdir(path); RETURN->type = T_BOOLEAN; RETURN->_integer.value = isdir ? -1 : 0; SUBR_LEAVE(); } void SUBR_copy(void) { SUBR_ENTER_PARAM(2); FILE_copy(get_path(&PARAM[0]), get_path(&PARAM[1])); SUBR_LEAVE_VOID(); } void SUBR_access(void) { int access; SUBR_ENTER(); if (NPARAM == 1) access = R_OK; else { VALUE_conv(&PARAM[1], T_INTEGER); access = PARAM[1]._integer.value; } RETURN->type = T_BOOLEAN; RETURN->_integer.value = FILE_access(get_path(PARAM), access) ? -1 : 0; SUBR_LEAVE(); } void SUBR_link(void) { SUBR_ENTER_PARAM(2); /* Parameters are NOT inverted ANYMORE! */ FILE_link(get_path(&PARAM[0]), get_path(&PARAM[1])); SUBR_LEAVE_VOID(); } void SUBR_lock(void) { SUBR_ENTER_PARAM(1); if (EXEC_code & 0x1F) { STREAM_close(get_stream(PARAM, FALSE)); SUBR_LEAVE_VOID(); } else { STREAM stream; CFILE *file; const char *path = get_path(PARAM); if (FILE_is_relative(path)) THROW(E_BADPATH); STREAM_open(&stream, path, ST_WRITE | ST_CREATE | ST_DIRECT); STREAM_lock(&stream); file = CFILE_create(&stream, ST_WRITE | ST_CREATE | ST_DIRECT); OBJECT_put(RETURN, file); SUBR_LEAVE(); } } void SUBR_inp_out(void) { CSTREAM *stream; void **where; SUBR_ENTER_PARAM(1); switch(EXEC_code & 0x1F) { case 0: where = &_default_in; break; case 1: where = &_default_out; break; default: where = &_default_err; break; } if (VALUE_is_null(PARAM)) { stream = pop_stream(where); if (stream) OBJECT_UNREF(stream, "SUBR_inp_out"); return; } VALUE_conv(PARAM, (TYPE)CLASS_Stream); stream = PARAM->_object.object; OBJECT_REF(stream, "SUBR_inp_out"); push_stream(where, stream); SUBR_LEAVE_VOID(); } static void free_list(void **list) { CSTREAM *stream; for(;;) { stream = pop_stream(list); if (!stream) return; OBJECT_UNREF(stream, "free_list"); } } void SUBR_exit_inp_out(void) { free_list((void **)&_default_in); free_list((void **)&_default_out); free_list((void **)&_default_err); } void SUBR_dfree(void) { SUBR_ENTER_PARAM(1); RETURN->type = T_LONG; RETURN->_long.value = FILE_free(get_path(PARAM)); SUBR_LEAVE(); } void SUBR_debug(void) { const int NPARAM = 0; STREAM *stream = get_default(2); const char *s = DEBUG_get_current_position(); STREAM_write(stream, (void *)s, strlen(s)); STREAM_write(stream, ": ", 2); SUBR_LEAVE(); }