stream.c revision f765521f
15dfecf96Smrg/* 25dfecf96Smrg * Copyright (c) 2001 by The XFree86 Project, Inc. 35dfecf96Smrg * 45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a 55dfecf96Smrg * copy of this software and associated documentation files (the "Software"), 65dfecf96Smrg * to deal in the Software without restriction, including without limitation 75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the 95dfecf96Smrg * Software is furnished to do so, subject to the following conditions: 105dfecf96Smrg * 115dfecf96Smrg * The above copyright notice and this permission notice shall be included in 125dfecf96Smrg * all copies or substantial portions of the Software. 135dfecf96Smrg * 145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 205dfecf96Smrg * SOFTWARE. 215dfecf96Smrg * 225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall 235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other 245dfecf96Smrg * dealings in this Software without prior written authorization from the 255dfecf96Smrg * XFree86 Project. 265dfecf96Smrg * 275dfecf96Smrg * Author: Paulo César Pereira de Andrade 285dfecf96Smrg */ 295dfecf96Smrg 305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/stream.c,v 1.21tsi Exp $ */ 315dfecf96Smrg 325dfecf96Smrg#include "lisp/read.h" 335dfecf96Smrg#include "lisp/stream.h" 345dfecf96Smrg#include "lisp/pathname.h" 355dfecf96Smrg#include "lisp/write.h" 365dfecf96Smrg#include "lisp/private.h" 375dfecf96Smrg#include <errno.h> 385dfecf96Smrg#include <fcntl.h> 395dfecf96Smrg#include <signal.h> 405dfecf96Smrg#include <string.h> 415dfecf96Smrg#include <sys/wait.h> 425dfecf96Smrg 435dfecf96Smrg/* 445dfecf96Smrg * Initialization 455dfecf96Smrg */ 465dfecf96Smrg#define DIR_PROBE 0 475dfecf96Smrg#define DIR_INPUT 1 485dfecf96Smrg#define DIR_OUTPUT 2 495dfecf96Smrg#define DIR_IO 3 505dfecf96Smrg 515dfecf96Smrg#define EXT_NIL 0 525dfecf96Smrg#define EXT_ERROR 1 535dfecf96Smrg#define EXT_NEW_VERSION 2 545dfecf96Smrg#define EXT_RENAME 3 555dfecf96Smrg#define EXT_RENAME_DELETE 4 565dfecf96Smrg#define EXT_OVERWRITE 5 575dfecf96Smrg#define EXT_APPEND 6 585dfecf96Smrg#define EXT_SUPERSEDE 7 595dfecf96Smrg 605dfecf96Smrg#define NOEXT_NIL 0 615dfecf96Smrg#define NOEXT_ERROR 1 625dfecf96Smrg#define NOEXT_CREATE 2 635dfecf96Smrg#define NOEXT_NOTHING 3 645dfecf96Smrg 655dfecf96Smrgextern char **environ; 665dfecf96Smrg 675dfecf96SmrgLispObj *Oopen, *Oclose, *Otruename; 685dfecf96Smrg 695dfecf96SmrgLispObj *Kif_does_not_exist, *Kprobe, *Kinput, *Koutput, *Kio, 705dfecf96Smrg *Knew_version, *Krename, *Krename_and_delete, *Koverwrite, 715dfecf96Smrg *Kappend, *Ksupersede, *Kcreate; 725dfecf96Smrg 735dfecf96Smrg/* 745dfecf96Smrg * Implementation 755dfecf96Smrg */ 765dfecf96Smrgvoid 775dfecf96SmrgLispStreamInit(void) 785dfecf96Smrg{ 795dfecf96Smrg Oopen = STATIC_ATOM("OPEN"); 805dfecf96Smrg Oclose = STATIC_ATOM("CLOSE"); 815dfecf96Smrg Otruename = STATIC_ATOM("TRUENAME"); 825dfecf96Smrg 835dfecf96Smrg Kif_does_not_exist = KEYWORD("IF-DOES-NOT-EXIST"); 845dfecf96Smrg Kprobe = KEYWORD("PROBE"); 855dfecf96Smrg Kinput = KEYWORD("INPUT"); 865dfecf96Smrg Koutput = KEYWORD("OUTPUT"); 875dfecf96Smrg Kio = KEYWORD("IO"); 885dfecf96Smrg Knew_version = KEYWORD("NEW-VERSION"); 895dfecf96Smrg Krename = KEYWORD("RENAME"); 905dfecf96Smrg Krename_and_delete = KEYWORD("RENAME-AND-DELETE"); 915dfecf96Smrg Koverwrite = KEYWORD("OVERWRITE"); 925dfecf96Smrg Kappend = KEYWORD("APPEND"); 935dfecf96Smrg Ksupersede = KEYWORD("SUPERSEDE"); 945dfecf96Smrg Kcreate = KEYWORD("CREATE"); 955dfecf96Smrg} 965dfecf96Smrg 975dfecf96SmrgLispObj * 985dfecf96SmrgLisp_DeleteFile(LispBuiltin *builtin) 995dfecf96Smrg/* 1005dfecf96Smrg delete-file filename 1015dfecf96Smrg */ 1025dfecf96Smrg{ 1035dfecf96Smrg GC_ENTER(); 1045dfecf96Smrg LispObj *filename; 1055dfecf96Smrg 1065dfecf96Smrg filename = ARGUMENT(0); 1075dfecf96Smrg 1085dfecf96Smrg if (STRINGP(filename)) { 1095dfecf96Smrg filename = APPLY1(Oparse_namestring, filename); 1105dfecf96Smrg GC_PROTECT(filename); 1115dfecf96Smrg } 1125dfecf96Smrg else if (STREAMP(filename)) { 1135dfecf96Smrg if (filename->data.stream.type != LispStreamFile) 1145dfecf96Smrg LispDestroy("%s: %s is not a FILE-STREAM", 1155dfecf96Smrg STRFUN(builtin), STROBJ(filename)); 1165dfecf96Smrg filename = filename->data.stream.pathname; 1175dfecf96Smrg } 1185dfecf96Smrg else { 1195dfecf96Smrg CHECK_PATHNAME(filename); 1205dfecf96Smrg } 1215dfecf96Smrg GC_LEAVE(); 1225dfecf96Smrg 1235dfecf96Smrg return (LispUnlink(THESTR(CAR(filename->data.pathname))) ? NIL : T); 1245dfecf96Smrg} 1255dfecf96Smrg 1265dfecf96SmrgLispObj * 1275dfecf96SmrgLisp_RenameFile(LispBuiltin *builtin) 1285dfecf96Smrg/* 1295dfecf96Smrg rename-file filename new-name 1305dfecf96Smrg */ 1315dfecf96Smrg{ 1325dfecf96Smrg int code; 1335dfecf96Smrg GC_ENTER(); 1345dfecf96Smrg char *from, *to; 1355dfecf96Smrg LispObj *old_truename, *new_truename; 1365dfecf96Smrg 1375dfecf96Smrg LispObj *filename, *new_name; 1385dfecf96Smrg 1395dfecf96Smrg new_name = ARGUMENT(1); 1405dfecf96Smrg filename = ARGUMENT(0); 1415dfecf96Smrg 1425dfecf96Smrg if (STRINGP(filename)) { 1435dfecf96Smrg filename = APPLY1(Oparse_namestring, filename); 1445dfecf96Smrg GC_PROTECT(filename); 1455dfecf96Smrg } 1465dfecf96Smrg else if (STREAMP(filename)) { 1475dfecf96Smrg if (filename->data.stream.type != LispStreamFile) 1485dfecf96Smrg LispDestroy("%s: %s is not a FILE-STREAM", 1495dfecf96Smrg STRFUN(builtin), STROBJ(filename)); 1505dfecf96Smrg filename = filename->data.stream.pathname; 1515dfecf96Smrg } 1525dfecf96Smrg else { 1535dfecf96Smrg CHECK_PATHNAME(filename); 1545dfecf96Smrg } 1555dfecf96Smrg old_truename = APPLY1(Otruename, filename); 1565dfecf96Smrg GC_PROTECT(old_truename); 1575dfecf96Smrg 1585dfecf96Smrg if (STRINGP(new_name)) { 1595dfecf96Smrg new_name = APPLY3(Oparse_namestring, new_name, NIL, filename); 1605dfecf96Smrg GC_PROTECT(new_name); 1615dfecf96Smrg } 1625dfecf96Smrg else { 1635dfecf96Smrg CHECK_PATHNAME(new_name); 1645dfecf96Smrg } 1655dfecf96Smrg 1665dfecf96Smrg from = THESTR(CAR(filename->data.pathname)); 1675dfecf96Smrg to = THESTR(CAR(new_name->data.pathname)); 1685dfecf96Smrg code = LispRename(from, to); 1695dfecf96Smrg if (code) 1705dfecf96Smrg LispDestroy("%s: rename(%s, %s): %s", 1715dfecf96Smrg STRFUN(builtin), from, to, strerror(errno)); 1725dfecf96Smrg GC_LEAVE(); 1735dfecf96Smrg 1745dfecf96Smrg new_truename = APPLY1(Otruename, new_name); 1755dfecf96Smrg RETURN_COUNT = 2; 1765dfecf96Smrg RETURN(0) = old_truename; 1775dfecf96Smrg RETURN(1) = new_truename; 1785dfecf96Smrg 1795dfecf96Smrg return (new_name); 1805dfecf96Smrg} 1815dfecf96Smrg 1825dfecf96SmrgLispObj * 1835dfecf96SmrgLisp_Streamp(LispBuiltin *builtin) 1845dfecf96Smrg/* 1855dfecf96Smrg streamp object 1865dfecf96Smrg */ 1875dfecf96Smrg{ 1885dfecf96Smrg LispObj *object; 1895dfecf96Smrg 1905dfecf96Smrg object = ARGUMENT(0); 1915dfecf96Smrg 1925dfecf96Smrg return (STREAMP(object) ? T : NIL); 1935dfecf96Smrg} 1945dfecf96Smrg 1955dfecf96SmrgLispObj * 1965dfecf96SmrgLisp_InputStreamP(LispBuiltin *builtin) 1975dfecf96Smrg/* 1985dfecf96Smrg input-stream-p stream 1995dfecf96Smrg */ 2005dfecf96Smrg{ 2015dfecf96Smrg LispObj *stream; 2025dfecf96Smrg 2035dfecf96Smrg stream = ARGUMENT(0); 2045dfecf96Smrg 2055dfecf96Smrg CHECK_STREAM(stream); 2065dfecf96Smrg 2075dfecf96Smrg return (stream->data.stream.readable ? T : NIL); 2085dfecf96Smrg} 2095dfecf96Smrg 2105dfecf96SmrgLispObj * 2115dfecf96SmrgLisp_OpenStreamP(LispBuiltin *builtin) 2125dfecf96Smrg/* 2135dfecf96Smrg open-stream-p stream 2145dfecf96Smrg */ 2155dfecf96Smrg{ 2165dfecf96Smrg LispObj *stream; 2175dfecf96Smrg 2185dfecf96Smrg stream = ARGUMENT(0); 2195dfecf96Smrg 2205dfecf96Smrg CHECK_STREAM(stream); 2215dfecf96Smrg 2225dfecf96Smrg return (stream->data.stream.readable || stream->data.stream.writable ? 2235dfecf96Smrg T : NIL); 2245dfecf96Smrg} 2255dfecf96Smrg 2265dfecf96SmrgLispObj * 2275dfecf96SmrgLisp_OutputStreamP(LispBuiltin *builtin) 2285dfecf96Smrg/* 2295dfecf96Smrg output-stream-p stream 2305dfecf96Smrg */ 2315dfecf96Smrg{ 2325dfecf96Smrg LispObj *stream; 2335dfecf96Smrg 2345dfecf96Smrg stream = ARGUMENT(0); 2355dfecf96Smrg 2365dfecf96Smrg CHECK_STREAM(stream); 2375dfecf96Smrg 2385dfecf96Smrg return (stream->data.stream.writable ? T : NIL); 2395dfecf96Smrg} 2405dfecf96Smrg 2415dfecf96SmrgLispObj * 2425dfecf96SmrgLisp_Open(LispBuiltin *builtin) 2435dfecf96Smrg/* 2445dfecf96Smrg open filename &key direction element-type if-exists if-does-not-exist external-format 2455dfecf96Smrg */ 2465dfecf96Smrg{ 2475dfecf96Smrg GC_ENTER(); 2485dfecf96Smrg char *string; 2495dfecf96Smrg LispObj *stream = NIL; 2505dfecf96Smrg int mode, flags, direction, exist, noexist, file_exist; 2515dfecf96Smrg LispFile *file; 2525dfecf96Smrg 2535dfecf96Smrg LispObj *filename, *odirection, *element_type, *if_exists, 2545dfecf96Smrg *if_does_not_exist, *external_format; 2555dfecf96Smrg 2565dfecf96Smrg external_format = ARGUMENT(5); 2575dfecf96Smrg if_does_not_exist = ARGUMENT(4); 2585dfecf96Smrg if_exists = ARGUMENT(3); 2595dfecf96Smrg element_type = ARGUMENT(2); 2605dfecf96Smrg odirection = ARGUMENT(1); 2615dfecf96Smrg filename = ARGUMENT(0); 2625dfecf96Smrg 2635dfecf96Smrg if (STRINGP(filename)) { 2645dfecf96Smrg filename = APPLY1(Oparse_namestring, filename); 2655dfecf96Smrg GC_PROTECT(filename); 2665dfecf96Smrg } 2675dfecf96Smrg else if (STREAMP(filename)) { 2685dfecf96Smrg if (filename->data.stream.type != LispStreamFile) 2695dfecf96Smrg LispDestroy("%s: %s is not a FILE-STREAM", 2705dfecf96Smrg STRFUN(builtin), STROBJ(filename)); 2715dfecf96Smrg filename = filename->data.stream.pathname; 2725dfecf96Smrg } 2735dfecf96Smrg else { 2745dfecf96Smrg CHECK_PATHNAME(filename); 2755dfecf96Smrg } 2765dfecf96Smrg 2775dfecf96Smrg if (odirection != UNSPEC) { 2785dfecf96Smrg direction = -1; 2795dfecf96Smrg if (KEYWORDP(odirection)) { 2805dfecf96Smrg if (odirection == Kprobe) 2815dfecf96Smrg direction = DIR_PROBE; 2825dfecf96Smrg else if (odirection == Kinput) 2835dfecf96Smrg direction = DIR_INPUT; 2845dfecf96Smrg else if (odirection == Koutput) 2855dfecf96Smrg direction = DIR_OUTPUT; 2865dfecf96Smrg else if (odirection == Kio) 2875dfecf96Smrg direction = DIR_IO; 2885dfecf96Smrg } 2895dfecf96Smrg if (direction == -1) 2905dfecf96Smrg LispDestroy("%s: bad :DIRECTION %s", 2915dfecf96Smrg STRFUN(builtin), STROBJ(odirection)); 2925dfecf96Smrg } 2935dfecf96Smrg else 2945dfecf96Smrg direction = DIR_INPUT; 2955dfecf96Smrg 2965dfecf96Smrg if (element_type != UNSPEC) { 2975dfecf96Smrg /* just check argument... */ 2985dfecf96Smrg if (SYMBOLP(element_type) && 2995dfecf96Smrg ATOMID(element_type) == Scharacter) 3005dfecf96Smrg ; /* do nothing */ 3015dfecf96Smrg else if (KEYWORDP(element_type) && 3025dfecf96Smrg ATOMID(element_type) == Sdefault) 3035dfecf96Smrg ; /* do nothing */ 3045dfecf96Smrg else 3055dfecf96Smrg LispDestroy("%s: only :%s and %s supported for :ELEMENT-TYPE, not %s", 306f14f4646Smrg STRFUN(builtin), Sdefault->value, Scharacter->value, STROBJ(element_type)); 3075dfecf96Smrg } 3085dfecf96Smrg 3095dfecf96Smrg if (if_exists != UNSPEC) { 3105dfecf96Smrg exist = -1; 3115dfecf96Smrg if (if_exists == NIL) 3125dfecf96Smrg exist = EXT_NIL; 3135dfecf96Smrg else if (KEYWORDP(if_exists)) { 3145dfecf96Smrg if (if_exists == Kerror) 3155dfecf96Smrg exist = EXT_ERROR; 3165dfecf96Smrg else if (if_exists == Knew_version) 3175dfecf96Smrg exist = EXT_NEW_VERSION; 3185dfecf96Smrg else if (if_exists == Krename) 3195dfecf96Smrg exist = EXT_RENAME; 3205dfecf96Smrg else if (if_exists == Krename_and_delete) 3215dfecf96Smrg exist = EXT_RENAME_DELETE; 3225dfecf96Smrg else if (if_exists == Koverwrite) 3235dfecf96Smrg exist = EXT_OVERWRITE; 3245dfecf96Smrg else if (if_exists == Kappend) 3255dfecf96Smrg exist = EXT_APPEND; 3265dfecf96Smrg else if (if_exists == Ksupersede) 3275dfecf96Smrg exist = EXT_SUPERSEDE; 3285dfecf96Smrg } 3295dfecf96Smrg if (exist == -1) 3305dfecf96Smrg LispDestroy("%s: bad :IF-EXISTS %s", 3315dfecf96Smrg STRFUN(builtin), STROBJ(if_exists)); 3325dfecf96Smrg } 3335dfecf96Smrg else 3345dfecf96Smrg exist = EXT_ERROR; 3355dfecf96Smrg 3365dfecf96Smrg if (if_does_not_exist != UNSPEC) { 3375dfecf96Smrg noexist = -1; 3385dfecf96Smrg if (if_does_not_exist == NIL) 3395dfecf96Smrg noexist = NOEXT_NIL; 3405dfecf96Smrg if (KEYWORDP(if_does_not_exist)) { 3415dfecf96Smrg if (if_does_not_exist == Kerror) 3425dfecf96Smrg noexist = NOEXT_ERROR; 3435dfecf96Smrg else if (if_does_not_exist == Kcreate) 3445dfecf96Smrg noexist = NOEXT_CREATE; 3455dfecf96Smrg } 3465dfecf96Smrg if (noexist == -1) 3475dfecf96Smrg LispDestroy("%s: bad :IF-DOES-NO-EXISTS %s", 3485dfecf96Smrg STRFUN(builtin), STROBJ(if_does_not_exist)); 3495dfecf96Smrg } 3505dfecf96Smrg else 3515dfecf96Smrg noexist = direction != DIR_INPUT ? NOEXT_NOTHING : NOEXT_ERROR; 3525dfecf96Smrg 3535dfecf96Smrg if (external_format != UNSPEC) { 3545dfecf96Smrg /* just check argument... */ 3555dfecf96Smrg if (SYMBOLP(external_format) && 3565dfecf96Smrg ATOMID(external_format) == Scharacter) 3575dfecf96Smrg ; /* do nothing */ 3585dfecf96Smrg else if (KEYWORDP(external_format) && 3595dfecf96Smrg ATOMID(external_format) == Sdefault) 3605dfecf96Smrg ; /* do nothing */ 3615dfecf96Smrg else 3625dfecf96Smrg LispDestroy("%s: only :%s and %s supported for :EXTERNAL-FORMAT, not %s", 363f14f4646Smrg STRFUN(builtin), Sdefault->value, Scharacter->value, STROBJ(external_format)); 3645dfecf96Smrg } 3655dfecf96Smrg 3665dfecf96Smrg /* string representation of pathname */ 3675dfecf96Smrg string = THESTR(CAR(filename->data.pathname)); 3685dfecf96Smrg mode = 0; 3695dfecf96Smrg 3705dfecf96Smrg file_exist = access(string, F_OK) == 0; 3715dfecf96Smrg if (file_exist) { 3725dfecf96Smrg if (exist == EXT_NIL) { 3735dfecf96Smrg GC_LEAVE(); 3745dfecf96Smrg return (NIL); 3755dfecf96Smrg } 3765dfecf96Smrg } 3775dfecf96Smrg else { 3785dfecf96Smrg if (noexist == NOEXT_NIL) { 3795dfecf96Smrg GC_LEAVE(); 3805dfecf96Smrg return (NIL); 3815dfecf96Smrg } 3825dfecf96Smrg if (noexist == NOEXT_ERROR) 3835dfecf96Smrg LispDestroy("%s: file %s does not exist", 3845dfecf96Smrg STRFUN(builtin), STROBJ(CAR(filename->data.quote))); 3855dfecf96Smrg else if (noexist == NOEXT_CREATE) { 3865dfecf96Smrg LispFile *tmp = LispFopen(string, FILE_WRITE); 3875dfecf96Smrg 3885dfecf96Smrg if (tmp) 3895dfecf96Smrg LispFclose(tmp); 3905dfecf96Smrg else 3915dfecf96Smrg LispDestroy("%s: cannot create file %s", 3925dfecf96Smrg STRFUN(builtin), 3935dfecf96Smrg STROBJ(CAR(filename->data.quote))); 3945dfecf96Smrg } 3955dfecf96Smrg } 3965dfecf96Smrg 3975dfecf96Smrg if (direction == DIR_OUTPUT || direction == DIR_IO) { 3985dfecf96Smrg if (file_exist) { 3995dfecf96Smrg if (exist == EXT_ERROR) 4005dfecf96Smrg LispDestroy("%s: file %s already exists", 4015dfecf96Smrg STRFUN(builtin), STROBJ(CAR(filename->data.quote))); 4025dfecf96Smrg if (exist == EXT_RENAME) { 4035dfecf96Smrg /* Add an ending '~' at the end of the backup file */ 4045dfecf96Smrg char tmp[PATH_MAX + 1]; 4055dfecf96Smrg 4065dfecf96Smrg strcpy(tmp, string); 4075dfecf96Smrg if (strlen(tmp) + 1 > PATH_MAX) 4085dfecf96Smrg LispDestroy("%s: backup name for %s too long", 4095dfecf96Smrg STRFUN(builtin), 4105dfecf96Smrg STROBJ(CAR(filename->data.quote))); 4115dfecf96Smrg strcat(tmp, "~"); 4125dfecf96Smrg if (rename(string, tmp)) 4135dfecf96Smrg LispDestroy("%s: rename: %s", 4145dfecf96Smrg STRFUN(builtin), strerror(errno)); 4155dfecf96Smrg mode |= FILE_WRITE; 4165dfecf96Smrg } 4175dfecf96Smrg else if (exist == EXT_OVERWRITE) 4185dfecf96Smrg mode |= FILE_WRITE; 4195dfecf96Smrg else if (exist == EXT_APPEND) 4205dfecf96Smrg mode |= FILE_APPEND; 4215dfecf96Smrg } 4225dfecf96Smrg else 4235dfecf96Smrg mode |= FILE_WRITE; 4245dfecf96Smrg if (direction == DIR_IO) 4255dfecf96Smrg mode |= FILE_IO; 4265dfecf96Smrg } 4275dfecf96Smrg else 4285dfecf96Smrg mode |= FILE_READ; 4295dfecf96Smrg 4305dfecf96Smrg file = LispFopen(string, mode); 4315dfecf96Smrg if (file == NULL) 4325dfecf96Smrg LispDestroy("%s: open: %s", STRFUN(builtin), strerror(errno)); 4335dfecf96Smrg 4345dfecf96Smrg flags = 0; 4355dfecf96Smrg if (direction == DIR_PROBE) { 4365dfecf96Smrg LispFclose(file); 4375dfecf96Smrg file = NULL; 4385dfecf96Smrg } 4395dfecf96Smrg else { 4405dfecf96Smrg if (direction == DIR_INPUT || direction == DIR_IO) 4415dfecf96Smrg flags |= STREAM_READ; 4425dfecf96Smrg if (direction == DIR_OUTPUT || direction == DIR_IO) 4435dfecf96Smrg flags |= STREAM_WRITE; 4445dfecf96Smrg } 4455dfecf96Smrg stream = FILESTREAM(file, filename, flags); 4465dfecf96Smrg GC_LEAVE(); 4475dfecf96Smrg 4485dfecf96Smrg return (stream); 4495dfecf96Smrg} 4505dfecf96Smrg 4515dfecf96SmrgLispObj * 4525dfecf96SmrgLisp_Close(LispBuiltin *builtin) 4535dfecf96Smrg/* 4545dfecf96Smrg close stream &key abort 4555dfecf96Smrg */ 4565dfecf96Smrg{ 4575dfecf96Smrg LispObj *stream, *oabort; 4585dfecf96Smrg 4595dfecf96Smrg oabort = ARGUMENT(1); 4605dfecf96Smrg stream = ARGUMENT(0); 4615dfecf96Smrg 4625dfecf96Smrg CHECK_STREAM(stream); 4635dfecf96Smrg 4645dfecf96Smrg if (stream->data.stream.readable || stream->data.stream.writable) { 4655dfecf96Smrg stream->data.stream.readable = stream->data.stream.writable = 0; 4665dfecf96Smrg if (stream->data.stream.type == LispStreamFile) { 4675dfecf96Smrg LispFclose(stream->data.stream.source.file); 4685dfecf96Smrg stream->data.stream.source.file = NULL; 4695dfecf96Smrg } 4705dfecf96Smrg else if (stream->data.stream.type == LispStreamPipe) { 4715dfecf96Smrg if (IPSTREAMP(stream)) { 4725dfecf96Smrg LispFclose(IPSTREAMP(stream)); 4735dfecf96Smrg IPSTREAMP(stream) = NULL; 4745dfecf96Smrg } 4755dfecf96Smrg if (OPSTREAMP(stream)) { 4765dfecf96Smrg LispFclose(OPSTREAMP(stream)); 4775dfecf96Smrg OPSTREAMP(stream) = NULL; 4785dfecf96Smrg } 4795dfecf96Smrg if (EPSTREAMP(stream)) { 4805dfecf96Smrg LispFclose(EPSTREAMP(stream)); 4815dfecf96Smrg EPSTREAMP(stream) = NULL; 4825dfecf96Smrg } 4835dfecf96Smrg if (PIDPSTREAMP(stream) > 0) { 4845dfecf96Smrg kill(PIDPSTREAMP(stream), 4855dfecf96Smrg oabort == UNSPEC || oabort == NIL ? SIGTERM : SIGKILL); 4865dfecf96Smrg waitpid(PIDPSTREAMP(stream), NULL, 0); 4875dfecf96Smrg } 4885dfecf96Smrg } 4895dfecf96Smrg return (T); 4905dfecf96Smrg } 4915dfecf96Smrg 4925dfecf96Smrg return (NIL); 4935dfecf96Smrg} 4945dfecf96Smrg 4955dfecf96SmrgLispObj * 4965dfecf96SmrgLisp_Listen(LispBuiltin *builtin) 4975dfecf96Smrg/* 4985dfecf96Smrg listen &optional input-stream 4995dfecf96Smrg */ 5005dfecf96Smrg{ 5015dfecf96Smrg LispFile *file = NULL; 5025dfecf96Smrg LispObj *result = NIL; 5035dfecf96Smrg 5045dfecf96Smrg LispObj *stream; 5055dfecf96Smrg 5065dfecf96Smrg stream = ARGUMENT(0); 5075dfecf96Smrg 5085dfecf96Smrg if (stream == UNSPEC) 5095dfecf96Smrg stream = NIL; 5105dfecf96Smrg else if (stream != NIL) { 5115dfecf96Smrg CHECK_STREAM(stream); 5125dfecf96Smrg } 5135dfecf96Smrg else 5145dfecf96Smrg stream = lisp__data.standard_input; 5155dfecf96Smrg 5165dfecf96Smrg if (stream->data.stream.readable) { 5175dfecf96Smrg switch (stream->data.stream.type) { 5185dfecf96Smrg case LispStreamString: 5195dfecf96Smrg if (SSTREAMP(stream)->input < SSTREAMP(stream)->length) 5205dfecf96Smrg result = T; 5215dfecf96Smrg break; 5225dfecf96Smrg case LispStreamFile: 5235dfecf96Smrg file = FSTREAMP(stream); 5245dfecf96Smrg break; 5255dfecf96Smrg case LispStreamStandard: 5265dfecf96Smrg file = FSTREAMP(stream); 5275dfecf96Smrg break; 5285dfecf96Smrg case LispStreamPipe: 5295dfecf96Smrg file = IPSTREAMP(stream); 5305dfecf96Smrg break; 5315dfecf96Smrg } 5325dfecf96Smrg 5335dfecf96Smrg if (file != NULL) { 5345dfecf96Smrg if (file->available || file->offset < file->length) 5355dfecf96Smrg result = T; 5365dfecf96Smrg else { 5375dfecf96Smrg unsigned char c; 5385dfecf96Smrg 5395dfecf96Smrg if (!file->nonblock) { 5405dfecf96Smrg if (fcntl(file->descriptor, F_SETFL, O_NONBLOCK) < 0) 5415dfecf96Smrg LispDestroy("%s: fcntl: %s", 5425dfecf96Smrg STRFUN(builtin), strerror(errno)); 5435dfecf96Smrg file->nonblock = 1; 5445dfecf96Smrg } 5455dfecf96Smrg if (read(file->descriptor, &c, 1) == 1) { 5465dfecf96Smrg LispFungetc(file, c); 5475dfecf96Smrg result = T; 5485dfecf96Smrg } 5495dfecf96Smrg } 5505dfecf96Smrg } 5515dfecf96Smrg } 5525dfecf96Smrg 5535dfecf96Smrg return (result); 5545dfecf96Smrg} 5555dfecf96Smrg 5565dfecf96SmrgLispObj * 5575dfecf96SmrgLisp_MakeStringInputStream(LispBuiltin *builtin) 5585dfecf96Smrg/* 5595dfecf96Smrg make-string-input-stream string &optional start end 5605dfecf96Smrg */ 5615dfecf96Smrg{ 5625dfecf96Smrg char *string; 5635dfecf96Smrg long start, end, length; 5645dfecf96Smrg 5655dfecf96Smrg LispObj *ostring, *ostart, *oend, *result; 5665dfecf96Smrg 5675dfecf96Smrg oend = ARGUMENT(2); 5685dfecf96Smrg ostart = ARGUMENT(1); 5695dfecf96Smrg ostring = ARGUMENT(0); 5705dfecf96Smrg 5715dfecf96Smrg start = end = 0; 5725dfecf96Smrg CHECK_STRING(ostring); 5735dfecf96Smrg LispCheckSequenceStartEnd(builtin, ostring, ostart, oend, 5745dfecf96Smrg &start, &end, &length); 5755dfecf96Smrg string = THESTR(ostring); 5765dfecf96Smrg 5775dfecf96Smrg if (end - start != length) 5785dfecf96Smrg length = end - start; 5795dfecf96Smrg result = LSTRINGSTREAM(string + start, STREAM_READ, length); 5805dfecf96Smrg 5815dfecf96Smrg return (result); 5825dfecf96Smrg} 5835dfecf96Smrg 5845dfecf96SmrgLispObj * 5855dfecf96SmrgLisp_MakeStringOutputStream(LispBuiltin *builtin) 5865dfecf96Smrg/* 5875dfecf96Smrg make-string-output-stream &key element-type 5885dfecf96Smrg */ 5895dfecf96Smrg{ 5905dfecf96Smrg LispObj *element_type; 5915dfecf96Smrg 5925dfecf96Smrg element_type = ARGUMENT(0); 5935dfecf96Smrg 5945dfecf96Smrg if (element_type != UNSPEC) { 5955dfecf96Smrg /* just check argument... */ 5965dfecf96Smrg if (SYMBOLP(element_type) && ATOMID(element_type) == Scharacter) 5975dfecf96Smrg ; /* do nothing */ 5985dfecf96Smrg else if (KEYWORDP(element_type) && 5995dfecf96Smrg ATOMID(element_type) == Sdefault) 6005dfecf96Smrg ; /* do nothing */ 6015dfecf96Smrg else 6025dfecf96Smrg LispDestroy("%s: only :%s and %s supported for :ELEMENT-TYPE, not %s", 603f14f4646Smrg STRFUN(builtin), Sdefault->value, Scharacter->value, STROBJ(element_type)); 6045dfecf96Smrg } 6055dfecf96Smrg 6065dfecf96Smrg return (LSTRINGSTREAM("", STREAM_WRITE, 1)); 6075dfecf96Smrg} 6085dfecf96Smrg 6095dfecf96SmrgLispObj * 6105dfecf96SmrgLisp_GetOutputStreamString(LispBuiltin *builtin) 6115dfecf96Smrg/* 6125dfecf96Smrg get-output-stream-string string-output-stream 6135dfecf96Smrg */ 6145dfecf96Smrg{ 6155dfecf96Smrg int length; 616f765521fSmrg const char *string; 6175dfecf96Smrg LispObj *string_output_stream, *result; 6185dfecf96Smrg 6195dfecf96Smrg string_output_stream = ARGUMENT(0); 6205dfecf96Smrg 6215dfecf96Smrg if (!STREAMP(string_output_stream) || 6225dfecf96Smrg string_output_stream->data.stream.type != LispStreamString || 6235dfecf96Smrg string_output_stream->data.stream.readable || 6245dfecf96Smrg !string_output_stream->data.stream.writable) 6255dfecf96Smrg LispDestroy("%s: %s is not an output string stream", 6265dfecf96Smrg STRFUN(builtin), STROBJ(string_output_stream)); 6275dfecf96Smrg 6285dfecf96Smrg string = LispGetSstring(SSTREAMP(string_output_stream), &length); 6295dfecf96Smrg result = LSTRING(string, length); 6305dfecf96Smrg 6315dfecf96Smrg /* reset string */ 6325dfecf96Smrg SSTREAMP(string_output_stream)->output = 6335dfecf96Smrg SSTREAMP(string_output_stream)->length = 6345dfecf96Smrg SSTREAMP(string_output_stream)->column = 0; 6355dfecf96Smrg 6365dfecf96Smrg return (result); 6375dfecf96Smrg} 6385dfecf96Smrg 6395dfecf96Smrg 6405dfecf96Smrg/* XXX Non standard functions below 6415dfecf96Smrg */ 6425dfecf96SmrgLispObj * 6435dfecf96SmrgLisp_MakePipe(LispBuiltin *builtin) 6445dfecf96Smrg/* 6455dfecf96Smrg make-pipe command-line &key :direction :element-type :external-format 6465dfecf96Smrg */ 6475dfecf96Smrg{ 6485dfecf96Smrg char *string; 6495dfecf96Smrg LispObj *stream = NIL; 6505dfecf96Smrg int flags, direction; 6515dfecf96Smrg LispFile *error_file; 6525dfecf96Smrg LispPipe *program; 6535dfecf96Smrg int ifd[2]; 6545dfecf96Smrg int ofd[2]; 6555dfecf96Smrg int efd[2]; 6565dfecf96Smrg char *argv[4]; 6575dfecf96Smrg 6585dfecf96Smrg LispObj *command_line, *odirection, *element_type, *external_format; 6595dfecf96Smrg 6605dfecf96Smrg external_format = ARGUMENT(3); 6615dfecf96Smrg element_type = ARGUMENT(2); 6625dfecf96Smrg odirection = ARGUMENT(1); 6635dfecf96Smrg command_line = ARGUMENT(0); 6645dfecf96Smrg 6655dfecf96Smrg if (PATHNAMEP(command_line)) 6665dfecf96Smrg command_line = CAR(command_line->data.quote); 6675dfecf96Smrg else if (!STRINGP(command_line)) 6685dfecf96Smrg LispDestroy("%s: %s is a bad pathname", 6695dfecf96Smrg STRFUN(builtin), STROBJ(command_line)); 6705dfecf96Smrg 6715dfecf96Smrg if (odirection != UNSPEC) { 6725dfecf96Smrg direction = -1; 6735dfecf96Smrg if (KEYWORDP(odirection)) { 6745dfecf96Smrg if (odirection == Kprobe) 6755dfecf96Smrg direction = DIR_PROBE; 6765dfecf96Smrg else if (odirection == Kinput) 6775dfecf96Smrg direction = DIR_INPUT; 6785dfecf96Smrg else if (odirection == Koutput) 6795dfecf96Smrg direction = DIR_OUTPUT; 6805dfecf96Smrg else if (odirection == Kio) 6815dfecf96Smrg direction = DIR_IO; 6825dfecf96Smrg } 6835dfecf96Smrg if (direction == -1) 6845dfecf96Smrg LispDestroy("%s: bad :DIRECTION %s", 6855dfecf96Smrg STRFUN(builtin), STROBJ(odirection)); 6865dfecf96Smrg } 6875dfecf96Smrg else 6885dfecf96Smrg direction = DIR_INPUT; 6895dfecf96Smrg 6905dfecf96Smrg if (element_type != UNSPEC) { 6915dfecf96Smrg /* just check argument... */ 6925dfecf96Smrg if (SYMBOLP(element_type) && ATOMID(element_type) == Scharacter) 6935dfecf96Smrg ; /* do nothing */ 6945dfecf96Smrg else if (KEYWORDP(element_type) && ATOMID(element_type) == Sdefault) 6955dfecf96Smrg ; /* do nothing */ 6965dfecf96Smrg else 6975dfecf96Smrg LispDestroy("%s: only :%s and %s supported for :ELEMENT-TYPE, not %s", 698f14f4646Smrg STRFUN(builtin), Sdefault->value, Scharacter->value, STROBJ(element_type)); 6995dfecf96Smrg } 7005dfecf96Smrg 7015dfecf96Smrg if (external_format != UNSPEC) { 7025dfecf96Smrg /* just check argument... */ 7035dfecf96Smrg if (SYMBOLP(external_format) && ATOMID(external_format) == Scharacter) 7045dfecf96Smrg ; /* do nothing */ 7055dfecf96Smrg else if (KEYWORDP(external_format) && 7065dfecf96Smrg ATOMID(external_format) == Sdefault) 7075dfecf96Smrg ; /* do nothing */ 7085dfecf96Smrg else 7095dfecf96Smrg LispDestroy("%s: only :%s and %s supported for :EXTERNAL-FORMAT, not %s", 710f14f4646Smrg STRFUN(builtin), Sdefault->value, Scharacter->value, STROBJ(external_format)); 7115dfecf96Smrg } 7125dfecf96Smrg 7135dfecf96Smrg string = THESTR(command_line); 7145dfecf96Smrg program = LispMalloc(sizeof(LispPipe)); 7155dfecf96Smrg if (direction != DIR_PROBE) { 7165dfecf96Smrg argv[0] = "sh"; 7175dfecf96Smrg argv[1] = "-c"; 7185dfecf96Smrg argv[2] = string; 7195dfecf96Smrg argv[3] = NULL; 7205dfecf96Smrg pipe(ifd); 7215dfecf96Smrg pipe(ofd); 7225dfecf96Smrg pipe(efd); 7235dfecf96Smrg if ((program->pid = fork()) == 0) { 7245dfecf96Smrg close(0); 7255dfecf96Smrg close(1); 7265dfecf96Smrg close(2); 7275dfecf96Smrg dup2(ofd[0], 0); 7285dfecf96Smrg dup2(ifd[1], 1); 7295dfecf96Smrg dup2(efd[1], 2); 7305dfecf96Smrg close(ifd[0]); 7315dfecf96Smrg close(ifd[1]); 7325dfecf96Smrg close(ofd[0]); 7335dfecf96Smrg close(ofd[1]); 7345dfecf96Smrg close(efd[0]); 7355dfecf96Smrg close(efd[1]); 7365dfecf96Smrg execve("/bin/sh", argv, environ); 7375dfecf96Smrg exit(-1); 7385dfecf96Smrg } 7395dfecf96Smrg else if (program->pid < 0) 7405dfecf96Smrg LispDestroy("%s: fork: %s", STRFUN(builtin), strerror(errno)); 7415dfecf96Smrg 7425dfecf96Smrg program->input = LispFdopen(ifd[0], FILE_READ | FILE_UNBUFFERED); 7435dfecf96Smrg close(ifd[1]); 7445dfecf96Smrg program->output = LispFdopen(ofd[1], FILE_WRITE | FILE_UNBUFFERED); 7455dfecf96Smrg close(ofd[0]); 7465dfecf96Smrg error_file = LispFdopen(efd[0], FILE_READ | FILE_UNBUFFERED); 7475dfecf96Smrg close(efd[1]); 7485dfecf96Smrg } 7495dfecf96Smrg else { 7505dfecf96Smrg program->pid = -1; 7515dfecf96Smrg program->input = program->output = error_file = NULL; 7525dfecf96Smrg } 7535dfecf96Smrg 7545dfecf96Smrg flags = direction == DIR_PROBE ? 0 : STREAM_READ; 7555dfecf96Smrg program->errorp = FILESTREAM(error_file, command_line, flags); 7565dfecf96Smrg 7575dfecf96Smrg flags = 0; 7585dfecf96Smrg if (direction != DIR_PROBE) { 7595dfecf96Smrg if (direction == DIR_INPUT || direction == DIR_IO) 7605dfecf96Smrg flags |= STREAM_READ; 7615dfecf96Smrg if (direction == DIR_OUTPUT || direction == DIR_IO) 7625dfecf96Smrg flags |= STREAM_WRITE; 7635dfecf96Smrg } 7645dfecf96Smrg stream = PIPESTREAM(program, command_line, flags); 7655dfecf96Smrg LispMused(program); 7665dfecf96Smrg 7675dfecf96Smrg return (stream); 7685dfecf96Smrg} 7695dfecf96Smrg 7705dfecf96Smrg/* Helper function, primarily for use with the xt module 7715dfecf96Smrg */ 7725dfecf96SmrgLispObj * 7735dfecf96SmrgLisp_PipeBroken(LispBuiltin *builtin) 7745dfecf96Smrg/* 7755dfecf96Smrg pipe-broken pipe-stream 7765dfecf96Smrg */ 7775dfecf96Smrg{ 7785dfecf96Smrg int pid, status, retval; 7795dfecf96Smrg LispObj *result = NIL; 7805dfecf96Smrg 7815dfecf96Smrg LispObj *pipe_stream; 7825dfecf96Smrg 7835dfecf96Smrg pipe_stream = ARGUMENT(0); 7845dfecf96Smrg 7855dfecf96Smrg if (!STREAMP(pipe_stream) || 7865dfecf96Smrg pipe_stream->data.stream.type != LispStreamPipe) 7875dfecf96Smrg LispDestroy("%s: %s is not a pipe stream", 7885dfecf96Smrg STRFUN(builtin), STROBJ(pipe_stream)); 7895dfecf96Smrg 7905dfecf96Smrg if ((pid = PIDPSTREAMP(pipe_stream)) > 0) { 7915dfecf96Smrg retval = waitpid(pid, &status, WNOHANG | WUNTRACED); 7925dfecf96Smrg if (retval == pid || (retval == -1 && errno == ECHILD)) 7935dfecf96Smrg result = T; 7945dfecf96Smrg } 7955dfecf96Smrg 7965dfecf96Smrg return (result); 7975dfecf96Smrg} 7985dfecf96Smrg 7995dfecf96Smrg/* 8005dfecf96Smrg Helper function, so that it is not required to redirect error output 8015dfecf96Smrg */ 8025dfecf96SmrgLispObj * 8035dfecf96SmrgLisp_PipeErrorStream(LispBuiltin *builtin) 8045dfecf96Smrg/* 8055dfecf96Smrg pipe-error-stream pipe-stream 8065dfecf96Smrg */ 8075dfecf96Smrg{ 8085dfecf96Smrg LispObj *pipe_stream; 8095dfecf96Smrg 8105dfecf96Smrg pipe_stream = ARGUMENT(0); 8115dfecf96Smrg 8125dfecf96Smrg if (!STREAMP(pipe_stream) || 8135dfecf96Smrg pipe_stream->data.stream.type != LispStreamPipe) 8145dfecf96Smrg LispDestroy("%s: %s is not a pipe stream", 8155dfecf96Smrg STRFUN(builtin), STROBJ(pipe_stream)); 8165dfecf96Smrg 8175dfecf96Smrg return (pipe_stream->data.stream.source.program->errorp); 8185dfecf96Smrg} 8195dfecf96Smrg 8205dfecf96Smrg/* 8215dfecf96Smrg Helper function, primarily for use with the xt module 8225dfecf96Smrg */ 8235dfecf96SmrgLispObj * 8245dfecf96SmrgLisp_PipeInputDescriptor(LispBuiltin *builtin) 8255dfecf96Smrg/* 8265dfecf96Smrg pipe-input-descriptor pipe-stream 8275dfecf96Smrg */ 8285dfecf96Smrg{ 8295dfecf96Smrg LispObj *pipe_stream; 8305dfecf96Smrg 8315dfecf96Smrg pipe_stream = ARGUMENT(0); 8325dfecf96Smrg 8335dfecf96Smrg if (!STREAMP(pipe_stream) || 8345dfecf96Smrg pipe_stream->data.stream.type != LispStreamPipe) 8355dfecf96Smrg LispDestroy("%s: %s is not a pipe stream", 8365dfecf96Smrg STRFUN(builtin), STROBJ(pipe_stream)); 8375dfecf96Smrg if (!IPSTREAMP(pipe_stream)) 8385dfecf96Smrg LispDestroy("%s: pipe %s is unreadable", 8395dfecf96Smrg STRFUN(builtin), STROBJ(pipe_stream)); 8405dfecf96Smrg 8415dfecf96Smrg return (INTEGER(LispFileno(IPSTREAMP(pipe_stream)))); 8425dfecf96Smrg} 8435dfecf96Smrg 8445dfecf96Smrg/* 8455dfecf96Smrg Helper function, primarily for use with the xt module 8465dfecf96Smrg */ 8475dfecf96SmrgLispObj * 8485dfecf96SmrgLisp_PipeErrorDescriptor(LispBuiltin *builtin) 8495dfecf96Smrg/* 8505dfecf96Smrg pipe-error-descriptor pipe-stream 8515dfecf96Smrg */ 8525dfecf96Smrg{ 8535dfecf96Smrg LispObj *pipe_stream; 8545dfecf96Smrg 8555dfecf96Smrg pipe_stream = ARGUMENT(0); 8565dfecf96Smrg 8575dfecf96Smrg if (!STREAMP(pipe_stream) || 8585dfecf96Smrg pipe_stream->data.stream.type != LispStreamPipe) 8595dfecf96Smrg LispDestroy("%s: %s is not a pipe stream", 8605dfecf96Smrg STRFUN(builtin), STROBJ(pipe_stream)); 8615dfecf96Smrg if (!EPSTREAMP(pipe_stream)) 8625dfecf96Smrg LispDestroy("%s: pipe %s is closed", 8635dfecf96Smrg STRFUN(builtin), STROBJ(pipe_stream)); 8645dfecf96Smrg 8655dfecf96Smrg return (INTEGER(LispFileno(EPSTREAMP(pipe_stream)))); 8665dfecf96Smrg} 867