/* ************************************************************************ */ /* */ /* Neko Standard Library */ /* Copyright (c)2005 Motion-Twin */ /* */ /* This library is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Lesser General Public */ /* License as published by the Free Software Foundation; either */ /* version 2.1 of the License, or (at your option) any later version. */ /* */ /* This library 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 */ /* Lesser General Public License or the LICENSE file for more details. */ /* */ /* ************************************************************************ */ #include #include #include #include #include #include #include #include #ifdef NEKO_WINDOWS # include # include # include #else # include # include # include # include # include # include # include # include #endif #ifdef NEKO_MAC # include # include # include #endif #ifndef CLK_TCK # define CLK_TCK 100 #endif /**

System

Interactions with the operating system.

**/ /** get_env : string -> string? Get some environment variable if exists **/ static value get_env( value v ) { char *s; val_check(v,string); s = getenv(val_string(v)); if( s == NULL ) return val_null; return alloc_string(s); } /** put_env : var:string -> val:string -> void Set some environment variable value **/ static value put_env( value e, value v ) { #ifdef NEKO_WINDOWS buffer b; val_check(e,string); val_check(v,string); b = alloc_buffer(NULL); val_buffer(b,e); buffer_append_sub(b,"=",1); val_buffer(b,v); if( putenv(val_string(buffer_to_string(b))) != 0 ) neko_error(); #else val_check(e,string); val_check(v,string); if( setenv(val_string(e),val_string(v),1) != 0 ) neko_error(); #endif return val_true; } /** sys_sleep : number -> void Sleep a given number of seconds **/ static value sys_sleep( value f ) { val_check(f,number); #ifdef NEKO_WINDOWS Sleep((DWORD)(val_number(f) * 1000)); #else { struct timespec t; struct timespec tmp; t.tv_sec = (int)val_number(f); t.tv_nsec = (int)((val_number(f) - t.tv_sec) * 1e9); while( nanosleep(&t,&tmp) == -1 ) { if( errno != EINTR ) neko_error(); t = tmp; } } #endif return val_true; } /** set_time_locale : string -> bool Set the locale for LC_TIME, returns true on success **/ static value set_time_locale( value l ) { #ifdef NEKO_POSIX locale_t lc, old; val_check(l,string); lc = newlocale(LC_TIME_MASK,val_string(l),NULL); if( lc == NULL ) return val_false; old = uselocale(lc); if( old == NULL ) { freelocale(lc); return val_false; } if( old != LC_GLOBAL_LOCALE ) freelocale(old); return val_true; #else val_check(l,string); return alloc_bool(setlocale(LC_TIME,val_string(l)) != NULL); #endif } /** get_cwd : void -> string Return current working directory **/ static value get_cwd() { char buf[256]; int l; if( getcwd(buf,256) == NULL ) neko_error(); l = (int)strlen(buf); if( buf[l-1] != '/' && buf[l-1] != '\\' ) { buf[l] = '/'; buf[l+1] = 0; } return alloc_string(buf); } /** set_cwd : string -> void Set current working directory **/ static value set_cwd( value d ) { val_check(d,string); if( chdir(val_string(d)) ) neko_error(); return val_true; } /** sys_string : void -> string Return the local system string. The current value are possible :
  • [Windows]
  • [Linux]
  • [BSD]
  • [Mac]
**/ static value sys_string() { #if defined(NEKO_WINDOWS) return alloc_string("Windows"); #elif defined(NEKO_GNUKBSD) return alloc_string("GNU/kFreeBSD"); #elif defined(NEKO_LINUX) return alloc_string("Linux"); #elif defined(NEKO_BSD) return alloc_string("BSD"); #elif defined(NEKO_MAC) return alloc_string("Mac"); #else #error Unknow system string #endif } /** sys_is64 : void -> bool Returns true if we are on a 64-bit system **/ static value sys_is64() { #ifdef NEKO_64BITS return val_true; #else return val_false; #endif } /** sys_command : string -> int Run the shell command and return exit code **/ static value sys_command( value cmd ) { val_check(cmd,string); if( val_strlen(cmd) == 0 ) return alloc_int(-1); return alloc_int( system(val_string(cmd)) ); } /** sys_exit : int -> void Exit with the given errorcode. Never returns. **/ static value sys_exit( value ecode ) { val_check(ecode,int); exit(val_int(ecode)); return val_true; } /** sys_exists : string -> bool Returns true if the file or directory exists. **/ static value sys_exists( value path ) { struct stat st; val_check(path,string); return alloc_bool(stat(val_string(path),&st) == 0); } /** file_exists : string -> bool Deprecated : use sys_exists instead. **/ static value file_exists( value path ) { return sys_exists(path); } /** file_delete : string -> void Delete the file. Exception on error. **/ static value file_delete( value path ) { val_check(path,string); if( unlink(val_string(path)) != 0 ) neko_error(); return val_true; } /** sys_rename : from:string -> to:string -> void Rename the file or directory. Exception on error. **/ static value sys_rename( value path, value newname ) { val_check(path,string); val_check(newname,string); if( rename(val_string(path),val_string(newname)) != 0 ) neko_error(); return val_true; } #define STATF(f) alloc_field(o,val_id(#f),alloc_int(s.st_##f)) #define STATF32(f) alloc_field(o,val_id(#f),alloc_int32(s.st_##f)) /** sys_stat : string -> { gid => int, uid => int, atime => 'int32, mtime => 'int32, ctime => 'int32, dev => int, ino => int, nlink => int, rdev => int, mode => int, size => int } Run the [stat] command on the given file or directory. **/ static value sys_stat( value path ) { struct stat s; value o; val_check(path,string); if( stat(val_string(path),&s) != 0 ) neko_error(); o = alloc_object(NULL); STATF(gid); STATF(uid); STATF32(atime); STATF32(mtime); STATF32(ctime); STATF(dev); STATF(ino); STATF(mode); STATF(nlink); STATF(rdev); STATF(size); STATF(mode); return o; } /** sys_file_type : string -> string Return the type of the file. The current values are possible :
  • [file]
  • [dir]
  • [symlink]
  • [sock]
  • [char]
  • [block]
  • [fifo]
**/ static value sys_file_type( value path ) { struct stat s; val_check(path,string); if( stat(val_string(path),&s) != 0 ) neko_error(); if( s.st_mode & S_IFREG ) return alloc_string("file"); if( s.st_mode & S_IFDIR ) return alloc_string("dir"); if( s.st_mode & S_IFCHR ) return alloc_string("char"); #ifndef NEKO_WINDOWS if( s.st_mode & S_IFLNK ) return alloc_string("symlink"); if( s.st_mode & S_IFBLK ) return alloc_string("block"); if( s.st_mode & S_IFIFO ) return alloc_string("fifo"); if( s.st_mode & S_IFSOCK ) return alloc_string("sock"); #endif neko_error(); } /** sys_create_dir : string -> mode:int -> void Create a directory with the specified rights **/ static value sys_create_dir( value path, value mode ) { val_check(path,string); val_check(mode,int); #ifdef NEKO_WINDOWS if( mkdir(val_string(path)) != 0 ) #else if( mkdir(val_string(path),val_int(mode)) != 0 ) #endif neko_error(); return val_true; } /** sys_remove_dir : string -> void Remove a directory. Exception on error **/ static value sys_remove_dir( value path ) { val_check(path,string); if( rmdir(val_string(path)) != 0 ) neko_error(); return val_true; } /** sys_time : void -> float Return an accurate local time stamp in seconds since Jan 1 1970 **/ static value sys_time() { #ifdef NEKO_WINDOWS #define EPOCH_DIFF (134774*24*60*60.0) SYSTEMTIME t; FILETIME ft; ULARGE_INTEGER ui; GetSystemTime(&t); if( !SystemTimeToFileTime(&t,&ft) ) neko_error(); ui.LowPart = ft.dwLowDateTime; ui.HighPart = ft.dwHighDateTime; return alloc_float( ((tfloat)ui.QuadPart) / 10000000.0 - EPOCH_DIFF ); #else struct timeval tv; if( gettimeofday(&tv,NULL) != 0 ) neko_error(); return alloc_float( tv.tv_sec + ((tfloat)tv.tv_usec) / 1000000.0 ); #endif } /** sys_cpu_time : void -> float Return the most accurate CPU time spent since the process started (in seconds) **/ static value sys_cpu_time() { #ifdef NEKO_WINDOWS FILETIME unused; FILETIME stime; FILETIME utime; if( !GetProcessTimes(GetCurrentProcess(),&unused,&unused,&stime,&utime) ) neko_error(); return alloc_float( ((tfloat)(utime.dwHighDateTime+stime.dwHighDateTime)) * 65.536 * 6.5536 + (((tfloat)utime.dwLowDateTime + (tfloat)stime.dwLowDateTime) / 10000000) ); #else struct tms t; times(&t); return alloc_float( ((tfloat)(t.tms_utime + t.tms_stime)) / CLK_TCK ); #endif } /** sys_read_dir : string -> string list Return the content of a directory **/ static value sys_read_dir( value path ) { value h = val_null; value cur = NULL, tmp; #ifdef NEKO_WINDOWS WIN32_FIND_DATA d; HANDLE handle; buffer b; int len; val_check(path,string); len = val_strlen(path); b = alloc_buffer(NULL); val_buffer(b,path); if( len && val_string(path)[len-1] != '/' && val_string(path)[len-1] != '\\' ) buffer_append(b,"/*.*"); else buffer_append(b,"*.*"); path = buffer_to_string(b); handle = FindFirstFile(val_string(path),&d); if( handle == INVALID_HANDLE_VALUE ) neko_error(); while( true ) { // skip magic dirs if( d.cFileName[0] != '.' || (d.cFileName[1] != 0 && (d.cFileName[1] != '.' || d.cFileName[2] != 0)) ) { tmp = alloc_array(2); val_array_ptr(tmp)[0] = alloc_string(d.cFileName); val_array_ptr(tmp)[1] = val_null; if( cur ) val_array_ptr(cur)[1] = tmp; else h = tmp; cur = tmp; } if( !FindNextFile(handle,&d) ) break; } FindClose(handle); #else DIR *d; struct dirent *e; val_check(path,string); d = opendir(val_string(path)); if( d == NULL ) neko_error(); while( true ) { e = readdir(d); if( e == NULL ) break; // skip magic dirs if( e->d_name[0] == '.' && (e->d_name[1] == 0 || (e->d_name[1] == '.' && e->d_name[2] == 0)) ) continue; tmp = alloc_array(2); val_array_ptr(tmp)[0] = alloc_string(e->d_name); val_array_ptr(tmp)[1] = val_null; if( cur ) val_array_ptr(cur)[1] = tmp; else h = tmp; cur = tmp; } closedir(d); #endif return h; } /** file_full_path : string -> string Return an absolute path from a relative one. The file or directory must exists **/ static value file_full_path( value path ) { #ifdef NEKO_WINDOWS char buf[MAX_PATH+1]; val_check(path,string); if( GetFullPathName(val_string(path),MAX_PATH+1,buf,NULL) == 0 ) neko_error(); return alloc_string(buf); #else char buf[PATH_MAX]; val_check(path,string); if( realpath(val_string(path),buf) == NULL ) neko_error(); return alloc_string(buf); #endif } /** sys_exe_path : void -> string Return the path of the executable **/ static value sys_exe_path() { #if defined(NEKO_WINDOWS) char path[MAX_PATH]; if( GetModuleFileName(NULL,path,MAX_PATH) == 0 ) neko_error(); return alloc_string(path); #elif defined(NEKO_MAC) char path[PATH_MAX+1]; uint32_t path_len = PATH_MAX; if( _NSGetExecutablePath(path, &path_len) ) neko_error(); return alloc_string(path); #else const char *p = getenv("_"); if( p != NULL ) return alloc_string(p); { char path[PATH_MAX]; int length = readlink("/proc/self/exe", path, sizeof(path)); if( length < 0 ) neko_error(); path[length] = '\0'; return alloc_string(path); } #endif } #ifdef NEKO_MAC # define environ (*_NSGetEnviron()) #endif #ifndef NEKO_WINDOWS extern char **environ; #endif /** sys_env : void -> #list Return all the (key,value) pairs in the environment as a chained list **/ static value sys_env() { value h = val_null; value cur = NULL, tmp, key; char **e = environ; while( *e ) { char *x = strchr(*e,'='); if( x == NULL ) { e++; continue; } tmp = alloc_array(3); key = alloc_empty_string((int)(x - *e)); memcpy(val_string(key),*e,(int)(x - *e)); val_array_ptr(tmp)[0] = key; val_array_ptr(tmp)[1] = alloc_string(x+1); val_array_ptr(tmp)[2] = val_null; if( cur ) val_array_ptr(cur)[2] = tmp; else h = tmp; cur = tmp; e++; } return h; } /** sys_getch : bool -> int Read a character from stdin with or without echo **/ static value sys_getch( value b ) { # ifdef NEKO_WINDOWS val_check(b,bool); return alloc_int( val_bool(b)?getche():getch() ); # else // took some time to figure out how to do that // without relying on ncurses, which clear the // terminal on initscr() int c; struct termios term, old; val_check(b,bool); tcgetattr(fileno(stdin), &old); term = old; cfmakeraw(&term); tcsetattr(fileno(stdin), 0, &term); c = getchar(); tcsetattr(fileno(stdin), 0, &old); if( val_bool(b) ) fputc(c,stdout); return alloc_int(c); # endif } /** sys_get_pid : void -> int Returns the current process identifier **/ static value sys_get_pid() { # ifdef NEKO_WINDOWS return alloc_int(GetCurrentProcessId()); # else return alloc_int(getpid()); # endif } DEFINE_PRIM(get_env,1); DEFINE_PRIM(put_env,2); DEFINE_PRIM(set_time_locale,1); DEFINE_PRIM(get_cwd,0); DEFINE_PRIM(set_cwd,1); DEFINE_PRIM(sys_sleep,1); DEFINE_PRIM(sys_command,1); DEFINE_PRIM(sys_exit,1); DEFINE_PRIM(sys_string,0); DEFINE_PRIM(sys_is64,0); DEFINE_PRIM(sys_stat,1); DEFINE_PRIM(sys_time,0); DEFINE_PRIM(sys_cpu_time,0); DEFINE_PRIM(sys_env,0); DEFINE_PRIM(sys_create_dir,2); DEFINE_PRIM(sys_remove_dir,1); DEFINE_PRIM(sys_read_dir,1); DEFINE_PRIM(file_full_path,1); DEFINE_PRIM(file_exists,1); DEFINE_PRIM(sys_exists,1); DEFINE_PRIM(file_delete,1); DEFINE_PRIM(sys_rename,2); DEFINE_PRIM(sys_exe_path,0); DEFINE_PRIM(sys_file_type,1); DEFINE_PRIM(sys_getch,1); DEFINE_PRIM(sys_get_pid,0); /* ************************************************************************ */