/* nl-filesys.c --- I/O process control, date/time - functions for newLISP Copyright (C) 2007 Lutz Mueller 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 3 of the License, 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, see . */ #include "newlisp.h" #include #include "protos.h" #ifdef SOLARIS #include #ifndef TRU64 #define FIONREAD I_NREAD #endif #endif #ifndef WIN_32 #include #include #include #include #include #endif #ifdef OS2 #include int semctl(int semid, int semnum, int cmd, ...); #endif #ifdef WIN_32 #define fgetc win32_fgetc #define random rand #define srandom srand #include #include #include #define popen _popen #define pclose _pclose #define pipe _pipe /* Set binary as default file mode for Windows. See also http://www.mingw.org/MinGWiki/index.php/binary */ unsigned int _CRT_fmode = _O_BINARY; struct timezone { int tz_minuteswest; int tz_dsttime; }; int gettimeofday( struct timeval *tp, struct timezone *tzp ); int setenv (const char *name, const char *value, int replace); #ifdef USE_WIN_UTF16PATH INT64 fileSizeW(WCHAR * pathName); #endif #endif #ifndef WIN_32 #include #define SOCKET_ERROR -1 #define INVALID_SOCKET -1 #endif #ifdef LINUX char * strptime(const char * str, const char * fmt, struct tm * ttm); #endif size_t calcDateValue(int year, int month, int day, int hour, int min, int sec); extern STREAM readLineStream; extern FILE * IOchannel; CELL * p_isFile(CELL * params) /* includes dev,socket,dir,file etc. */ { char * fileName; getString(params, &fileName); if(isFile(fileName) == 0) return(trueCell); return(nilCell); } int isFile(char * fileName) { struct stat fileInfo; #ifdef USE_WIN_UTF16PATH return(stat_utf16(fileName, &fileInfo)); #else return(stat(fileName, &fileInfo)); #endif } CELL * p_isDirectory(CELL * params) { char * fileName; getString(params, &fileName); if(isDir(fileName)) return(trueCell); return(nilCell); } int isDir(char * fileName) { struct stat fileInfo; #ifdef USE_WIN_UTF16PATH if(stat_utf16(fileName, &fileInfo) != 0) #else if(stat(fileName, &fileInfo) != 0) #endif return(0); if(S_ISDIR(fileInfo.st_mode)) return(1); return(0); } CELL * p_open(CELL * params) { char * fileName; char * accessMode; char * option = NULL; int handle; params = getString(params, &fileName); params = getString(params, &accessMode); if(params != nilCell) getString(params, &option); if( (handle = openFile(fileName, accessMode, option)) == (int)-1) return(nilCell); return(stuffInteger((UINT)handle)); } CELL * p_close(CELL * params) { UINT handle; getInteger(params, &handle); if(handle == 0) return(nilCell); if(handle == printDevice) printDevice = 0; if(close((int)handle) == -1) return(nilCell); return(trueCell); } CELL * p_readChar(CELL * params) { UINT handle; unsigned char chr; getInteger(params, &handle); if(read((int)handle, &chr, 1) <= 0) return(nilCell); return(stuffInteger((UINT)chr)); } CELL * p_readBuffer(CELL * params) { UINT handle; size_t size, length; ssize_t bytesRead = 0; int found = 0; char * waitFor; char chr; STREAM stream; CELL * strCell; SYMBOL * readSptr; params = getInteger(params, &handle); params = getSymbol(params, &readSptr); params = getInteger(params, (UINT *)&size); if(isProtected(readSptr->flags)) return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(readSptr))); memset(&stream, 0, sizeof(stream)); if(params == nilCell) { openStrStream(&stream, size, 0); found = 1; if((bytesRead = read(handle, stream.buffer, size)) == -1) { closeStrStream(&stream); return(nilCell); } } else { getString(params, &waitFor); openStrStream(&stream, MAX_LINE, 0); length = strlen(waitFor); while(bytesRead < size) { if(read(handle, &chr, 1) <= 0) break; writeStreamChar(&stream, chr); if(++bytesRead < length) continue; if(strcmp(waitFor, stream.ptr - length) == 0) { found = 1; break; } } } if(bytesRead == 0) { deleteList((CELL *)readSptr->contents); readSptr->contents = (UINT)nilCell; closeStrStream(&stream); return(nilCell); } strCell = getCell(CELL_STRING); strCell->aux = bytesRead + 1; stream.buffer = reallocMemory(stream.buffer, bytesRead +1); strCell->contents = (UINT)stream.buffer; deleteList((CELL *)readSptr->contents); readSptr->contents = (UINT)strCell; if(found) return(stuffInteger(bytesRead)); return(nilCell); } CELL * p_readFile(CELL * params) { char * fileName; char * buffer = NULL; CELL * cell; ssize_t size; params = getString(params, &fileName); if(my_strnicmp(fileName, "http://", 7) == 0) return(getPutPostDeleteUrl(fileName, params, HTTP_GET_URL, 0)); if(my_strnicmp(fileName, "file://", 7) == 0) fileName = fileName + 7; if((size = readFile(fileName, &buffer)) == -1) return(nilCell); cell = getCell(CELL_STRING); cell->aux = size + 1; cell->contents = (UINT)buffer; return(cell); } /* allocate a buffer and reads a file into it */ ssize_t readFile(char * fileName, char * * buffer) { int handle; size_t size; struct stat fileInfo; #ifdef USE_WIN_UTF16PATH if(stat_utf16(fileName, &fileInfo) != 0) #else if(stat(fileName, &fileInfo) != 0) #endif return(-1); size = fileInfo.st_size; if( (handle = openFile(fileName, "r", NULL)) == (int)-1) return(-1); *buffer = callocMemory(size+1); if(read(handle, *buffer, size) == -1) { freeMemory(*buffer); close(handle); *buffer = NULL; return(-1); } close(handle); return(size); } CELL * p_writeChar(CELL * params) { UINT handle; UINT data; size_t count; unsigned char chr; params = getInteger(params, &handle); count = 0; while(params != nilCell) { params = getInteger(params, &data); chr = (unsigned char)data; if(write((int)handle, (void *)&chr, 1) == -1) return(nilCell); ++count; } return(stuffInteger(count)); } size_t appendCellString(CELL * cell, char * buffer, size_t size) { cell->contents = (UINT)reallocMemory((char *)cell->contents, cell->aux + size); memcpy((char *)cell->contents + cell->aux - 1, buffer, size); cell->aux += size; *((char *)cell->contents + cell->aux - 1) = 0; return(size); } CELL * p_writeBuffer(CELL * params) { UINT handle; ssize_t bytesWritten; size_t size; char * buffer; CELL * strCell; SYMBOL * writeSptr; CELL * cell; CELL * flagPtr = NULL; cell = evalCheckProtected(params, &flagPtr); params = params->next; if(isNumber(cell->type)) { getIntegerExt(cell, &handle, FALSE); cell = NULL; } else if(cell->type != CELL_STRING) return(errorProc(ERR_NUMBER_OR_STRING_EXPECTED)); strCell = evaluateExpression(params); if(strCell->type == CELL_SYMBOL) { writeSptr = (SYMBOL *)strCell->contents; strCell = (CELL *)writeSptr->contents; } else if(strCell->type == CELL_DYN_SYMBOL) { writeSptr = getDynamicSymbol(strCell); strCell = (CELL *)writeSptr->contents; } if(strCell->type != CELL_STRING) return(errorProcExt(ERR_STRING_EXPECTED, params)); if(params->next == nilCell) size = strCell->aux - 1; else getInteger(params->next, (UINT *)&size); buffer = (char *)strCell->contents; if(size > (strCell->aux - 1)) size = strCell->aux - 1; if(cell != NULL) { if(flagPtr) return(errorProcExt(ERR_SYMBOL_PROTECTED, flagPtr)); return(stuffInteger(appendCellString(cell, buffer, size))); } if((bytesWritten = write((int)handle, buffer, size)) == (UINT)-1) return(nilCell); return(stuffInteger(bytesWritten)); } CELL * p_appendFile(CELL * params) { return(appendWriteFile(params, "a")); } CELL * p_writeFile(CELL * params) { return(appendWriteFile(params, "w")); } CELL * appendWriteFile(CELL * params, char * type) { char * fileName; int handle; char * buffer; size_t size; params = getString(params, &fileName); if(my_strnicmp(fileName, "http://", 7) == 0) return(getPutPostDeleteUrl(fileName, params, (*type == 'w') ? HTTP_PUT_URL : HTTP_PUT_APPEND_URL, 0)); if(my_strnicmp(fileName, "file://", 7) == 0) fileName = fileName + 7; getStringSize(params, &buffer, &size, TRUE); if( (handle = openFile(fileName, type, NULL)) == (int)-1) return(nilCell); if(write((int)handle, buffer, size) == -1) return(nilCell); close(handle); return(stuffInteger(size)); } CELL * p_writeLine(CELL * params) { char * buffer; UINT handle; CELL * flagPtr = NULL; size_t size; if(params->type == CELL_NIL) buffer = readLineStream.buffer; else params = getStringSize(params, &buffer, &size, TRUE); if(params != nilCell) { params = evalCheckProtected(params, &flagPtr); if(isNumber(params->type)) { getIntegerExt(params, &handle, FALSE); if(write((int)handle, buffer, strlen(buffer)) == -1) return(nilCell); if(write((int)handle, LINE_FEED, strlen(LINE_FEED)) == -1) return(nilCell); } if(params->type == CELL_STRING) { if(flagPtr) return(errorProcExt(ERR_SYMBOL_PROTECTED, flagPtr)); appendCellString(params, buffer, size); appendCellString(params, LINE_FEED, strlen(LINE_FEED)); } } else { varPrintf(OUT_DEVICE, "%s", buffer); varPrintf(OUT_DEVICE, LINE_FEED); } return(stuffString(buffer)); } CELL * p_seek(CELL * params) { UINT handle; #ifdef LFS INT64 paramPosition; off_t newPosition; #else off_t paramPosition; off_t newPosition; #endif params = getInteger(params, &handle); if(params == nilCell) { if(handle == 0) newPosition = ftell(stdout); else if( (newPosition = lseek(handle, 0, SEEK_CUR)) == -1) return(nilCell); } else { #ifdef LFS getInteger64(params, ¶mPosition); #else getInteger(params, (UINT *)¶mPosition); #endif newPosition = paramPosition; if(newPosition == -1) { if( (newPosition = lseek((int)handle, 0, SEEK_END)) == -1) return(nilCell); } else { if( lseek((int)handle, newPosition, SEEK_SET) == -1) return(nilCell); } } paramPosition = newPosition; #ifdef LFS return(stuffInteger64(paramPosition)); #else return(stuffInteger(paramPosition)); #endif } char * readStreamLine(STREAM * stream, FILE * inStream) { int chr; openStrStream(stream, MAX_STRING, 1); #ifdef TRU64 do { errno = 0; #endif while((chr = fgetc(inStream)) != EOF) { if(chr == '\n') break; if(chr == '\r') { chr = fgetc(inStream); if(chr == '\n' || chr == EOF) break; } writeStreamChar(stream, chr); } #ifdef TRU64 } while (errno == EINTR); #endif if(chr == EOF && stream->position == 0) return(NULL); return(stream->buffer); } CELL * p_readLine(CELL * params) { UINT handle; unsigned char chr; char * line; int bytesRead; if(params != nilCell) getInteger(params, &handle); else handle = printDevice; if(handle == 0) { if((line = readStreamLine(&readLineStream, IOchannel)) == NULL) return(nilCell); return(stuffString(line)); } openStrStream(&readLineStream, MAX_STRING, 1); while(TRUE) { if((bytesRead = read((int)handle, &chr, 1)) <= 0) break; if(chr == '\n') break; if(chr == '\r') { if(read((int)handle, &chr, 1) < 0) break; if(chr == '\n') break; } writeStreamChar(&readLineStream, chr); } if(bytesRead <= 0 && readLineStream.position == 0) return(nilCell); return(stuffString(readLineStream.buffer));; } CELL * p_currentLine(CELL * params) { return(stuffString(readLineStream.buffer)); } int openFile(char * fileName, char * accessMode, char * option) { int blocking = 0; #ifndef WIN_32 if(option != NULL && *option == 'n') blocking = O_NONBLOCK; #endif if(*accessMode == 'r') return(open(fileName, O_RDONLY | O_BINARY | blocking, 0)); else if(*accessMode == 'w') #ifdef WIN_32 return(open( fileName, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IREAD | S_IWRITE) ); #else return(open(fileName,O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | blocking, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH)); /* rw-rw-rw */ #endif else if(*accessMode == 'u') return(open(fileName, O_RDWR | O_BINARY, 0)); else if(*accessMode == 'a') { #ifdef WIN_32 return(open(fileName, O_RDWR | O_APPEND | O_BINARY | O_CREAT, S_IREAD | S_IWRITE)); #else return(open(fileName, O_RDWR | O_APPEND | O_BINARY | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH)); /* rw-rw-rw */ #endif } return(-1); } /* ------------------------- directory management ------------------------- */ CELL * p_copyFile(CELL * params) { char * fromName; char * toName; int fromHandle, toHandle; unsigned char * copyBuffer; UINT bytesRead; params = getString(params, &fromName); getString(params, &toName); if((fromHandle = openFile(fromName, "read", NULL)) < 0) return(nilCell); if((toHandle = openFile(toName,"write", NULL)) < 0) return(nilCell); copyBuffer = allocMemory(MAX_FILE_BUFFER); do { bytesRead = read(fromHandle, copyBuffer, MAX_FILE_BUFFER); write(toHandle, copyBuffer, (int)bytesRead); } while (bytesRead == MAX_FILE_BUFFER); free(copyBuffer); close((int)fromHandle); close((int)toHandle); return(trueCell); } CELL * p_renameFile(CELL * params) { char *oldName; char *newName; params = getString(params, &oldName); getString(params, &newName); return(rename(oldName, newName) == 0 ? trueCell : nilCell); } CELL * p_deleteFile(CELL * params) { char * fileName; params = getString(params, &fileName); if(my_strnicmp(fileName, "http://", 7) == 0) return(getPutPostDeleteUrl(fileName, params, HTTP_DELETE_URL, 0)); return(unlink(fileName) == 0 ? trueCell : nilCell); } CELL * p_makeDir(CELL * params) { char * dirString; mode_t mode; UINT inMode; params = getString(params, &dirString); if(params != nilCell) { getInteger(params, &inMode); mode = inMode; } else mode = 0777; /* drwxrwxrwx gets user masked to drwxr-xr-x on most UNIX */ #ifdef WIN_32 return(mkdir(dirString) == 0 ? trueCell : nilCell); #else return(mkdir(dirString, (mode_t)mode) == 0 ? trueCell : nilCell); #endif } CELL * p_removeDir(CELL * params) { char * dirString; getString(params, &dirString); return(rmdir(dirString) == 0 ? trueCell : nilCell); } CELL * p_changeDir(CELL * params) { char * newDir; getString(params, &newDir); return(chdir(newDir) == 0 ? trueCell : nilCell); } CELL * p_directory(CELL * params) { CELL * dirList; CELL * lastEntry; char * dirPath; char * fileName; char * pattern = NULL; UINT options = 0; DIR * dir; struct dirent * dEnt; if(params != nilCell) { params = getString(params, &dirPath); if(params != nilCell) { params = getString(params, &pattern); if(params != nilCell) getInteger(params, &options); } } else dirPath = "."; dirList = getCell(CELL_EXPRESSION); lastEntry = NULL; dir = opendir(dirPath); if(dir == NULL) return(nilCell); while((dEnt = readdir(dir)) != NULL) { #ifdef USE_WIN_UTF16PATH fileName = utf16_to_utf8(dEnt->d_name); #else fileName = dEnt->d_name; #endif if(pattern) { if(searchBufferRegex(fileName, 0, pattern, strlen(fileName), options, NULL) == -1) continue; } if(lastEntry == NULL) { lastEntry = stuffString(fileName); dirList->contents = (UINT)lastEntry; } else { lastEntry->next = stuffString(fileName); lastEntry = lastEntry->next; } #ifdef USE_WIN_UTF16PATH free(fileName); #endif } closedir(dir); return(dirList); } #define DOT_PATH ".\000" CELL * p_realpath(CELL * params) { char path[PATH_MAX]; char * dir; if(params != nilCell) getString(params, &dir); else dir = DOT_PATH; if(realpath(dir, path) == NULL) return(nilCell); return(stuffString(path)); } CELL * p_fileInfo(CELL * params) { #ifdef USE_WIN_UTF16PATH WCHAR * pathName; struct _stat fileInfo; #else char * pathName; struct stat fileInfo; #endif CELL * list; #ifdef USE_WIN_UTF16PATH char * utf8pathName; params = getString(params, &utf8pathName); pathName = utf8_to_utf16(utf8pathName); #else params = getString(params, &pathName); #endif if(lstat(pathName, &fileInfo) != 0) { #ifdef USE_WIN_UTF16PATH free(pathName); #endif return(nilCell); } list = stuffIntegerList( 8, (UINT)fileInfo.st_size, (UINT)fileInfo.st_mode, (UINT)fileInfo.st_rdev, (UINT)fileInfo.st_uid, (UINT)fileInfo.st_gid, (UINT)fileInfo.st_atime, (UINT)fileInfo.st_mtime, (UINT)fileInfo.st_ctime ); #ifndef NEWLISP64 #ifdef LFS ((CELL *)list->contents)->type = CELL_INT64; #ifdef USE_WIN_UTF16PATH *(INT64 *)&((CELL *)list->contents)->aux = fileSizeW(pathName); #else *(INT64 *)&((CELL *)list->contents)->aux = fileSize(pathName); #endif /* UTF16PATH */ #endif /* LFS */ #endif /* NEWLISP64 */ #ifdef USE_WIN_UTF16PATH free(pathName); #endif if(params != nilCell) return(copyCell(implicitIndexList(list, params))); return(list); } #ifdef LFS INT64 fileSize(char * pathName) { int handle; INT64 size; #ifndef WIN_32 handle = open(pathName,O_RDONLY | O_BINARY | O_NONBLOCK , 0); #else handle = open(pathName,O_RDONLY | O_BINARY, 0); #endif size = lseek(handle, 0, SEEK_END); close(handle); if(size == -1) size = 0; return(size); } #endif /* ------------------------- processes and pipes ------------------------- */ CELL * p_system(CELL *params) { char * command; getString(params, &command); return(stuffInteger((UINT)system(command))); } CELL * p_exec(CELL * params) { char * command, * data; params = getString(params, &command); if(params == nilCell) return(readProcess(command)); getString(params, &data); return(writeProcess(command, data)); } CELL * readProcess(char * command) { CELL * lineList; CELL * lastLine; FILE * handle; char * line; lastLine = NULL; if((handle = popen(command , "r")) == NULL) return(nilCell); lineList = getCell(CELL_EXPRESSION); while((line = readStreamLine(&readLineStream, handle)) != NULL) { if(lastLine == NULL) { lastLine= stuffString(line); lineList->contents = (UINT)lastLine; } else { lastLine->next = stuffString(line); lastLine = lastLine->next; } } pclose(handle); return(lineList); } CELL * writeProcess(char * command, char * data) { FILE * handle; if((handle = popen(command, "w")) == NULL) return(nilCell); if(fwrite(data, sizeof(char), strlen(data), handle) < strlen(data)) return(nilCell); pclose(handle); return(trueCell); } #ifdef WIN_32 int winPipe(UINT * inpipe, UINT * outpipe); int winPipedProcess(char * command, int inpipe, int outpipe, int option); CELL * plainProcess(char * command); CELL * p_pipe(CELL * params) { /* for MinGW only int handles[2]; if(pipe(handles, MAX_STRING, O_BINARY) != 0) return(nilCell); return(stuffIntegerList(2, (UINT)handles[0], (UINT)handles[1])); */ UINT hin, hout; if(!winPipe(&hin, &hout)) /* see file win32-util.c */ return(nilCell); return(stuffIntegerList(2, hin, hout)); } CELL * p_process(CELL * params) { char * command; int result; UINT inpipe = 0, outpipe = 0, option = 1; params = getString(params, &command); if(params != nilCell) { params = getInteger(params, (UINT *)&inpipe); params = getInteger(params, (UINT *)&outpipe); if(params != nilCell) getInteger(params, (UINT *)&option); } else return(plainProcess(command)); result = winPipedProcess(command, (int)inpipe, (int)outpipe, (int)option); if(!result) return(nilCell); return(stuffInteger(result)); } CELL * plainProcess(char * command) { char * cPtr; char * argv[6]; int idx, len; len = strlen(command); cPtr = allocMemory(len + 1); memcpy(cPtr, command, len + 1); argv[0] = cPtr; for(idx = 1; idx < 5; idx++) { cPtr = strchr(cPtr, ' '); if(cPtr == NULL) break; while(*cPtr == ' ') *cPtr++ = 0; argv[idx] = cPtr; } argv[idx] = NULL; #ifdef WIN_32 idx = spawnvp(P_NOWAIT, argv[0], (const char * const *)argv); #else idx = spawnvp(P_NOWAIT, argv[0], argv); #endif free(argv[0]); if(idx == -1) return(nilCell); return(stuffInteger(idx)); } #else /* not WIN_32 */ CELL * p_pipe(CELL * params) { int handles[2]; if(pipe(handles) != 0) return(nilCell); return(stuffIntegerList(2, (UINT)handles[0], (UINT)handles[1])); } CELL * p_process(CELL * params) { char * command; int forkResult; UINT inpipe = 0, outpipe = 0, errpipe = 0; params = getString(params, &command); if(params != nilCell) { params = getInteger(params, (UINT *)&inpipe); params = getInteger(params, (UINT *)&outpipe); if(params != nilCell) getInteger(params, (UINT *)&errpipe); } if((forkResult = fork()) == -1) return(nilCell); if(forkResult == 0) { /* redirect stdin and stdout, stderr to pipe handles */ if(inpipe) { close(STDIN_FILENO); if(dup2((int)inpipe, STDIN_FILENO) == -1) exit(0); close((int)inpipe); } if(outpipe) { close(STDOUT_FILENO); if(dup2((int)outpipe, STDOUT_FILENO) == -1) exit(0); if(!errpipe) if(dup2((int)outpipe, STDERR_FILENO) == -1) exit(0); close((int)outpipe); } if(errpipe) { close(STDERR_FILENO); if(dup2((int)errpipe, STDERR_FILENO) == -1) exit(0); close((int)errpipe); } system(command); exit(0); } return(stuffInteger(forkResult)); } CELL * p_fork(CELL * params) { int forkResult; if((forkResult = fork()) == -1) return(nilCell); if(forkResult == 0) { evaluateExpression(params); exit(0); } return(stuffInteger(forkResult)); } CELL * p_waitpid(CELL * params) { UINT pid, options; int result; params = getInteger(params, (UINT *)&pid); if(params != nilCell) getInteger(params, (UINT *)&options); else options = 0; waitpid((int)pid, &result, (int)options); return(stuffInteger(result)); } #endif /* ------------------------------ semaphores --------------------------------- */ #ifdef WIN_32 UINT winCreateSemaphore(void); UINT winWaitSemaphore(UINT hSemaphore); UINT winSignalSemaphore(UINT hSemaphore, int count); UINT winDeleteSemaphore(UINT hSemaphore); int getSemaphoreCount(UINT hSemaphore); CELL * p_semaphore(CELL * params) { UINT sem_id; long value; if(params != nilCell) { params = getInteger(params, &sem_id); if(params != nilCell) { getInteger(params,(UINT *)&value); if(value == 0) { if(!winDeleteSemaphore(sem_id)) return(nilCell); return(trueCell); } /* wait or signal */ if(value < 0) { if(winWaitSemaphore(sem_id)) return(trueCell); return(nilCell); } if(value > 0) { if(winSignalSemaphore(sem_id, value)) return(trueCell); return(nilCell); } } else { /* return semaphore value, not on Win32 ? */ return(nilCell); } } /* create semaphore */ if((sem_id = winCreateSemaphore()) == 0) return(nilCell); return(stuffInteger(sem_id)); } #endif #ifndef WIN_32 /* only available on Linux/UNIX */ CELL * p_semaphore(CELL * params) { UINT sem_id, value = 0; struct sembuf sem_b; #ifdef SOLARIS #ifndef NEWLISP64 int semun_val = 0; #endif #endif #ifdef MAC_OSX union semun semu; semu.val = 0; #endif if(params != nilCell) { params = getInteger(params, (UINT*)&sem_id); if(params != nilCell) { getInteger(params,(UINT*)&value); if(value == 0) { /* remove semaphore */ #ifdef SOLARIS #ifdef TRU64 if(semctl(sem_id, 0, IPC_RMID, 0) == -1) #else #ifndef NEWLISP64 if(semctl(sem_id, 0, IPC_RMID, &semun_val) == -1) #else if(semctl(sem_id, 0, IPC_RMID, 0) == -1) #endif #endif /* SOLARIS */ #else #ifdef MAC_OSX if(semctl(sem_id, 0, IPC_RMID, semu) == -1) #else if(semctl(sem_id, 0, IPC_RMID, 0) == -1) #endif #endif return(nilCell); return(trueCell); } /* wait or signal */ sem_b.sem_num = 0; sem_b.sem_op = value; sem_b.sem_flg = 0; if(semop(sem_id, &sem_b, 1) == -1) return(nilCell); return(trueCell); } else /* return semaphore value */ #ifdef MAC_OSX return(stuffInteger(semctl(sem_id, 0, GETVAL, semu))); #else return(stuffInteger(semctl(sem_id, 0, GETVAL))); #endif } /* create semaphore */ sem_id = semget(IPC_PRIVATE, 1, 0666 ); #ifdef SOLARIS #ifdef TRU64 if(semctl(sem_id, 0, SETVAL, 0) == -1) #else #ifndef NEWLISP64 if(semctl(sem_id, 0, SETVAL, &semun_val) == -1) #else if(semctl(sem_id, 0, SETVAL, 0) == -1) #endif #endif #else #ifdef MAC_OSX if(semctl(sem_id, 0, SETVAL, semu) == -1) #else if(semctl(sem_id, 0, SETVAL, 0) == -1) #endif #endif return(nilCell); return(stuffInteger(sem_id)); } #endif /* not WIN_32 */ union num_ptr { UINT num; UINT * ptr; }; #ifdef WIN_32 UINT winSharedMemory(int size); UINT * winMapView(UINT handle, int size); #endif #ifndef OS2 CELL * p_share(CELL * params) { union num_ptr address; CELL * cell; size_t size; char * str; static int pagesize = 0; #ifndef WIN_32 if(!pagesize) pagesize = getpagesize(); #else UINT handle; pagesize = 4096; #endif if(params != nilCell) { cell = evaluateExpression(params); #ifndef WIN_32 if(isNil(cell)) { getInteger(params->next, &address.num); if(munmap((void *)address.ptr, pagesize) == -1) return(nilCell); else return(trueCell); } #endif getIntegerExt(cell, &address.num, FALSE); params = params->next; #ifdef WIN_32 if((address.ptr = winMapView(address.num, pagesize)) == NULL) return(nilCell); #endif if(params != nilCell) /* write to shared memory */ { cell = evaluateExpression(params); if(cell->type == CELL_NIL) { *address.ptr = CELL_NIL; #ifdef WIN_32 UnmapViewOfFile(address.ptr); #endif return(nilCell); } if(cell->type == CELL_TRUE) { *address.ptr = CELL_TRUE; #ifdef WIN_32 UnmapViewOfFile(address.ptr); #endif return(trueCell); } if(cell->type == CELL_STRING) { getStringSize(cell, &str, &size, FALSE); if(size > (pagesize - 2 * sizeof(long) - 1)) size = pagesize - 2 * sizeof(long) - 1; *address.ptr = cell->type; *(address.ptr + 1) = size; memcpy((char *)(address.num + 2 * sizeof(long)), str, size); *(char *)(address.num + 2 * sizeof(long) + size) = 0; /* fall thru to address.ptr == CELL_STRING, to return sized string */ goto return_new_string_cell; } if(cell->type == CELL_LONG) { *address.ptr = cell->type; *(address.ptr + 1) = sizeof(long); *(address.ptr + 2) = cell->contents; #ifdef WIN_32 UnmapViewOfFile(address.ptr); #endif return(copyList(cell)); } #ifndef NEWLISP64 if(cell->type == CELL_INT64) { *address.ptr = cell->type; *(address.ptr + 1) = sizeof(INT64); memcpy(address.ptr + 2, (void *)&cell->aux, sizeof(INT64)); #ifdef WIN_32 UnmapViewOfFile(address.ptr); #endif return(copyList(cell)); } if(cell->type == CELL_FLOAT) { *address.ptr = cell->type; *(address.ptr + 1) = sizeof(double); *(address.ptr + 2) = cell->aux; *(address.ptr + 3) = cell->contents; #ifdef WIN_32 UnmapViewOfFile(address.ptr); #endif return(copyList(cell)); } #else /* NEWLISP64 */ if(cell->type == CELL_FLOAT) { *address.ptr = cell->type; *(address.ptr + 1) = sizeof(double); *(address.ptr + 2) = cell->contents; return(copyList(cell)); } #endif /* NEWLISP64 */ return(errorProcExt(ERR_ILLEGAL_TYPE, cell)); } if(*address.ptr == CELL_NIL) /* rrad from share memory */ { #ifdef WIN_32 UnmapViewOfFile(address.ptr); #endif return(nilCell); } if(*address.ptr == CELL_TRUE) { #ifdef WIN_32 UnmapViewOfFile(address.ptr); #endif return(trueCell); } if(*address.ptr == CELL_LONG) { cell = stuffInteger(*(address.ptr + 2)); #ifdef WIN_32 UnmapViewOfFile(address.ptr); #endif return(cell); } #ifndef NEWLISP64 if(*address.ptr == CELL_INT64) { cell = stuffInteger64(*(INT64 *)(address.ptr + 2)); #ifdef WIN_32 UnmapViewOfFile(address.ptr); #endif return(cell); } #endif if(*address.ptr == CELL_FLOAT) { #ifndef NEWLISP64 cell = getCell(CELL_FLOAT); cell->aux = *(address.ptr + 2); cell->contents = *(address.ptr + 3); #else cell = getCell(CELL_FLOAT); cell->contents = *(address.ptr + 2); #endif #ifdef WIN_32 UnmapViewOfFile(address.ptr); #endif return(cell); } if(*address.ptr == CELL_STRING) { return_new_string_cell: cell = getCell(CELL_STRING); cell->aux = *(address.ptr + 1) + 1; cell->contents = (UINT)allocMemory(cell->aux); memcpy((char *)cell->contents, (char*)(address.num + 2 * sizeof(long)), cell->aux); #ifdef WIN_32 UnmapViewOfFile(address.ptr); #endif return(cell); } return(nilCell); } #ifndef WIN_32 if((address.ptr = (UINT*)mmap( 0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0)) == (void*)-1) return(nilCell); memset((char *)address.num, 0, pagesize); return(stuffInteger(address.num)); #else if((handle = winSharedMemory(pagesize)) == 0) return(nilCell); if((address.ptr = winMapView(handle, pagesize)) == NULL) return(nilCell); memset((char *)address.num, 0, pagesize); return(stuffInteger(handle)); #endif } #endif /* no OS2 */ /* ------------------------------ time and date functions -------------------- */ CELL * p_systemInfo(CELL * params) { CELL * cell; cell = stuffIntegerList( 8, cellCount, MAX_CELL_COUNT, symbolCount, (UINT)recursionCount, (UINT)envStackIdx, MAX_CPU_STACK, version, opsys); if(params != nilCell) return(copyCell(implicitIndexList(cell, params))); return(cell); } CELL * p_systemError(CELL * params) { UINT init; if(params != nilCell) { getInteger(params, (UINT*)&init); errno=(int)init; } return(stuffInteger((UINT)errno)); } CELL * p_date(CELL * params) { time_t t; struct timeval tv; struct tm * ltm; char * ct; char * fmt; ssize_t offset; ssize_t tme; #ifdef SUPPORT_UTF8 #ifdef WCSFTIME int * ufmt; int * timeString; int size; #endif char * utf8str; #else char * timeString; #endif if(params == nilCell) { gettimeofday(&tv, NULL); t = tv.tv_sec; } else { params = getInteger(params, (UINT *)&tme); t = tme; if(params != nilCell) { params = getInteger(params, (UINT *)&offset); t += (int)offset * 60; } if(params != nilCell) { params = getString(params, &fmt); ltm = localtime(&t); #ifdef SUPPORT_UTF8 /* some Linux do UTF-8 but don't have wcsftime() or it is buggy */ #ifdef WCSFTIME size = utf8_wlen(fmt); ufmt = alloca(UTF8_MAX_BYTES * (size + 1)); utf8_wstr(ufmt, fmt, size); timeString = alloca(UTF8_MAX_BYTES * 128); size = wcsftime((wchar_t *)timeString, 127, (wchar_t *)ufmt, ltm); utf8str = alloca(size * UTF8_MAX_BYTES + 1); size = wstr_utf8(utf8str, timeString, size * UTF8_MAX_BYTES); return(stuffString(utf8str)); #else utf8str = alloca(128); strftime(utf8str, 127, fmt, ltm); return(stuffString(utf8str)); #endif /* WCSFTIME */ #else timeString = alloca(128); strftime(timeString, 127, fmt, ltm); return(stuffString(timeString)); #endif } } ct = ctime(&t); if(ct == NULL) return(nilCell); ct[strlen(ct) - 1] = 0; /* supress linefeed */ return(stuffString(ct)); } int milliSecTime(void) { struct timeval tv; struct tm * ttm; gettimeofday(&tv, NULL); ttm = localtime((time_t *)&tv.tv_sec); return (ttm->tm_hour * 3600000 + ttm->tm_min * 60000 + ttm->tm_sec * 1000 + tv.tv_usec/1000); } /* returns a differerence of 2 timeval structs in milliseconds */ int timediff(struct timeval out, struct timeval in ) { if( (out.tv_usec -= in.tv_usec) < 0 ) { out.tv_sec--; out.tv_usec += 1000000; } out.tv_sec -= in.tv_sec; return(out.tv_sec*1000 + (out.tv_usec/1000)); } #ifndef WIN_32 CELL * p_parseDate(CELL * params) { struct tm ttm; char * dateStr; char * formatStr; size_t dateValue; params = getString(params, &dateStr); params = getString(params, &formatStr); memset (&ttm, 0, sizeof (ttm)); if(strptime(dateStr, formatStr, &ttm) == NULL) return(nilCell); dateValue = calcDateValue( ttm.tm_year + 1900, ttm.tm_mon + 1, ttm.tm_mday, ttm.tm_hour, ttm.tm_min, ttm.tm_sec); return(stuffInteger(dateValue)); } #endif CELL * p_time(CELL * params) { struct timeval start, end; INT64 N = 1; int resultIdxSave; gettimeofday(&start, NULL); if(params->next != nilCell) getInteger64(params->next, &N); resultIdxSave = resultStackIdx; while(N--) { evaluateExpression(params); cleanupResults(resultIdxSave); } gettimeofday(&end, NULL); return(stuffInteger((UINT)timediff(end, start))); } CELL * p_timeOfDay(CELL * params) { return(stuffInteger(milliSecTime())); } CELL * p_now(CELL * params) { struct timeval tv; struct tm *ttm; struct tm *ltm; struct timezone tzp; ssize_t offset; gettimeofday(&tv, &tzp); if(params != nilCell) { getInteger(params, (UINT*)&offset); offset *= 60; tv.tv_sec += offset; } ltm = localtime((time_t *)&tv.tv_sec); ttm = gmtime((time_t *)&tv.tv_sec); return(stuffIntegerList( 11, (UINT)ttm->tm_year + 1900, (UINT)ttm->tm_mon + 1, (UINT)ttm->tm_mday, (UINT)ttm->tm_hour, (UINT)ttm->tm_min, (UINT)ttm->tm_sec, (UINT)tv.tv_usec, (UINT)ttm->tm_yday + 1, (UINT)ttm->tm_wday + 1, /* Note, that on SOLARIS tzp.tz_minuteswest and tzp.tz_dsttime might not work correctly and contain garbage */ (UINT)tzp.tz_minuteswest, #ifdef WIN_32 /* (UINT)ltm->tm_isdst */ (UINT)tzp.tz_dsttime #else (UINT)ltm->tm_isdst #endif )); } UINT seconds(void) { struct timeval tv; gettimeofday(&tv, NULL); return(tv.tv_sec); } CELL * p_dateValue(CELL * params) { struct timeval tv; ssize_t year, month, day, hour, min, sec; size_t dateValue; if(params->type == CELL_NIL) { gettimeofday(&tv, NULL); return(stuffInteger(tv.tv_sec)); } params = getInteger(params, (UINT *)&year); params = getInteger(params, (UINT *)&month); params = getInteger(params, (UINT *)&day); if(year < 1970) return(stuffInteger(0)); hour = min = sec = 0; if(params != nilCell) { params = getInteger(params, (UINT *)&hour); params = getInteger(params, (UINT *)&min); getInteger(params, (UINT *)&sec); } dateValue = calcDateValue(year, month, day, hour, min, sec); return(stuffInteger((UINT)dateValue)); } size_t calcDateValue(int year, int month, int day, int hour, int min, int sec) { size_t dateValue; dateValue = 367 * year - (7 * (year + ((month + 9) / 12)))/4 + (275 * month)/9 + day + 1721013; dateValue = dateValue * 24 * 3600 + hour * 3600 + min * 60 + sec - 413319296; /* correction for 1970-1-1 */ #ifdef NEWLISP64 dateValue = dateValue % 0x80000000; #endif return(dateValue); } #ifdef MAC_OSX extern int nanosleep(); #endif void mySleep(int ms) { #ifdef NANOSLEEP struct timespec tm; tm.tv_sec = ms / 1000; tm.tv_nsec = (ms - tm.tv_sec * 1000) * 1000000; nanosleep(&tm, 0); #else #ifdef WIN_32 _sleep(ms); #else sleep((ms + 500)/1000); #endif #endif } CELL * p_sleep(CELL * params) { size_t milliSecs; getInteger(params, (UINT *)&milliSecs); mySleep(milliSecs); return(stuffInteger((UINT)milliSecs)); } /* -------------------------------- environment functions ------------------- */ CELL * p_env(CELL * params) { char * varName; char * varValue; /* no parameters returns whole environment */ if(params == nilCell) return(environment()); /* one parameter get environment for one variable */ params = getString(params, &varName); if(params == nilCell) { if( (varValue = getenv(varName)) == NULL) return(nilCell); return(stuffString(varValue)); } /* two parameters sets environment for one variable */ getString(params, &varValue); if(setenv(varName, varValue, 1) != 0) return(nilCell); return(trueCell); } #ifdef MY_SETENV int my_setenv(const char * varName, const char * varValue, int flag) { char * envstr; envstr = allocMemory(strlen(varName) + strlen(varValue) + 2); strcpy(envstr, varName); strcat(envstr, "="); strcat(envstr, varValue); return(putenv(envstr)); } #endif #ifdef MAC_OSX #ifdef LIBRARY char ** environ = NULL; #else extern char ** environ; #endif #else #ifndef TRU64 extern char ** environ; #endif #endif CELL * environment(void) { char ** env; CELL * envList; CELL * lastEntry; lastEntry = NULL; envList = getCell(CELL_EXPRESSION); #ifdef MAC_OSX #ifdef LIBRARY return(envList); #endif #endif env = environ; while(*env) { if(lastEntry == NULL) { lastEntry = stuffString(*env); envList->contents = (UINT)lastEntry; } else { lastEntry->next = stuffString(*env); lastEntry = lastEntry->next; } env++; } return(envList); } /* --------------------- read the keyboard -----------------------------------*/ /* thanks to Peter van Eerten for contributing this function */ CELL * p_readKey(CELL * params) { #ifdef WIN_32 return(stuffInteger(getch())); #else #ifdef OS2 return(stuffInteger(getch())); #else struct termios term, oterm; char c = 0; tcgetattr(0, &oterm); memcpy(&term, &oterm, sizeof(term)); /* put the terminal in non-canonical mode, any reads timeout after 0.1 seconds or when a single character is read */ term.c_lflag &= ~(ICANON | ECHO); term.c_cc[VMIN] = 0; term.c_cc[VTIME] = 1; tcsetattr(0, TCSANOW, &term); #if defined (_BSD) || (MAC_OSX) while(read(0, &c, 1) == 0); #else while((c = (char)getchar()) == (char)-1); #endif /* reset the terminal to original state */ tcsetattr(0, TCSANOW, &oterm); return(stuffInteger(c)); #endif #endif } /* --------------------- peek a file descriptor ------------------------------*/ #ifndef WIN_32 CELL * p_peek(CELL * params) { UINT handle; #ifdef WIN_32 unsigned long result; #else int result; #endif getInteger(params, &handle); if(ioctl((int)handle, FIONREAD, &result) < 0) return(nilCell); return(stuffInteger((UINT)result)); } #endif /* --------------------- library functions not found on some OSs -------------*/ #ifdef MY_VASPRINTF int my_vasprintf(char * * buffer, const char * format, va_list argptr) { ssize_t size = MAX_STRING; ssize_t pSize; while(TRUE) { *buffer = allocMemory(size + 2); pSize = vsnprintf(*buffer, size + 1, format, argptr); #if defined(WIN_32) || defined(TRU64) if(pSize < 0) { freeMemory(*buffer); size = size + size / 2; continue; } #else if(pSize > size) { freeMemory(*buffer); size = pSize; continue; } #endif break; } return((int)pSize); } #endif /* ---------------------- Universal Unique ID version 1 and 3 ----------- */ #define UINT16 unsigned short #define UINT32 unsigned int typedef struct { UINT32 time_low; UINT16 time_mid; UINT16 time_hi_and_version; unsigned char clock_seq_hi_and_reserved; unsigned char clock_seq_low; unsigned char node[6]; } UUID; UINT16 clock_seq = 0; INT64 last_time = 0; char last_node[6]; #define OCT151582 0x01B21DD213814000LL int getUUID(UUID * uuid, char * node) { struct timeval tp; INT64 timestamp; UINT16 nodeID[3]; int uuid_version; gettimeofday(&tp, (struct timezone *)0); /* add UUID UTC offset Oct 15, 1582 */ timestamp = tp.tv_sec * (INT64)10000000 + tp.tv_usec * 10 + OCT151582; #ifdef WIN_32 if(timestamp <= last_time) timestamp = last_time + 1; #else if(timestamp < last_time) clock_seq++; if(timestamp == last_time) timestamp++; #endif if(last_time == 0) srandom((timestamp & 0xFFFFFFFF) + getpid()); last_time = timestamp; if(clock_seq == 0) clock_seq = random(); if(node != NULL && (memcmp(last_node, node, 6) != 0)) { clock_seq = random(); memcpy(last_node, node, 6); } if(node == NULL) { nodeID[0] = random(); nodeID[1] = random(); nodeID[2] = random(); uuid_version = 4; memcpy(uuid->node, (void *)nodeID, 6); } else { uuid_version = 1; /* least sign bit of first byte must be 0 on MACs and 1 on artifical generated node IDs */ memcpy(uuid->node, node, 6); } if(uuid_version == 4) { clock_seq = random(); uuid->time_low = random(); #ifdef WIN_32 uuid->time_low |= (random() << 16); #endif uuid->time_mid = random(); uuid->time_hi_and_version = random(); } else { uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF); uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF); uuid->time_hi_and_version = (unsigned short)(timestamp >> 48) ; } uuid->time_hi_and_version &= 0x0FFF; uuid->time_hi_and_version |= (uuid_version << 12); uuid->clock_seq_low = clock_seq & 0xFF; uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8; uuid->clock_seq_hi_and_reserved |= 0x80; return(1); } CELL * p_uuid(CELL * params) { UUID uuid; char * nodeMAC = NULL; size_t size; char str[38]; if(params != nilCell) { getStringSize(params, &nodeMAC, &size, TRUE); if(size < 6) nodeMAC = NULL; } getUUID(&uuid, nodeMAC); snprintf(str, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, uuid.clock_seq_hi_and_reserved, uuid.clock_seq_low, uuid.node[0], uuid.node[1], uuid.node[2], uuid.node[3], uuid.node[4], uuid.node[5]); return(stuffString(str)); } /* eof */