/** regexp_matched : 'regexp -> n:int -> string? <doc>Return the [n]th matched block by the regexp. If [n] is 0 then return the whole matched substring. If the [n]th matched block was optional and not matched, returns null</doc> **/ static value regexp_matched( value o, value n ) { pcredata *d; int m; val_check_kind(o,k_regexp); d = PCRE(o); val_check(n,int); m = val_int(n); if( m < 0 || m >= d->nmatchs || val_is_null(d->str) ) neko_error(); { int start = d->matchs[m*2]; int len = d->matchs[m*2+1] - start; value str; if( start == -1 ) return val_null; str = alloc_empty_string(len); memcpy((char*)val_string(str),val_string(d->str)+start,len); return str; } }
value cgi_command( value v ) { val_check(v,string); if( strcmp(val_string(v),"stats") == 0 ) return neko_stats_build(neko_vm_current()); if( strcmp(val_string(v),"cache") == 0 ) { cache *c = (cache*)local_get(cache_root); value l = val_null; while( c != NULL ) { value a = alloc_array(4); val_array_ptr(a)[0] = c->file; val_array_ptr(a)[1] = c->main; val_array_ptr(a)[2] = alloc_int(c->hits); val_array_ptr(a)[3] = l; l = a; c = c->next; } return l; } neko_error(); }
/** regexp_match : 'regexp -> string -> pos:int -> len:int -> bool <doc>Match [len] chars of a string starting at [pos] using the regexp. Return true if match found</doc> **/ static value regexp_match( value o, value s, value p, value len ) { pcredata *d; int pp,ll; val_check_kind(o,k_regexp); val_check(s,string); val_check(p,int); val_check(len,int); pp = val_int(p); ll = val_int(len); if( pp < 0 || ll < 0 || pp > val_strlen(s) || pp + ll > val_strlen(s) ) neko_error(); d = PCRE(o); if( do_exec(d,val_string(s),ll+pp,pp) ) { d->str = s; return val_true; } else { d->str = val_null; return val_false; } }
/** ui_loop : void -> void <doc> Starts the native UI event loop. This method can only be called from the main thread. </doc> **/ static value ui_loop() { if( !val_bool(ui_is_main()) ) neko_error(); # if defined(NEKO_WINDOWS) { MSG msg; while( GetMessage(&msg,NULL,0,0) ) { TranslateMessage(&msg); DispatchMessage(&msg); if( msg.message == WM_QUIT ) break; } } # elif defined(NEKO_MAC) RunApplicationEventLoop(); # else gtk_main(); # endif return val_null; }
/** $sfind : src:string -> pos:int -> pat:string -> int? <doc> Return the first position starting at [pos] in [src] where [pat] was found. Return null if not found. Error if [pos] is outside [src] bounds. </doc> **/ static value builtin_sfind( value src, value pos, value pat ) { int p, l, l2; const char *ptr; val_check(src,string); val_check(pos,int); val_check(pat,string); p = val_int(pos); l = val_strlen(src); l2 = val_strlen(pat); if( p < 0 || p >= l ) neko_error(); ptr = val_string(src) + p; while( l - p >= l2 ) { if( memcmp(ptr,val_string(pat),l2) == 0 ) return alloc_int(p); p++; ptr++; } return val_null; }
/** 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 } <doc>Run the [stat] command on the given file or directory.</doc> **/ 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; }
/** $hadd : 'hash -> k:any -> v:any -> void <doc> Add the value [v] with key [k] to the hashtable. Previous binding is masked but not removed. </doc> **/ static value builtin_hadd( value vh, value key, value val ) { vhash *h; hcell *c; int hkey; val_check_kind(vh,k_hash); h = val_hdata(vh); hkey = val_hash(key); if( hkey < 0 ) neko_error(); if( h->nitems >= (h->ncells << 1) ) builtin_hresize(vh,alloc_int(h->ncells << 1)); c = (hcell*)alloc(sizeof(hcell)); c->hkey = hkey; c->key = key; c->val = val; hkey %= h->ncells; c->next = h->cells[hkey]; h->cells[hkey] = c; h->nitems++; return val_null; }
/** socket_new : udp:bool -> 'socket <doc>Create a new socket, TCP or UDP</doc> **/ static value socket_new( value udp ) { SOCKET s; val_check(udp,bool); if( val_bool(udp) ) s = socket(AF_INET,SOCK_DGRAM,0); else s = socket(AF_INET,SOCK_STREAM,0); if( s == INVALID_SOCKET ) neko_error(); # ifdef NEKO_MAC setsockopt(s,SOL_SOCKET,SO_NOSIGPIPE,NULL,0); # endif # ifdef NEKO_POSIX // we don't want sockets to be inherited in case of exec { int old = fcntl(s,F_GETFD,0); if( old >= 0 ) fcntl(s,F_SETFD,old|FD_CLOEXEC); } # endif return alloc_abstract(k_socket,(value)(int_val)s); }
/** socket_recv_from : 'socket -> buf:string -> pos:int -> length:int -> addr:{host:'int32,port:int} -> int <doc> Read data from an unconnected UDP socket, store the address from which we received data in addr. </doc> **/ static value socket_recv_from( value o, value data, value pos, value len, value addr ) { int p,l,dlen,ret; int retry = 0; struct sockaddr_in saddr; int slen = sizeof(saddr); val_check_kind(o,k_socket); val_check(data,string); val_check(pos,int); val_check(len,int); val_check(addr,object); p = val_int(pos); l = val_int(len); dlen = val_strlen(data); if( p < 0 || l < 0 || p > dlen || p + l > dlen ) neko_error(); POSIX_LABEL(recv_from_again); if( retry++ > NRETRYS ) { sock_tmp t; t.sock = val_sock(o); t.buf = val_string(data) + p; t.size = l; neko_thread_blocking(tmp_recv,&t); ret = t.ret; } else ret = recvfrom(val_sock(o), val_string(data) + p , l, MSG_NOSIGNAL, (struct sockaddr*)&saddr, &slen); if( ret == SOCKET_ERROR ) { HANDLE_EINTR(recv_from_again); #ifdef NEKO_WINDOWS if( WSAGetLastError() == WSAECONNRESET ) ret = 0; else #endif return block_error(); } alloc_field(addr,f_host,alloc_int32(*(int*)&saddr.sin_addr)); alloc_field(addr,f_port,alloc_int(ntohs(saddr.sin_port))); return alloc_int(ret); }
/** socket_recv_char : 'socket -> int <doc>Read a single char from a connected socket.</doc> **/ static value socket_recv_char( value o ) { int ret; int retry = 0; unsigned char cc; val_check_kind(o,k_socket); POSIX_LABEL(recv_char_again); if( retry++ > NRETRYS ) { sock_tmp t; t.sock = val_sock(o); t.buf = (char*)&cc; t.size = 1; neko_thread_blocking(tmp_recv,&t); ret = t.ret; } else ret = recv(val_sock(o),&cc,1,MSG_NOSIGNAL); if( ret == SOCKET_ERROR ) { HANDLE_EINTR(recv_char_again); return block_error(); } if( ret == 0 ) neko_error(); return alloc_int(cc); }
/** socket_set_keepalive : 'socket -> bool -> time:int? -> interval:int? -> void <doc> Enable or disable TCP_KEEPALIVE flag for the socket </doc> **/ static value socket_set_keepalive( value o, value b, value time, value interval ) { int val; SOCKET s; val_check_kind(o,k_socket); val_check(b,bool); if( !val_is_null(time) || !val_is_null(interval) ){ val_check(time,int); val_check(interval,int); } s = val_sock(o); if( !val_bool(b) ) { val = 0; if( setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&val, sizeof(val)) != 0 ) neko_error(); } else { val = 1; if( setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&val, sizeof(val)) != 0 ) neko_error(); if( !val_is_null(time) && !val_is_null(interval) ) { # if defined(NEKO_WINDOWS) u_long params[3] = { 1, (unsigned long)val_int(time)*1000, (unsigned long)val_int(interval)*1000 }; if( WSAIoctl(s, SIO_KEEPALIVE_VALS, ¶ms, sizeof(params), NULL, 0, &val, NULL, NULL) != 0 ) neko_error(); # else # if defined(TCP_KEEPIDLE) val = val_int(time); if( setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&val, sizeof(val)) != 0 ) neko_error(); # elif defined(TCP_KEEPALIVE) val = val_int(time); if( setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE, (void *)&val, sizeof(val)) != 0 ) neko_error(); # endif # if defined(TCP_KEEPINTVL) val = val_int(interval); if( setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&val, sizeof(val)) != 0 ) neko_error(); # endif # endif } } return val_null; }
static value cert_add_pem( value cert, value data ){ mbedtls_x509_crt *crt; int r, len; unsigned char *buf; val_check(data,string); if( !val_is_null(cert) ){ val_check_kind(cert,k_cert); crt = val_cert(cert); if( !crt ) neko_error(); }else{ crt = (mbedtls_x509_crt *)alloc(sizeof(mbedtls_x509_crt)); mbedtls_x509_crt_init( crt ); cert = alloc_abstract(k_cert, crt); val_gc(cert,free_cert); } len = val_strlen(data)+1; buf = (unsigned char *)alloc(len); memcpy(buf, val_string(data), len-1); buf[len-1] = '\0'; if( (r = mbedtls_x509_crt_parse(crt, buf, len)) < 0 ) return ssl_error(r); return cert; }
/** Free an allocated ENetEvent struct from neko **/ static value free_enetevent( value e ) { val_check_kind(e,k_udprevent); ENetEvent *event = (ENetEvent *)val_data(e); if(e == NULL) neko_error(); // enet_packet_destroy frees the packet itself. #ifdef ENET_DEBUG printf("*** free_enetevent freeing packet\n"); #endif if(event->packet != NULL) enet_packet_destroy (event->packet); #ifdef ENET_DEBUG //printf("*** free_enetevent freeing event\n"); #endif enet_free(event); val_gc(e,NULL); val_kind(e) = NULL; #ifdef ENET_DEBUG //printf("*** free_enetevent done.\n"); #endif return val_true; }
//value ImageStringTTF(value img,value fontname,value ptsize, value angle, value x, value y,value string, value align, value antiAntiAlias, value color) { value ImageStringTTF(value *args,int nargs) { enum {eImg,eFontname,ePtsize,eAngle,eX,eY,eString,eAlign,eAntiAlias,eColor,eSize}; if (nargs!=eSize) neko_error(); ImageData _img = getImage(args[eImg]); char *_fontname = val_string(args[eFontname]); double _ptsize = val_float(args[ePtsize]); double _angle = val_float(args[eAngle]); int _x = val_int(args[eX]); int _y = val_int(args[eY]); char *_string = val_string(args[eString]); int _align = val_int(args[eAlign]); int _antiAliasing = val_bool(args[eAntiAlias]); //calculation size of output int brect[8]; char *err; err = gdImageStringFT(NULL,&brect[0],0,_fontname,_ptsize,_angle,0,0,_string); if (err) val_throw(alloc_string(err)); int width = brect[2] - brect[6]; int height = brect[3] - brect[7]; switch (_align) { case 0: // LeftTop break; case 1: // CenterTop _x-=width/2; break; case 2: // RightTop _x-=width; break; case 3: // LeftMiddle _y-=height/2; break; case 4: // CenterMiddle _y-=height/2; _x-=width/2; break; case 5: // Right Middle _y-=height/2; _x-=width; break; case 6: // LeftBottom _y-=height; break; case 7: // CenterBottom _y-=height; _x-=width/2; break; case 8: // RightBottom _y-=height; _x-=width; break; default: //something went wrong val_throw(alloc_string("unknown position type")); break; } _y+=height; //drawing int _color = initColor(_img,args[eColor]); err = gdImageStringFT(imageImage(_img),&brect[0],getAntiAliasingColor(_color,_antiAliasing),_fontname,_ptsize,_angle,_x,_y,_string); if (err) val_throw(alloc_string(err)); return val_null; }
/** $idiv : any -> any -> int <doc>Divide two integers. An error occurs if division by 0</doc> **/ static value builtin_idiv( value a, value b ) { if( val_any_int(b) == 0 ) neko_error(); return alloc_best_int( val_any_int(a) / val_any_int(b) ); }
/** $new : object? -> object <doc>Return a copy of the object or a new object if [null]</doc> **/ static value builtin_new( value o ) { if( !val_is_null(o) && !val_is_object(o) ) neko_error(); return alloc_object(o); }
/** parse_multipart_data : onpart:function:2 -> ondata:function:3 -> void <doc> Incrementally parse the multipart data. call [onpart(name,filename)] for each part found and [ondata(buf,pos,len)] when some data is available </doc> **/ static value parse_multipart_data( value onpart, value ondata ) { value buf; int len = 0; mcontext *c = CONTEXT(); const char *ctype = ap_table_get(c->r->headers_in,"Content-Type"); value boundstr; val_check_function(onpart,2); val_check_function(ondata,3); buf = alloc_empty_string(BUFSIZE); if( !ctype || strstr(ctype,"multipart/form-data") == NULL ) return val_null; // extract boundary value { const char *boundary, *bend; if( (boundary = strstr(ctype,"boundary=")) == NULL ) neko_error(); boundary += 9; PARSE_HEADER(boundary,bend); len = (int)(bend - boundary); boundstr = alloc_empty_string(len+2); if( val_strlen(boundstr) > BUFSIZE / 2 ) neko_error(); val_string(boundstr)[0] = '-'; val_string(boundstr)[1] = '-'; memcpy(val_string(boundstr)+2,boundary,len); } len = 0; if( !ap_should_client_block(c->r) ) neko_error(); while( true ) { char *name, *end_name, *filename, *end_file_name, *data; int pos; // refill buffer // we assume here that the the whole multipart header can fit in the buffer fill_buffer(c,buf,&len); // is boundary at the beginning of buffer ? if( len < val_strlen(boundstr) || memcmp(val_string(buf),val_string(boundstr),val_strlen(boundstr)) != 0 ) return discard_body(c); name = memfind(val_string(buf),len,"Content-Disposition:"); if( name == NULL ) break; name = memfind(name,len - (int)(name - val_string(buf)),"name="); if( name == NULL ) return discard_body(c); name += 5; PARSE_HEADER(name,end_name); data = memfind(end_name,len - (int)(end_name - val_string(buf)),"\r\n\r\n"); if( data == NULL ) return discard_body(c); filename = memfind(name,(int)(data - name),"filename="); if( filename != NULL ) { filename += 9; PARSE_HEADER(filename,end_file_name); } data += 4; pos = (int)(data - val_string(buf)); // send part name val_call2(onpart,copy_string(name,(int)(end_name - name)),filename?copy_string(filename,(int)(end_file_name - filename)):val_null); // read data while( true ) { const char *boundary; // recall buffer memmove(val_string(buf),val_string(buf)+pos,len - pos); len -= pos; pos = 0; fill_buffer(c,buf,&len); // lookup bounds boundary = memfind(val_string(buf),len,val_string(boundstr)); if( boundary == NULL ) { if( len == 0 ) return discard_body(c); // send as much buffer as possible to client if( len < BUFSIZE ) pos = len; else pos = len - val_strlen(boundstr) + 1; val_call3(ondata,buf,alloc_int(0),alloc_int(pos)); } else { // send remaining data pos = (int)(boundary - val_string(buf)); val_call3(ondata,buf,alloc_int(0),alloc_int(pos-2)); // recall memmove(val_string(buf),val_string(buf)+pos,len - pos); len -= pos; break; } } } return val_null; }
static value discard_body( mcontext *c ) { char buf[256]; while( ap_get_client_block(c->r,buf,256) > 0 ) { } neko_error(); }
/** process_run_raw : cmd:string -> 'process <doc> Start a process using a command. The input string contains the command as well as the arguments. Shell meta-characters will not be auto escaped/quoted. </doc> **/ CAMLprim value process_run_raw( value cmd ) { int i; vprocess *p; val_check(cmd,string); char* cmdStr = val_string(cmd); # ifdef _WIN32 { SECURITY_ATTRIBUTES sattr; STARTUPINFO sinf; HANDLE proc = GetCurrentProcess(); HANDLE oread,eread,iwrite; // creates commandline buffer b = alloc_buffer(NULL); char *sargs; buffer_append_char(b,'"'); char* cmdexe = getenv("COMSPEC"); if (!cmdexe) cmdexe = "cmd.exe"; buffer_append_str(b,cmdexe); buffer_append_char(b,'"'); buffer_append_str(b,"/C \""); buffer_append_str(b,cmdStr); buffer_append_char(b,'"'); sargs = buffer_to_string(b); p = (vprocess*)alloc_private(sizeof(vprocess)); // startup process sattr.nLength = sizeof(sattr); sattr.bInheritHandle = TRUE; sattr.lpSecurityDescriptor = NULL; memset(&sinf,0,sizeof(sinf)); sinf.cb = sizeof(sinf); sinf.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; sinf.wShowWindow = SW_HIDE; CreatePipe(&oread,&sinf.hStdOutput,&sattr,0); CreatePipe(&eread,&sinf.hStdError,&sattr,0); CreatePipe(&sinf.hStdInput,&iwrite,&sattr,0); DuplicateHandle(proc,oread,proc,&p->oread,0,FALSE,DUPLICATE_SAME_ACCESS); DuplicateHandle(proc,eread,proc,&p->eread,0,FALSE,DUPLICATE_SAME_ACCESS); DuplicateHandle(proc,iwrite,proc,&p->iwrite,0,FALSE,DUPLICATE_SAME_ACCESS); CloseHandle(oread); CloseHandle(eread); CloseHandle(iwrite); if( !CreateProcess(NULL,val_string(sargs),NULL,NULL,TRUE,0,NULL,NULL,&sinf,&p->pinf) ) { CloseHandle(p->eread); CloseHandle(p->oread); CloseHandle(p->iwrite); free(sargs); neko_error(); } free(sargs); // close unused pipes CloseHandle(sinf.hStdOutput); CloseHandle(sinf.hStdError); CloseHandle(sinf.hStdInput); } # else char **argv = (char**)alloc_private(sizeof(char*)*4); argv[0] = cmd = "/bin/sh"; argv[1] = "-c"; argv[2] = cmdStr; argv[3] = NULL; int input[2], output[2], error[2]; if( pipe(input) || pipe(output) || pipe(error) ) neko_error(); p = (vprocess*)alloc_private(sizeof(vprocess)); p->pid = fork(); if( p->pid == -1 ) { do_close(input[0]); do_close(input[1]); do_close(output[0]); do_close(output[1]); do_close(error[0]); do_close(error[1]); neko_error(); } // child if( p->pid == 0 ) { close(input[1]); close(output[0]); close(error[0]); dup2(input[0],0); dup2(output[1],1); dup2(error[1],2); execvp(val_string(cmd),argv); fprintf(stderr,"Command not found : %s\n",val_string(cmd)); exit(1); } // parent do_close(input[0]); do_close(output[1]); do_close(error[1]); p->iwrite = input[1]; p->oread = output[0]; p->eread = error[0]; # endif { value vp = alloc_abstract(k_process,p); val_gc(vp,free_process); return vp; } }
value hxfcgi_parse_multipart_neko(value hreq, value onpart, value ondata ) { val_check_kind(hreq,hxRequest); val_check_function(onpart,2); val_check_function(ondata,3); hxfcgi::Request *req = get_request(hreq); char *buf; int len = 0; char *boundstr; hxfcgi::BasicData b; string ctype = b.getHeader("CONTENT_TYPE"); if(ctype.find("multipart/form-data") != 0) return val_null; // extract boundary value { const char *boundary, *bend; if( (boundary = strstr(ctype.c_str(),"boundary=")) == NULL ) neko_error(); boundary += 9; PARSE_HEADER(boundary,bend); len = (int)(bend - boundary); boundstr = (char *) malloc(sizeof(char) * (len+3)); if( strlen(boundstr) > BUFSIZE / 2 ) neko_error(); boundstr[0] = '-'; boundstr[1] = '-'; memcpy(boundstr+2,boundary,len); boundstr[len+2] = 0; } len = 0; buf = (char *) malloc(sizeof(char) * (BUFSIZE)); while( true ) { char *name, *end_name, *filename, *end_file_name, *data; int pos; // refill buffer // we assume here that the the whole multipart header can fit in the buffer req->bufferFill(buf,&len); // is boundary at the beginning of buffer ? if( len < (int) strlen(boundstr) || memcmp(buf,boundstr,strlen(boundstr)) != 0 ) { free(boundstr); free(buf); return val_null; } name = memfind(buf,len,"Content-Disposition:"); if( name == NULL ) break; name = memfind(name,len - (int)(name - buf),"name="); if( name == NULL ) { free(boundstr); free(buf); return val_null; } name += 5; PARSE_HEADER(name,end_name); data = memfind(end_name,len - (int)(end_name - buf),"\r\n\r\n"); if( data == NULL ) { free(boundstr); free(buf); return val_null; } filename = memfind(name,(int)(data - name),"filename="); if( filename != NULL ) { filename += 9; PARSE_HEADER(filename,end_file_name); } data += 4; pos = (int)(data - buf); // send part name val_call2(onpart,copy_string(name,(int)(end_name - name)),filename?copy_string(filename,(int)(end_file_name - filename)):val_null); // read data while( true ) { const char *boundary; // recall buffer memcpy(buf,buf+pos,len - pos); len -= pos; pos = 0; req->bufferFill(buf,&len); // lookup bounds boundary = memfind(buf,len,boundstr); if( boundary == NULL ) { if( len == 0 ) { free(boundstr); free(buf); return val_null; } // send as much buffer as possible to client if( len < BUFSIZE ) pos = len; else pos = len - strlen(boundstr) + 1; val_call3(ondata,copy_string(buf,pos),alloc_int(0),alloc_int(pos)); } else { // send remaining data pos = (int)(boundary - buf); val_call3(ondata,copy_string(buf,pos-2),alloc_int(0),alloc_int(pos-2)); // recall memcpy(buf,buf+pos,len - pos); len -= pos; break; } } } free(boundstr); free(buf); return val_null; }
static value enumerate_ips() { value rv, cur = NULL, tmp; int c,x; int addr; #ifdef NEKO_WINDOWS LPSOCKET_ADDRESS_LIST list = NULL; SOCKET s; int len = 0; char *buf = (char *)malloc(4096); s = socket(AF_INET, SOCK_RAW, IPPROTO_IP); if(s == SOCKET_ERROR) neko_error(); c = WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0, buf, 4096, (unsigned long *) &len, NULL, NULL); closesocket(s); printf("iface count: %d\n", len); if(c == SOCKET_ERROR || len <=0) { free(buf); neko_error(); } list = (LPSOCKET_ADDRESS_LIST) buf; if(list->iAddressCount <= 0) { free(buf); neko_error(); } char sbuf[20]; for(x=0; x < list->iAddressCount; ++x) { sprintf(sbuf, "inet%d", x); tmp = alloc_array(3); val_array_ptr(tmp)[0] = alloc_string(sbuf); memcpy(&addr, &list->Address[x].lpSockaddr->sa_data[2], 4); //(SOCKADDR_IN *)list.Address[x].lpSockaddr)->sin_addr val_array_ptr(tmp)[1] = alloc_int(addr); val_array_ptr(tmp)[2] = val_null; if( cur ) val_array_ptr(cur)[2] = tmp; else rv = tmp; cur = tmp; } // insert the localhost record. if(list->iAddressCount > 0) { sprintf(sbuf, "inet%d", list->iAddressCount); tmp = alloc_array(3); val_array_ptr(tmp)[0] = alloc_string(sbuf); val_array_ptr(tmp)[1] = alloc_int(16777343); val_array_ptr(tmp)[2] = val_null; if( cur ) val_array_ptr(cur)[2] = tmp; else rv = tmp; cur = tmp; } free(buf); return rv; #else struct ifconf ifc; int s; int icnt = 10; // number of potential network interfaces. s = socket(AF_INET, SOCK_DGRAM,0); if(s < 0) neko_error(); ifc.ifc_buf = NULL; while(1) { ifc.ifc_len = sizeof(struct ifreq) * icnt; ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len); if(ioctl(s, SIOCGIFCONF, &ifc) < 0) { close(s); free(ifc.ifc_buf); neko_error(); } if(ifc.ifc_len == icnt * sizeof(struct ifreq)) { // may have more interfaces than we allowed for. icnt += 5; continue; } break; } rv = alloc_array(ifc.ifc_len/sizeof(struct ifreq)); struct ifreq *ifr = ifc.ifc_req; //struct ifreq ifr2; for(x = 0, c = 0; x < ifc.ifc_len; x += sizeof(struct ifreq), c++) { if(ifr->ifr_addr.sa_family == AF_INET) { printf("x: %d c: %d name: %s\n", x, c, ifr->ifr_name); tmp = alloc_array(3); val_array_ptr(tmp)[0] = alloc_string(ifr->ifr_name); memcpy(&addr, &ifr->ifr_addr.sa_data[2],4); val_array_ptr(tmp)[1] = alloc_int(addr); val_array_ptr(tmp)[2] = val_null; if( cur ) val_array_ptr(cur)[2] = tmp; else rv = tmp; cur = tmp; } ifr++; } close(s); free(ifc.ifc_buf); return rv; #endif }
/** sys_read_dir : string -> string list <doc>Return the content of a directory</doc> **/ 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; }
/** sys_remove_dir : string -> void <doc>Remove a directory. Exception on error</doc> **/ static value sys_remove_dir( value path ) { val_check(path,string); if( rmdir(val_string(path)) != 0 ) neko_error(); return val_true; }
/** set_cwd : string -> void <doc>Set current working directory</doc> **/ static value set_cwd( value d ) { val_check(d,string); if( chdir(val_string(d)) ) neko_error(); return val_true; }
/** file_delete : string -> void <doc>Delete the file. Exception on error.</doc> **/ static value file_delete( value path ) { val_check(path,string); if( unlink(val_string(path)) != 0 ) neko_error(); return val_true; }
/** process_run : cmd:string -> args:string array -> 'process <doc> Start a process using a command and the specified arguments. </doc> **/ CAMLprim value process_run( value cmd, value vargs ) { int i; vprocess *p; val_check(cmd,string); val_check(vargs,array); # ifdef _WIN32 { SECURITY_ATTRIBUTES sattr; STARTUPINFO sinf; HANDLE proc = GetCurrentProcess(); HANDLE oread,eread,iwrite; // creates commandline buffer b = alloc_buffer(NULL); char *sargs; buffer_append_char(b,'"'); buffer_append_str(b,val_string(cmd)); buffer_append_char(b,'"'); for(i=0;i<val_array_size(vargs);i++) { value v = val_array_ptr(vargs)[i]; int j,len; val_check(v,string); len = val_strlen(v); buffer_append_str(b," \""); for(j=0;j<len;j++) { char c = val_string(v)[j]; switch( c ) { case '"': buffer_append_str(b,"\\\""); break; case '\\': buffer_append_str(b,"\\\\"); break; default: buffer_append_char(b,c); break; } } buffer_append_char(b,'"'); } sargs = buffer_to_string(b); p = (vprocess*)alloc_private(sizeof(vprocess)); // startup process sattr.nLength = sizeof(sattr); sattr.bInheritHandle = TRUE; sattr.lpSecurityDescriptor = NULL; memset(&sinf,0,sizeof(sinf)); sinf.cb = sizeof(sinf); sinf.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; sinf.wShowWindow = SW_HIDE; CreatePipe(&oread,&sinf.hStdOutput,&sattr,0); CreatePipe(&eread,&sinf.hStdError,&sattr,0); CreatePipe(&sinf.hStdInput,&iwrite,&sattr,0); DuplicateHandle(proc,oread,proc,&p->oread,0,FALSE,DUPLICATE_SAME_ACCESS); DuplicateHandle(proc,eread,proc,&p->eread,0,FALSE,DUPLICATE_SAME_ACCESS); DuplicateHandle(proc,iwrite,proc,&p->iwrite,0,FALSE,DUPLICATE_SAME_ACCESS); CloseHandle(oread); CloseHandle(eread); CloseHandle(iwrite); if( !CreateProcess(NULL,val_string(sargs),NULL,NULL,TRUE,0,NULL,NULL,&sinf,&p->pinf) ) { CloseHandle(p->eread); CloseHandle(p->oread); CloseHandle(p->iwrite); free(sargs); neko_error(); } free(sargs); // close unused pipes CloseHandle(sinf.hStdOutput); CloseHandle(sinf.hStdError); CloseHandle(sinf.hStdInput); } # else char **argv = (char**)alloc_private(sizeof(char*)*(val_array_size(vargs)+2)); argv[0] = val_string(cmd); for(i=0;i<val_array_size(vargs);i++) { value v = val_array_ptr(vargs)[i]; val_check(v,string); argv[i+1] = val_string(v); } argv[i+1] = NULL; int input[2], output[2], error[2]; if( pipe(input) || pipe(output) || pipe(error) ) neko_error(); p = (vprocess*)alloc_private(sizeof(vprocess)); p->pid = fork(); if( p->pid == -1 ) { do_close(input[0]); do_close(input[1]); do_close(output[0]); do_close(output[1]); do_close(error[0]); do_close(error[1]); neko_error(); } // child if( p->pid == 0 ) { close(input[1]); close(output[0]); close(error[0]); dup2(input[0],0); dup2(output[1],1); dup2(error[1],2); execvp(val_string(cmd),argv); fprintf(stderr,"Command not found : %s\n",val_string(cmd)); exit(1); } // parent do_close(input[0]); do_close(output[1]); do_close(error[1]); p->iwrite = input[1]; p->oread = output[0]; p->eread = error[0]; # endif { value vp = alloc_abstract(k_process,p); val_gc(vp,free_process); return vp; } }
/** process_run : cmd:string -> args:string array -> 'process <doc> Start a process using a command and the specified arguments. When args is not null, cmd and args will be auto-quoted/escaped. If no auto-quoting/escaping is desired, you should append necessary arguments to cmd as if it is inputted to the shell directly, and pass null as args. </doc> **/ static value process_run( value cmd, value vargs ) { int i, isRaw; vprocess *p; val_check(cmd,string); isRaw = val_is_null(vargs); if (!isRaw) { val_check(vargs,array); } # ifdef NEKO_WINDOWS { SECURITY_ATTRIBUTES sattr; STARTUPINFO sinf; HANDLE proc = GetCurrentProcess(); HANDLE oread,eread,iwrite; // creates commandline buffer b = alloc_buffer(NULL); value sargs; if (isRaw) { char* cmdexe = getenv("COMSPEC"); if (!cmdexe) cmdexe = "cmd.exe"; buffer_append(b,"\""); buffer_append(b,cmdexe); buffer_append(b,"\" /C \""); buffer_append(b,val_string(cmd)); buffer_append_char(b,'"'); } else { buffer_append_char(b,'"'); val_buffer(b,cmd); buffer_append_char(b,'"'); for(i=0;i<val_array_size(vargs);i++) { value v = val_array_ptr(vargs)[i]; int j,len; unsigned int bs_count = 0; unsigned int k; val_check(v,string); len = val_strlen(v); buffer_append(b," \""); for(j=0;j<len;j++) { char c = val_string(v)[j]; switch( c ) { case '"': // Double backslashes. for (k=0;k<bs_count*2;k++) { buffer_append_char(b,'\\'); } bs_count = 0; buffer_append(b, "\\\""); break; case '\\': // Don't know if we need to double yet. bs_count++; break; default: // Normal char for (k=0;k<bs_count;k++) { buffer_append_char(b,'\\'); } bs_count = 0; buffer_append_char(b,c); break; } } // Add remaining backslashes, if any. for (k=0;k<bs_count*2;k++) { buffer_append_char(b,'\\'); } buffer_append_char(b,'"'); } } sargs = buffer_to_string(b); p = (vprocess*)alloc_private(sizeof(vprocess)); // startup process sattr.nLength = sizeof(sattr); sattr.bInheritHandle = TRUE; sattr.lpSecurityDescriptor = NULL; memset(&sinf,0,sizeof(sinf)); sinf.cb = sizeof(sinf); sinf.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; sinf.wShowWindow = SW_HIDE; CreatePipe(&oread,&sinf.hStdOutput,&sattr,0); CreatePipe(&eread,&sinf.hStdError,&sattr,0); CreatePipe(&sinf.hStdInput,&iwrite,&sattr,0); DuplicateHandle(proc,oread,proc,&p->oread,0,FALSE,DUPLICATE_SAME_ACCESS); DuplicateHandle(proc,eread,proc,&p->eread,0,FALSE,DUPLICATE_SAME_ACCESS); DuplicateHandle(proc,iwrite,proc,&p->iwrite,0,FALSE,DUPLICATE_SAME_ACCESS); CloseHandle(oread); CloseHandle(eread); CloseHandle(iwrite); if( !CreateProcess(NULL,val_string(sargs),NULL,NULL,TRUE,0,NULL,NULL,&sinf,&p->pinf) ) neko_error(); // close unused pipes CloseHandle(sinf.hStdOutput); CloseHandle(sinf.hStdError); CloseHandle(sinf.hStdInput); } # else char **argv; if (isRaw) { argv = (char**)alloc_private(sizeof(char*)*4); argv[0] = "/bin/sh"; argv[1] = "-c"; argv[2] = val_string(cmd); argv[3] = NULL; } else { argv = (char**)alloc_private(sizeof(char*)*(val_array_size(vargs)+2)); argv[0] = val_string(cmd); for(i=0;i<val_array_size(vargs);i++) { value v = val_array_ptr(vargs)[i]; val_check(v,string); argv[i+1] = val_string(v); } argv[i+1] = NULL; } int input[2], output[2], error[2]; if( pipe(input) || pipe(output) || pipe(error) ) neko_error(); p = (vprocess*)alloc_private(sizeof(vprocess)); p->pid = fork(); if( p->pid == -1 ) { do_close(input[0]); do_close(input[1]); do_close(output[0]); do_close(output[1]); do_close(error[0]); do_close(error[1]); neko_error(); } // child if( p->pid == 0 ) { close(input[1]); close(output[0]); close(error[0]); dup2(input[0],0); dup2(output[1],1); dup2(error[1],2); execvp(argv[0],argv); fprintf(stderr,"Command not found : %s\n",val_string(cmd)); exit(1); } // parent do_close(input[0]); do_close(output[1]); do_close(error[1]); p->iwrite = input[1]; p->oread = output[0]; p->eread = error[0]; # endif { value vp = alloc_abstract(k_process,p); val_gc(vp,free_process); return vp; } }
/** host_local : void -> string <doc>Return the local host name.</doc> **/ static value host_local() { char buf[256]; if( gethostname(buf,256) == SOCKET_ERROR ) neko_error(); return alloc_string(buf); }