1 /* nl-filesys.c --- I/O process control, date/time - functions for newLISP
4 Copyright (C) 2008 Lutz Mueller
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #define FIONREAD I_NREAD
33 #include <sys/types.h>
37 #include <sys/ioctl.h>
40 int init_argv(char * ptr
, char *argv
[]);
44 int semctl(int semid
, int semnum
, int cmd
, ...);
49 char ** environ
= NULL
;
51 extern char ** environ
;
55 extern char ** environ
;
61 #define fgetc win32_fgetc
68 #define pclose _pclose
72 Set binary as default file mode for Windows.
73 See also http://www.mingw.org/MinGWiki/index.php/binary
75 unsigned int _CRT_fmode
= _O_BINARY
;
77 /* not needed with MinGW gcc 3.4.5
85 /* with MinGW gcc 3.4.5 not needed
86 int gettimeofday( struct timeval *tp, struct timezone *tzp );
89 int setenv (const char *name
, const char *value
, int replace
);
90 #ifdef USE_WIN_UTF16PATH
91 INT64
fileSizeW(WCHAR
* pathName
);
97 #include <sys/socket.h>
98 #define SOCKET_ERROR -1
99 #define INVALID_SOCKET -1
103 char * strptime(const char * str
, const char * fmt
, struct tm
* ttm
);
106 size_t calcDateValue(int year
, int month
, int day
, int hour
, int min
, int sec
);
108 extern STREAM readLineStream
;
109 extern FILE * IOchannel
;
111 CELL
* p_isFile(CELL
* params
) /* includes dev,socket,dir,file etc. */
115 getString(params
, &fileName
);
116 if(isFile(fileName
) == 0)
122 int isFile(char * fileName
)
124 struct stat fileInfo
;
127 #ifdef USE_WIN_UTF16PATH
128 return(stat_utf16(fileName
, &fileInfo
));
130 return(stat(fileName
, &fileInfo
));
134 CELL
* p_isDirectory(CELL
* params
)
138 getString(params
, &fileName
);
139 if(isDir(fileName
)) return(trueCell
);
144 int isDir(char * fileName
)
146 struct stat fileInfo
;
152 len
= strlen(fileName
);
153 slash
= *(fileName
+ len
- 1);
154 if(slash
== '\\' || slash
== '/')
155 *(fileName
+ len
- 1) = 0;
160 #ifdef USE_WIN_UTF16PATH
161 if(stat_utf16(fileName
, &fileInfo
) != 0)
163 if(stat(fileName
, &fileInfo
) != 0)
167 *(fileName
+ len
- 1) = slash
;
173 *(fileName
+ len
- 1) = slash
;
176 if(S_ISDIR(fileInfo
.st_mode
))
183 CELL
* p_open(CELL
* params
)
187 char * option
= NULL
;
190 params
= getString(params
, &fileName
);
191 params
= getString(params
, &accessMode
);
193 if(params
!= nilCell
)
194 getString(params
, &option
);
196 if( (handle
= openFile(fileName
, accessMode
, option
)) == (int)-1)
198 return(stuffInteger((UINT
)handle
));
201 CELL
* p_close(CELL
* params
)
205 getInteger(params
, &handle
);
206 if(handle
== 0) return(nilCell
);
207 if(handle
== printDevice
) printDevice
= 0;
208 if(close((int)handle
) == -1) return(nilCell
);
212 CELL
* p_readChar(CELL
* params
)
217 getInteger(params
, &handle
);
218 if(read((int)handle
, &chr
, 1) <= 0) return(nilCell
);
220 return(stuffInteger((UINT
)chr
));
224 CELL
* p_readBuffer(CELL
* params
)
228 ssize_t bytesRead
= 0;
236 params
= getInteger(params
, &handle
);
237 params
= getSymbol(params
, &readSptr
);
238 params
= getInteger(params
, (UINT
*)&size
);
240 if(isProtected(readSptr
->flags
))
241 return(errorProcExt2(ERR_SYMBOL_PROTECTED
, stuffSymbol(readSptr
)));
243 memset(&stream
, 0, sizeof(stream
));
245 if(params
== nilCell
)
247 openStrStream(&stream
, size
, 0);
249 if((bytesRead
= read(handle
, stream
.buffer
, size
)) == -1)
251 closeStrStream(&stream
);
257 getString(params
, &waitFor
);
258 openStrStream(&stream
, MAX_LINE
, 0);
259 length
= strlen(waitFor
);
260 while(bytesRead
< size
)
262 if(read(handle
, &chr
, 1) <= 0)
265 writeStreamChar(&stream
, chr
);
266 if(++bytesRead
< length
) continue;
267 if(strcmp(waitFor
, stream
.ptr
- length
) == 0)
277 deleteList((CELL
*)readSptr
->contents
);
278 readSptr
->contents
= (UINT
)nilCell
;
279 closeStrStream(&stream
);
283 strCell
= getCell(CELL_STRING
);
284 strCell
->aux
= bytesRead
+ 1;
285 stream
.buffer
= reallocMemory(stream
.buffer
, bytesRead
+1);
286 strCell
->contents
= (UINT
)stream
.buffer
;
288 deleteList((CELL
*)readSptr
->contents
);
289 readSptr
->contents
= (UINT
)strCell
;
292 return(stuffInteger(bytesRead
));
296 CELL
* p_readFile(CELL
* params
)
299 char * buffer
= NULL
;
303 params
= getString(params
, &fileName
);
304 if(my_strnicmp(fileName
, "http://", 7) == 0)
305 return(getPutPostDeleteUrl(fileName
, params
, HTTP_GET_URL
, 0));
307 if(my_strnicmp(fileName
, "file://", 7) == 0)
308 fileName
= fileName
+ 7;
310 if((size
= readFile(fileName
, &buffer
)) == -1)
313 cell
= getCell(CELL_STRING
);
314 cell
->aux
= size
+ 1;
315 cell
->contents
= (UINT
)buffer
;
320 /* allocate a buffer and reads a file into it */
321 ssize_t
readFile(char * fileName
, char * * buffer
)
325 struct stat fileInfo
;
327 #ifdef USE_WIN_UTF16PATH
328 if(stat_utf16(fileName
, &fileInfo
) != 0)
330 if(stat(fileName
, &fileInfo
) != 0)
334 size
= fileInfo
.st_size
;
336 if( (handle
= openFile(fileName
, "r", NULL
)) == (int)-1)
339 *buffer
= callocMemory(size
+1);
341 if(read(handle
, *buffer
, size
) == -1)
356 CELL
* p_writeChar(CELL
* params
)
363 params
= getInteger(params
, &handle
);
366 while(params
!= nilCell
)
368 params
= getInteger(params
, &data
);
369 chr
= (unsigned char)data
;
370 if(write((int)handle
, (void *)&chr
, 1) == -1)
375 return(stuffInteger(count
));
379 size_t appendCellString(CELL
* cell
, char * buffer
, size_t size
)
381 cell
->contents
= (UINT
)reallocMemory((char *)cell
->contents
, cell
->aux
+ size
);
382 memcpy((char *)cell
->contents
+ cell
->aux
- 1, buffer
, size
);
385 *((char *)cell
->contents
+ cell
->aux
- 1) = 0;
391 CELL
* p_writeBuffer(CELL
* params
)
394 ssize_t bytesWritten
;
400 CELL
* flagPtr
= NULL
;
402 cell
= evalCheckProtected(params
, &flagPtr
);
404 params
= params
->next
;
406 if(isNumber(cell
->type
))
408 getIntegerExt(cell
, &handle
, FALSE
);
411 else if(cell
->type
!= CELL_STRING
)
412 return(errorProc(ERR_NUMBER_OR_STRING_EXPECTED
));
414 strCell
= evaluateExpression(params
);
415 if(strCell
->type
== CELL_SYMBOL
)
417 writeSptr
= (SYMBOL
*)strCell
->contents
;
418 strCell
= (CELL
*)writeSptr
->contents
;
420 else if(strCell
->type
== CELL_DYN_SYMBOL
)
422 writeSptr
= getDynamicSymbol(strCell
);
423 strCell
= (CELL
*)writeSptr
->contents
;
426 if(strCell
->type
!= CELL_STRING
)
427 return(errorProcExt(ERR_STRING_EXPECTED
, params
));
429 if(params
->next
== nilCell
)
430 size
= strCell
->aux
- 1;
432 getInteger(params
->next
, (UINT
*)&size
);
434 buffer
= (char *)strCell
->contents
;
435 if(size
> (strCell
->aux
- 1)) size
= strCell
->aux
- 1;
439 if(flagPtr
) return(errorProcExt(ERR_SYMBOL_PROTECTED
, flagPtr
));
440 return(stuffInteger(appendCellString(cell
, buffer
, size
)));
443 if((bytesWritten
= write((int)handle
, buffer
, size
)) == (UINT
)-1)
446 return(stuffInteger(bytesWritten
));
450 CELL
* p_appendFile(CELL
* params
)
452 return(appendWriteFile(params
, "a"));
455 CELL
* p_writeFile(CELL
* params
)
457 return(appendWriteFile(params
, "w"));
461 CELL
* appendWriteFile(CELL
* params
, char * type
)
468 params
= getString(params
, &fileName
);
470 if(my_strnicmp(fileName
, "http://", 7) == 0)
471 return(getPutPostDeleteUrl(fileName
, params
,
472 (*type
== 'w') ? HTTP_PUT_URL
: HTTP_PUT_APPEND_URL
, 0));
474 if(my_strnicmp(fileName
, "file://", 7) == 0)
475 fileName
= fileName
+ 7;
477 getStringSize(params
, &buffer
, &size
, TRUE
);
479 if( (handle
= openFile(fileName
, type
, NULL
)) == (int)-1)
482 if(write((int)handle
, buffer
, size
) == -1)
487 return(stuffInteger(size
));
491 CELL
* p_writeLine(CELL
* params
)
495 CELL
* flagPtr
= NULL
;
498 if(params
->type
== CELL_NIL
)
499 buffer
= readLineStream
.buffer
;
501 params
= getStringSize(params
, &buffer
, &size
, TRUE
);
503 if(params
!= nilCell
)
505 params
= evalCheckProtected(params
, &flagPtr
);
506 if(isNumber(params
->type
))
508 getIntegerExt(params
, &handle
, FALSE
);
509 if(write((int)handle
, buffer
, strlen(buffer
)) == -1) return(nilCell
);
510 if(write((int)handle
, LINE_FEED
, strlen(LINE_FEED
)) == -1) return(nilCell
);
512 if(params
->type
== CELL_STRING
)
514 if(flagPtr
) return(errorProcExt(ERR_SYMBOL_PROTECTED
, flagPtr
));
515 appendCellString(params
, buffer
, size
);
516 appendCellString(params
, LINE_FEED
, strlen(LINE_FEED
));
521 varPrintf(OUT_DEVICE
, "%s", buffer
);
522 varPrintf(OUT_DEVICE
, LINE_FEED
);
525 return(stuffString(buffer
));
529 CELL
* p_seek(CELL
* params
)
540 params
= getInteger(params
, &handle
);
542 if(params
== nilCell
)
545 newPosition
= ftell(stdout
);
546 else if( (newPosition
= lseek(handle
, 0, SEEK_CUR
)) == -1)
552 getInteger64(params
, ¶mPosition
);
554 getInteger(params
, (UINT
*)¶mPosition
);
557 newPosition
= paramPosition
;
558 if(newPosition
== -1)
560 if( (newPosition
= lseek((int)handle
, 0, SEEK_END
)) == -1)
565 if( lseek((int)handle
, newPosition
, SEEK_SET
) == -1)
570 paramPosition
= newPosition
;
572 return(stuffInteger64(paramPosition
));
574 return(stuffInteger(paramPosition
));
579 char * readStreamLine(STREAM
* stream
, FILE * inStream
)
583 openStrStream(stream
, MAX_STRING
, 1);
589 while((chr
= fgetc(inStream
)) != EOF
)
591 if(chr
== '\n') break;
594 chr
= fgetc(inStream
);
595 if(chr
== '\n' || chr
== EOF
) break;
597 writeStreamChar(stream
, chr
);
600 } while (errno
== EINTR
);
603 if(chr
== EOF
&& stream
->position
== 0) return(NULL
);
604 return(stream
->buffer
);
608 CELL
* p_readLine(CELL
* params
)
616 if(params
!= nilCell
)
617 getInteger(params
, &handle
);
619 handle
= printDevice
;
623 if((line
= readStreamLine(&readLineStream
, IOchannel
)) == NULL
)
626 return(stuffString(line
));
629 openStrStream(&readLineStream
, MAX_STRING
, 1);
632 if((bytesRead
= read((int)handle
, &chr
, 1)) <= 0) break;
633 if(chr
== '\n') break;
636 if(read((int)handle
, &chr
, 1) < 0) break;
637 if(chr
== '\n') break;
639 writeStreamChar(&readLineStream
, chr
);
642 if(bytesRead
<= 0 && readLineStream
.position
== 0)
645 return(stuffString(readLineStream
.buffer
));;
649 CELL
* p_currentLine(CELL
* params
)
651 return(stuffString(readLineStream
.buffer
));
655 int openFile(char * fileName
, char * accessMode
, char * option
)
660 if(option
!= NULL
&& *option
== 'n')
661 blocking
= O_NONBLOCK
;
664 if(*accessMode
== 'r')
665 return(open(fileName
, O_RDONLY
| O_BINARY
| blocking
, 0));
667 else if(*accessMode
== 'w')
669 return(open( fileName
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, S_IREAD
| S_IWRITE
) );
671 return(open(fileName
,O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
| blocking
,
672 S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
)); /* rw-rw-rw */
675 else if(*accessMode
== 'u')
676 return(open(fileName
, O_RDWR
| O_BINARY
, 0));
678 else if(*accessMode
== 'a')
681 return(open(fileName
, O_RDWR
| O_APPEND
| O_BINARY
| O_CREAT
, S_IREAD
| S_IWRITE
));
683 return(open(fileName
, O_RDWR
| O_APPEND
| O_BINARY
| O_CREAT
,
684 S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
)); /* rw-rw-rw */
691 /* ------------------------- directory management ------------------------- */
693 CELL
* p_copyFile(CELL
* params
)
697 int fromHandle
, toHandle
;
698 unsigned char * copyBuffer
;
701 params
= getString(params
, &fromName
);
702 getString(params
, &toName
);
704 if((fromHandle
= openFile(fromName
, "read", NULL
)) < 0)
707 if((toHandle
= openFile(toName
,"write", NULL
)) < 0)
710 copyBuffer
= allocMemory(MAX_FILE_BUFFER
);
713 bytesRead
= read(fromHandle
, copyBuffer
, MAX_FILE_BUFFER
);
714 write(toHandle
, copyBuffer
, (int)bytesRead
);
715 } while (bytesRead
== MAX_FILE_BUFFER
);
719 close((int)fromHandle
);
720 close((int)toHandle
);
726 CELL
* p_renameFile(CELL
* params
)
731 params
= getString(params
, &oldName
);
732 getString(params
, &newName
);
733 return(rename(oldName
, newName
) == 0 ? trueCell
: nilCell
);
737 CELL
* p_deleteFile(CELL
* params
)
741 params
= getString(params
, &fileName
);
742 if(my_strnicmp(fileName
, "http://", 7) == 0)
743 return(getPutPostDeleteUrl(fileName
, params
, HTTP_DELETE_URL
, 0));
745 return(unlink(fileName
) == 0 ? trueCell
: nilCell
);
749 CELL
* p_makeDir(CELL
* params
)
755 params
= getString(params
, &dirString
);
756 if(params
!= nilCell
)
758 getInteger(params
, &inMode
);
762 mode
= 0777; /* drwxrwxrwx gets user masked to drwxr-xr-x on most UNIX */
765 return(mkdir(dirString
) == 0 ? trueCell
: nilCell
);
767 return(mkdir(dirString
, (mode_t
)mode
) == 0 ? trueCell
: nilCell
);
772 CELL
* p_removeDir(CELL
* params
)
776 getString(params
, &dirString
);
777 return(rmdir(dirString
) == 0 ? trueCell
: nilCell
);
781 CELL
* p_changeDir(CELL
* params
)
785 getString(params
, &newDir
);
786 return(chdir(newDir
) == 0 ? trueCell
: nilCell
);
789 CELL
* p_directory(CELL
* params
)
795 char * pattern
= NULL
;
798 struct dirent
* dEnt
;
800 if(params
!= nilCell
)
802 params
= getString(params
, &dirPath
);
803 if(params
!= nilCell
)
805 params
= getString(params
, &pattern
);
806 if(params
!= nilCell
)
807 getInteger(params
, &options
);
812 dirList
= getCell(CELL_EXPRESSION
);
815 dir
= opendir(dirPath
);
816 if(dir
== NULL
) return(nilCell
);
818 while((dEnt
= readdir(dir
)) != NULL
)
820 #ifdef USE_WIN_UTF16PATH
821 fileName
= utf16_to_utf8(dEnt
->d_name
);
823 fileName
= dEnt
->d_name
;
827 if(searchBufferRegex(fileName
, 0, pattern
, strlen(fileName
), options
, NULL
) == -1)
830 if(lastEntry
== NULL
)
832 lastEntry
= stuffString(fileName
);
833 dirList
->contents
= (UINT
)lastEntry
;
837 lastEntry
->next
= stuffString(fileName
);
838 lastEntry
= lastEntry
->next
;
840 #ifdef USE_WIN_UTF16PATH
849 #define DOT_PATH ".\000"
851 CELL
* p_realpath(CELL
* params
)
856 if(params
!= nilCell
)
857 getString(params
, &dir
);
860 if(realpath(dir
, path
) == NULL
)
863 return(stuffString(path
));
866 CELL
* p_fileInfo(CELL
* params
)
868 #ifdef USE_WIN_UTF16PATH
870 struct _stat fileInfo
;
873 struct stat fileInfo
;
878 #ifdef USE_WIN_UTF16PATH
880 params
= getString(params
, &utf8pathName
);
881 pathName
= utf8_to_utf16(utf8pathName
);
883 params
= getString(params
, &pathName
);
886 if(lstat(pathName
, &fileInfo
) != 0)
888 #ifdef USE_WIN_UTF16PATH
894 list
= stuffIntegerList(
896 (UINT
)fileInfo
.st_size
,
897 (UINT
)fileInfo
.st_mode
,
898 (UINT
)fileInfo
.st_rdev
,
899 (UINT
)fileInfo
.st_uid
,
900 (UINT
)fileInfo
.st_gid
,
901 (UINT
)fileInfo
.st_atime
,
902 (UINT
)fileInfo
.st_mtime
,
903 (UINT
)fileInfo
.st_ctime
908 ((CELL
*)list
->contents
)->type
= CELL_INT64
;
909 #ifdef USE_WIN_UTF16PATH
910 *(INT64
*)&((CELL
*)list
->contents
)->aux
= fileSizeW(pathName
);
912 *(INT64
*)&((CELL
*)list
->contents
)->aux
= fileSize(pathName
);
913 #endif /* UTF16PATH */
915 #endif /* NEWLISP64 */
917 #ifdef USE_WIN_UTF16PATH
921 if(params
!= nilCell
)
924 return(copyCell(implicitIndexList(list
, params
)));
931 INT64
fileSize(char * pathName
)
937 handle
= open(pathName
,O_RDONLY
| O_BINARY
| O_NONBLOCK
, 0);
939 handle
= open(pathName
,O_RDONLY
| O_BINARY
, 0);
941 size
= lseek(handle
, 0, SEEK_END
);
943 if(size
== -1) size
= 0;
949 /* ------------------------- processes and pipes ------------------------- */
952 CELL
* p_system(CELL
*params
)
955 getString(params
, &command
);
956 return(stuffInteger((UINT
)system(command
)));
960 CELL
* p_exec(CELL
* params
)
962 char * command
, * data
;
964 params
= getString(params
, &command
);
965 if(params
== nilCell
)
966 return(readProcess(command
));
968 getString(params
, &data
);
969 return(writeProcess(command
, data
));
973 CELL
* readProcess(char * command
)
982 if((handle
= popen(command
, "r")) == NULL
)
985 lineList
= getCell(CELL_EXPRESSION
);
986 while((line
= readStreamLine(&readLineStream
, handle
)) != NULL
)
990 lastLine
= stuffString(line
);
991 lineList
->contents
= (UINT
)lastLine
;
995 lastLine
->next
= stuffString(line
);
996 lastLine
= lastLine
->next
;
1005 CELL
* writeProcess(char * command
, char * data
)
1009 if((handle
= popen(command
, "w")) == NULL
)
1012 if(fwrite(data
, sizeof(char), strlen(data
), handle
) < strlen(data
))
1020 int init_argv(char * ptr
, char *argv
[])
1027 while(*ptr
== ' ') ++ptr
;
1028 if(*ptr
== 0) break;
1029 if(*ptr
== '\'' || *ptr
== '"')
1032 argv
[argc
++] = ++ptr
;
1033 while(*ptr
!= brkChr
&& *ptr
!= 0) ++ptr
;
1034 if(*ptr
== 0) break;
1040 argv
[argc
++] = ptr
++;
1041 while(*ptr
!= ' ' && *ptr
!= 0) ptr
++;
1042 if(*ptr
== 0) break;
1054 int winPipe(UINT
* inpipe
, UINT
* outpipe
);
1055 UINT
winPipedProcess(char * command
, int inpipe
, int outpipe
, int option
);
1056 CELL
* plainProcess(char * command
, size_t size
);
1058 CELL
* p_pipe(CELL
* params
)
1062 if(!winPipe(&hin
, &hout
)) /* see file win32-util.c */
1065 return(stuffIntegerList(2, hin
, hout
));
1069 CELL
* p_process(CELL
* params
)
1075 UINT inpipe
= 0, outpipe
= 0, option
= 1;
1077 params
= getStringSize(params
, &command
, &size
, TRUE
);
1078 if(params
!= nilCell
)
1080 params
= getInteger(params
, (UINT
*)&inpipe
);
1081 params
= getInteger(params
, (UINT
*)&outpipe
);
1082 if(params
!= nilCell
)
1083 getInteger(params
, (UINT
*)&option
);
1085 else return(plainProcess(command
, size
));
1087 result
= winPipedProcess(command
, (int)inpipe
, (int)outpipe
, (int)option
);
1089 if(!result
) return(nilCell
);
1091 return(stuffInteger(result
));
1094 CELL
* plainProcess(char * command
, size_t len
)
1100 cPtr
= callocMemory(len
+ 1);
1101 memcpy(cPtr
, command
, len
+ 1);
1105 for(idx
= 1; idx
< 5; idx
++)
1107 cPtr
= strchr(cPtr
, ' ');
1108 if(cPtr
== NULL
) break;
1109 while(*cPtr
== ' ') *cPtr
++ = 0;
1115 init_argv(cPtr
, argv
);
1117 idx
= spawnvp(P_NOWAIT
, argv
[0], (const char * const *)argv
);
1120 if(idx
== -1) return(nilCell
);
1122 return(stuffInteger(idx
));
1126 CELL
* p_destroyProcess(CELL
* params
)
1130 getInteger(params
, &pid
);
1132 if(TerminateProcess((HANDLE
)pid
, 0) == 0)
1139 #else /* not WIN_32 */
1141 CELL
* p_pipe(CELL
* params
)
1144 if(pipe(handles
) != 0)
1147 return(stuffIntegerList(2, (UINT
)handles
[0], (UINT
)handles
[1]));
1151 CELL
* p_process(CELL
* params
)
1156 UINT inpipe
= 0, outpipe
= 0, errpipe
= 0;
1160 params
= getStringSize(params
, &command
, &size
, TRUE
);
1161 cmd
= callocMemory(size
+ 1);
1162 memcpy(cmd
, command
, size
+ 1);
1164 #ifdef DEBUG_INIT_ARGV
1166 init_argv(cmd
, argv
);
1167 for(i
= 0; i
< 15; i
++)
1169 if(argv
[i
] == NULL
) break;
1170 printf("->%s<-\n", argv
[i
]);
1175 if(params
!= nilCell
)
1177 params
= getInteger(params
, (UINT
*)&inpipe
);
1178 params
= getInteger(params
, (UINT
*)&outpipe
);
1179 if(params
!= nilCell
)
1180 getInteger(params
, (UINT
*)&errpipe
);
1183 if((forkResult
= fork()) == -1)
1187 /* redirect stdin and stdout, stderr to pipe handles */
1190 close(STDIN_FILENO
);
1191 if(dup2((int)inpipe
, STDIN_FILENO
) == -1) exit(0);
1196 close(STDOUT_FILENO
);
1197 if(dup2((int)outpipe
, STDOUT_FILENO
) == -1) exit(0);
1199 if(dup2((int)outpipe
, STDERR_FILENO
) == -1) exit(0);
1200 close((int)outpipe
);
1204 close(STDERR_FILENO
);
1205 if(dup2((int)errpipe
, STDERR_FILENO
) == -1) exit(0);
1206 close((int)errpipe
);
1209 init_argv(cmd
, argv
);
1211 execve(argv
[0], argv
, environ
);
1215 return(stuffInteger(forkResult
));
1218 CELL
* p_fork(CELL
* params
)
1222 if((forkResult
= fork()) == -1)
1226 evaluateExpression(params
);
1230 return(stuffInteger(forkResult
));
1233 CELL
* p_destroyProcess(CELL
* params
)
1238 params
= getInteger(params
, &pid
);
1239 if(params
!= nilCell
)
1240 getInteger(params
, &sig
);
1244 if(kill(pid
, sig
) != 0)
1250 CELL
* p_waitpid(CELL
* params
)
1255 params
= getInteger(params
, (UINT
*)&pid
);
1256 if(params
!= nilCell
)
1257 getInteger(params
, (UINT
*)&options
);
1261 waitpid((int)pid
, &result
, (int)options
);
1263 return(stuffInteger(result
));
1268 /* ------------------------------ semaphores --------------------------------- */
1272 UINT
winCreateSemaphore(void);
1273 UINT
winWaitSemaphore(UINT hSemaphore
);
1274 UINT
winSignalSemaphore(UINT hSemaphore
, int count
);
1275 UINT
winDeleteSemaphore(UINT hSemaphore
);
1276 int getSemaphoreCount(UINT hSemaphore
);
1278 CELL
* p_semaphore(CELL
* params
)
1283 if(params
!= nilCell
)
1285 params
= getInteger(params
, &sem_id
);
1286 if(params
!= nilCell
)
1288 getInteger(params
,(UINT
*)&value
);
1291 if(!winDeleteSemaphore(sem_id
))
1296 /* wait or signal */
1299 if(winWaitSemaphore(sem_id
)) return(trueCell
);
1304 if(winSignalSemaphore(sem_id
, value
)) return(trueCell
);
1311 /* return semaphore value, not on Win32 ? */
1316 /* create semaphore */
1317 if((sem_id
= winCreateSemaphore()) == 0) return(nilCell
);
1318 return(stuffInteger(sem_id
));
1323 /* only available on Linux/UNIX */
1326 CELL
* p_semaphore(CELL
* params
)
1328 UINT sem_id
, value
= 0;
1329 struct sembuf sem_b
;
1341 if(params
!= nilCell
)
1343 params
= getInteger(params
, (UINT
*)&sem_id
);
1344 if(params
!= nilCell
)
1346 getInteger(params
,(UINT
*)&value
);
1349 /* remove semaphore */
1353 if(semctl(sem_id
, 0, IPC_RMID
, 0) == -1)
1356 if(semctl(sem_id
, 0, IPC_RMID
, &semun_val
) == -1)
1358 if(semctl(sem_id
, 0, IPC_RMID
, 0) == -1)
1360 #endif /* SOLARIS */
1365 if(semctl(sem_id
, 0, IPC_RMID
, semu
) == -1)
1367 if(semctl(sem_id
, 0, IPC_RMID
, 0) == -1)
1374 /* wait or signal */
1376 sem_b
.sem_op
= value
;
1378 if(semop(sem_id
, &sem_b
, 1) == -1)
1384 /* return semaphore value */
1386 return(stuffInteger(semctl(sem_id
, 0, GETVAL
, semu
)));
1388 return(stuffInteger(semctl(sem_id
, 0, GETVAL
)));
1392 /* create semaphore */
1393 sem_id
= semget(IPC_PRIVATE
, 1, 0666 );
1397 if(semctl(sem_id
, 0, SETVAL
, 0) == -1)
1400 if(semctl(sem_id
, 0, SETVAL
, &semun_val
) == -1)
1402 if(semctl(sem_id
, 0, SETVAL
, 0) == -1)
1409 if(semctl(sem_id
, 0, SETVAL
, semu
) == -1)
1411 if(semctl(sem_id
, 0, SETVAL
, 0) == -1)
1416 return(stuffInteger(sem_id
));
1419 #endif /* not WIN_32 */
1428 UINT
winSharedMemory(int size
);
1429 UINT
* winMapView(UINT handle
, int size
);
1433 CELL
* p_share(CELL
* params
)
1435 union num_ptr address
;
1439 static int pagesize
= 0;
1442 if(!pagesize
) pagesize
= getpagesize();
1448 if(params
!= nilCell
)
1450 cell
= evaluateExpression(params
);
1454 getInteger(params
->next
, &address
.num
);
1455 if(munmap((void *)address
.ptr
, pagesize
) == -1)
1457 else return(trueCell
);
1460 getIntegerExt(cell
, &address
.num
, FALSE
);
1461 params
= params
->next
;
1463 if((address
.ptr
= winMapView(address
.num
, pagesize
)) == NULL
)
1466 if(params
!= nilCell
) /* write to shared memory */
1468 cell
= evaluateExpression(params
);
1469 if(cell
->type
== CELL_NIL
)
1471 *address
.ptr
= CELL_NIL
;
1473 UnmapViewOfFile(address
.ptr
);
1477 if(cell
->type
== CELL_TRUE
)
1479 *address
.ptr
= CELL_TRUE
;
1481 UnmapViewOfFile(address
.ptr
);
1485 if(cell
->type
== CELL_STRING
)
1487 getStringSize(cell
, &str
, &size
, FALSE
);
1488 if(size
> (pagesize
- 2 * sizeof(long) - 1))
1489 size
= pagesize
- 2 * sizeof(long) - 1;
1490 *address
.ptr
= cell
->type
;
1491 *(address
.ptr
+ 1) = size
;
1492 memcpy((char *)(address
.num
+ 2 * sizeof(long)), str
, size
);
1493 *(char *)(address
.num
+ 2 * sizeof(long) + size
) = 0;
1494 /* fall thru to address.ptr == CELL_STRING, to return sized string */
1496 goto return_new_string_cell
;
1498 if(cell
->type
== CELL_LONG
)
1500 *address
.ptr
= cell
->type
;
1501 *(address
.ptr
+ 1) = sizeof(long);
1502 *(address
.ptr
+ 2) = cell
->contents
;
1504 UnmapViewOfFile(address
.ptr
);
1506 return(copyList(cell
));
1509 if(cell
->type
== CELL_INT64
)
1511 *address
.ptr
= cell
->type
;
1512 *(address
.ptr
+ 1) = sizeof(INT64
);
1513 memcpy(address
.ptr
+ 2, (void *)&cell
->aux
, sizeof(INT64
));
1515 UnmapViewOfFile(address
.ptr
);
1517 return(copyList(cell
));
1519 if(cell
->type
== CELL_FLOAT
)
1521 *address
.ptr
= cell
->type
;
1522 *(address
.ptr
+ 1) = sizeof(double);
1523 *(address
.ptr
+ 2) = cell
->aux
;
1524 *(address
.ptr
+ 3) = cell
->contents
;
1526 UnmapViewOfFile(address
.ptr
);
1528 return(copyList(cell
));
1531 #else /* NEWLISP64 */
1532 if(cell
->type
== CELL_FLOAT
)
1534 *address
.ptr
= cell
->type
;
1535 *(address
.ptr
+ 1) = sizeof(double);
1536 *(address
.ptr
+ 2) = cell
->contents
;
1537 return(copyList(cell
));
1539 #endif /* NEWLISP64 */
1540 return(errorProcExt(ERR_ILLEGAL_TYPE
, cell
));
1542 if(*address
.ptr
== CELL_NIL
) /* rrad from share memory */
1545 UnmapViewOfFile(address
.ptr
);
1549 if(*address
.ptr
== CELL_TRUE
)
1552 UnmapViewOfFile(address
.ptr
);
1556 if(*address
.ptr
== CELL_LONG
)
1558 cell
= stuffInteger(*(address
.ptr
+ 2));
1560 UnmapViewOfFile(address
.ptr
);
1565 if(*address
.ptr
== CELL_INT64
)
1567 cell
= stuffInteger64(*(INT64
*)(address
.ptr
+ 2));
1569 UnmapViewOfFile(address
.ptr
);
1575 if(*address
.ptr
== CELL_FLOAT
)
1578 cell
= getCell(CELL_FLOAT
);
1579 cell
->aux
= *(address
.ptr
+ 2);
1580 cell
->contents
= *(address
.ptr
+ 3);
1582 cell
= getCell(CELL_FLOAT
);
1583 cell
->contents
= *(address
.ptr
+ 2);
1586 UnmapViewOfFile(address
.ptr
);
1590 if(*address
.ptr
== CELL_STRING
)
1592 return_new_string_cell
:
1593 cell
= getCell(CELL_STRING
);
1594 cell
->aux
= *(address
.ptr
+ 1) + 1;
1595 cell
->contents
= (UINT
)allocMemory(cell
->aux
);
1596 memcpy((char *)cell
->contents
, (char*)(address
.num
+ 2 * sizeof(long)), cell
->aux
);
1598 UnmapViewOfFile(address
.ptr
);
1606 if((address
.ptr
= (UINT
*)mmap(
1607 0, pagesize
, PROT_READ
| PROT_WRITE
, MAP_SHARED
| MAP_ANON
, -1, 0)) == (void*)-1)
1610 memset((char *)address
.num
, 0, pagesize
);
1611 return(stuffInteger(address
.num
));
1614 if((handle
= winSharedMemory(pagesize
)) == 0)
1617 if((address
.ptr
= winMapView(handle
, pagesize
)) == NULL
)
1620 memset((char *)address
.num
, 0, pagesize
);
1621 return(stuffInteger(handle
));
1626 /* ------------------------------ time and date functions -------------------- */
1628 CELL
* p_systemInfo(CELL
* params
)
1632 cell
= stuffIntegerList(
1637 (UINT
)recursionCount
,
1639 (UINT
)MAX_CPU_STACK
,
1643 if(params
!= nilCell
)
1646 return(copyCell(implicitIndexList(cell
, params
)));
1653 CELL
* p_systemError(CELL
* params
)
1657 if(params
!= nilCell
)
1659 getInteger(params
, (UINT
*)&init
);
1663 return(stuffInteger((UINT
)errno
));
1667 CELL
* p_date(CELL
* params
)
1688 if(params
== nilCell
)
1690 gettimeofday(&tv
, NULL
);
1695 params
= getInteger(params
, (UINT
*)&tme
);
1698 if(params
!= nilCell
)
1700 params
= getInteger(params
, (UINT
*)&offset
);
1701 t
+= (int)offset
* 60;
1704 if(params
!= nilCell
)
1706 params
= getString(params
, &fmt
);
1707 ltm
= localtime(&t
);
1709 /* some Linux do UTF-8 but don't have wcsftime() or it is buggy */
1711 size
= utf8_wlen(fmt
);
1712 ufmt
= alloca(UTF8_MAX_BYTES
* (size
+ 1));
1713 utf8_wstr(ufmt
, fmt
, size
);
1715 timeString
= alloca(UTF8_MAX_BYTES
* 128);
1716 size
= wcsftime((wchar_t *)timeString
, 127, (wchar_t *)ufmt
, ltm
);
1717 utf8str
= alloca(size
* UTF8_MAX_BYTES
+ 1);
1718 size
= wstr_utf8(utf8str
, timeString
, size
* UTF8_MAX_BYTES
);
1719 return(stuffString(utf8str
));
1721 utf8str
= alloca(128);
1722 strftime(utf8str
, 127, fmt
, ltm
);
1723 return(stuffString(utf8str
));
1724 #endif /* WCSFTIME */
1727 timeString
= alloca(128);
1728 strftime(timeString
, 127, fmt
, ltm
);
1729 return(stuffString(timeString
));
1735 if(ct
== NULL
) return(nilCell
);
1737 ct
[strlen(ct
) - 1] = 0; /* supress linefeed */
1738 return(stuffString(ct
));
1742 int milliSecTime(void)
1747 gettimeofday(&tv
, NULL
);
1749 ttm
= localtime((time_t *)&tv
.tv_sec
);
1751 return (ttm
->tm_hour
* 3600000 +
1752 ttm
->tm_min
* 60000 + ttm
->tm_sec
* 1000 +
1757 /* returns a differerence of 2 timeval structs in milliseconds
1759 int timediff(struct timeval out
, struct timeval in
)
1761 if( (out
.tv_usec
-= in
.tv_usec
) < 0 ) {
1763 out
.tv_usec
+= 1000000;
1765 out
.tv_sec
-= in
.tv_sec
;
1767 return(out
.tv_sec
*1000 + (out
.tv_usec
/1000));
1770 UINT64
timediff64(struct timeval out
, struct timeval in
)
1772 if( (out
.tv_usec
-= in
.tv_usec
) < 0 ) {
1774 out
.tv_usec
+= 1000000;
1776 out
.tv_sec
-= in
.tv_sec
;
1778 return(out
.tv_sec
*1000000 + out
.tv_usec
);
1782 CELL
* p_parseDate(CELL
* params
)
1789 params
= getString(params
, &dateStr
);
1790 params
= getString(params
, &formatStr
);
1792 memset (&ttm
, 0, sizeof (ttm
));
1794 if(strptime(dateStr
, formatStr
, &ttm
) == NULL
)
1797 dateValue
= calcDateValue(
1805 return(stuffInteger(dateValue
));
1809 CELL
* p_time(CELL
* params
)
1811 struct timeval start
, end
;
1815 gettimeofday(&start
, NULL
);
1816 if(params
->next
!= nilCell
)
1817 getInteger64(params
->next
, &N
);
1819 resultIdxSave
= resultStackIdx
;
1822 evaluateExpression(params
);
1823 cleanupResults(resultIdxSave
);
1826 gettimeofday(&end
, NULL
);
1827 return(stuffInteger((UINT
)timediff(end
, start
)));
1831 CELL
* p_timeOfDay(CELL
* params
)
1833 return(stuffInteger(milliSecTime()));
1836 CELL
* p_now(CELL
* params
)
1841 struct timezone tzp
;
1844 gettimeofday(&tv
, &tzp
);
1846 if(params
!= nilCell
)
1848 getInteger(params
, (UINT
*)&offset
);
1850 tv
.tv_sec
+= offset
;
1853 ltm
= localtime((time_t *)&tv
.tv_sec
);
1855 ttm
= gmtime((time_t *)&tv
.tv_sec
);
1857 return(stuffIntegerList(
1859 (UINT
)ttm
->tm_year
+ 1900,
1860 (UINT
)ttm
->tm_mon
+ 1,
1866 (UINT
)ttm
->tm_yday
+ 1,
1867 (UINT
)ttm
->tm_wday
+ 1,
1868 /* Note, that on SOLARIS tzp.tz_minuteswest and
1869 tzp.tz_dsttime might not work correctly
1872 (UINT
)tzp
.tz_minuteswest
,
1874 /* (UINT)ltm->tm_isdst */
1875 (UINT
)tzp
.tz_dsttime
1887 gettimeofday(&tv
, NULL
);
1892 CELL
* p_dateValue(CELL
* params
)
1895 ssize_t year
, month
, day
, hour
, min
, sec
;
1898 if(params
->type
== CELL_NIL
)
1900 gettimeofday(&tv
, NULL
);
1901 return(stuffInteger(tv
.tv_sec
));
1904 params
= getInteger(params
, (UINT
*)&year
);
1905 params
= getInteger(params
, (UINT
*)&month
);
1906 params
= getInteger(params
, (UINT
*)&day
);
1908 if(year
< 1970) return(stuffInteger(0));
1910 hour
= min
= sec
= 0;
1911 if(params
!= nilCell
)
1913 params
= getInteger(params
, (UINT
*)&hour
);
1914 params
= getInteger(params
, (UINT
*)&min
);
1915 getInteger(params
, (UINT
*)&sec
);
1918 dateValue
= calcDateValue(year
, month
, day
, hour
, min
, sec
);
1920 return(stuffInteger((UINT
)dateValue
));
1924 size_t calcDateValue(int year
, int month
, int day
, int hour
, int min
, int sec
)
1928 dateValue
= 367 * year
- (7 * (year
+ ((month
+ 9) / 12)))/4
1929 + (275 * month
)/9 + day
+ 1721013;
1931 dateValue
= dateValue
* 24 * 3600 + hour
* 3600 + min
* 60 + sec
1932 - 413319296; /* correction for 1970-1-1 */
1935 dateValue
= dateValue
% 0x80000000;
1943 extern int nanosleep();
1946 void mySleep(int ms
)
1951 tm
.tv_sec
= ms
/ 1000;
1952 tm
.tv_nsec
= (ms
- tm
.tv_sec
* 1000) * 1000000;
1958 /* _sleep() is deprecated in MinGW gcc 3.4.5 */
1961 sleep((ms
+ 500)/1000);
1968 CELL
* p_sleep(CELL
* params
)
1972 getInteger(params
, (UINT
*)&milliSecs
);
1976 return(stuffInteger((UINT
)milliSecs
));
1979 /* -------------------------------- environment functions ------------------- */
1982 CELL
* p_env(CELL
* params
)
1987 /* no parameters returns whole environment */
1988 if(params
== nilCell
)
1989 return(environment());
1991 /* one parameter get environment for one variable */
1992 params
= getString(params
, &varName
);
1993 if(params
== nilCell
)
1995 if( (varValue
= getenv(varName
)) == NULL
)
1997 return(stuffString(varValue
));
2000 /* two parameters sets environment for one variable */
2001 getString(params
, &varValue
);
2007 if(setenv(varName
, varValue
, 1) != 0)
2015 int my_setenv(const char * varName
, const char * varValue
, int flag
)
2018 envstr
= alloca(strlen(varName
) + strlen(varValue
) + 2);
2019 strcpy(envstr
, varName
);
2020 strcat(envstr
, "=");
2021 strcat(envstr
, varValue
);
2022 return(putenv(envstr
));
2027 CELL
* environment(void)
2034 envList
= getCell(CELL_EXPRESSION
);
2046 if(lastEntry
== NULL
)
2048 lastEntry
= stuffString(*env
);
2049 envList
->contents
= (UINT
)lastEntry
;
2053 lastEntry
->next
= stuffString(*env
);
2054 lastEntry
= lastEntry
->next
;
2062 /* --------------------- read the keyboard -----------------------------------*/
2064 /* thanks to Peter van Eerten for contributing this function */
2065 CELL
* p_readKey(CELL
* params
)
2068 return(stuffInteger(getch()));
2071 return(stuffInteger(getch()));
2074 struct termios term
, oterm
;
2077 tcgetattr(0, &oterm
);
2079 memcpy(&term
, &oterm
, sizeof(term
));
2081 /* put the terminal in non-canonical mode, any
2082 reads timeout after 0.1 seconds or when a
2083 single character is read */
2084 term
.c_lflag
&= ~(ICANON
| ECHO
);
2085 term
.c_cc
[VMIN
] = 0;
2086 term
.c_cc
[VTIME
] = 1;
2087 tcsetattr(0, TCSANOW
, &term
);
2089 #if defined (_BSD) || (MAC_OSX)
2090 while(read(0, &c
, 1) == 0);
2092 while((c
= (char)getchar()) == (char)-1);
2095 /* reset the terminal to original state */
2096 tcsetattr(0, TCSANOW
, &oterm
);
2098 return(stuffInteger(c
));
2103 /* --------------------- peek a file descriptor ------------------------------*/
2105 CELL
* p_peek(CELL
* params
)
2109 unsigned long result
;
2114 getInteger(params
, &handle
);
2116 if(ioctl((int)handle
, FIONREAD
, &result
) < 0)
2119 return(stuffInteger((UINT
)result
));
2124 /* --------------------- library functions not found on some OSs -------------*/
2128 int my_vasprintf(char * * buffer
, const char * format
, va_list argptr
)
2130 ssize_t size
= MAX_STRING
;
2135 *buffer
= allocMemory(size
+ 2);
2136 pSize
= vsnprintf(*buffer
, size
+ 1, format
, argptr
);
2138 #if defined(WIN_32) || defined(TRU64)
2141 freeMemory(*buffer
);
2142 size
= size
+ size
/ 2;
2148 freeMemory(*buffer
);
2161 /* ---------------------- Universal Unique ID version 1 and 3 ----------- */
2163 #define UINT16 unsigned short
2164 #define UINT32 unsigned int
2170 UINT16 time_hi_and_version
;
2171 unsigned char clock_seq_hi_and_reserved
;
2172 unsigned char clock_seq_low
;
2173 unsigned char node
[6];
2176 UINT16 clock_seq
= 0;
2177 INT64 last_time
= 0;
2180 #define OCT151582 0x01B21DD213814000LL
2182 int getUUID(UUID
* uuid
, char * node
)
2189 gettimeofday(&tp
, (struct timezone
*)0);
2191 /* add UUID UTC offset Oct 15, 1582 */
2192 timestamp
= tp
.tv_sec
* (INT64
)10000000 + tp
.tv_usec
* 10 + OCT151582
;
2195 if(timestamp
<= last_time
) timestamp
= last_time
+ 1;
2197 if(timestamp
< last_time
) clock_seq
++;
2198 if(timestamp
== last_time
) timestamp
++;
2202 srandom((timestamp
& 0xFFFFFFFF) + getpid());
2204 last_time
= timestamp
;
2207 if(clock_seq
== 0) clock_seq
= random();
2208 if(node
!= NULL
&& (memcmp(last_node
, node
, 6) != 0))
2210 clock_seq
= random();
2211 memcpy(last_node
, node
, 6);
2216 nodeID
[0] = random();
2217 nodeID
[1] = random();
2218 nodeID
[2] = random();
2220 memcpy(uuid
->node
, (void *)nodeID
, 6);
2225 /* least sign bit of first byte must be 0 on MACs
2226 and 1 on artifical generated node IDs */
2227 memcpy(uuid
->node
, node
, 6);
2230 if(uuid_version
== 4)
2232 clock_seq
= random();
2233 uuid
->time_low
= random();
2235 uuid
->time_low
|= (random() << 16);
2237 uuid
->time_mid
= random();
2238 uuid
->time_hi_and_version
= random();
2242 uuid
->time_low
= (unsigned long)(timestamp
& 0xFFFFFFFF);
2243 uuid
->time_mid
= (unsigned short)((timestamp
>> 32) & 0xFFFF);
2244 uuid
->time_hi_and_version
= (unsigned short)(timestamp
>> 48) ;
2247 uuid
->time_hi_and_version
&= 0x0FFF;
2248 uuid
->time_hi_and_version
|= (uuid_version
<< 12);
2249 uuid
->clock_seq_low
= clock_seq
& 0xFF;
2250 uuid
->clock_seq_hi_and_reserved
= (clock_seq
& 0x3F00) >> 8;
2251 uuid
->clock_seq_hi_and_reserved
|= 0x80;
2256 CELL
* p_uuid(CELL
* params
)
2259 char * nodeMAC
= NULL
;
2263 if(params
!= nilCell
)
2265 getStringSize(params
, &nodeMAC
, &size
, TRUE
);
2266 if(size
< 6) nodeMAC
= NULL
;
2269 getUUID(&uuid
, nodeMAC
);
2271 snprintf(str
, 37, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2272 uuid
.time_low
, uuid
.time_mid
, uuid
.time_hi_and_version
,
2273 uuid
.clock_seq_hi_and_reserved
, uuid
.clock_seq_low
,
2274 uuid
.node
[0], uuid
.node
[1], uuid
.node
[2],
2275 uuid
.node
[3], uuid
.node
[4], uuid
.node
[5]);
2277 return(stuffString(str
));