From 515981b679935d7789277caa95e916e66f3e035d Mon Sep 17 00:00:00 2001 From: vike Date: Thu, 11 Jul 2024 16:43:52 +0200 Subject: [PATCH 01/21] adding custom *pfe* --- .gitignore | 3 + CHANGES | 4 + custom/Makefile | 8 +- custom/custtbl.c | 71 +++ custom/pfe | 91 +++ custom/pfe.cal | 199 +++++++ custom/u_pfe.c | 1378 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1750 insertions(+), 4 deletions(-) create mode 100755 custom/pfe create mode 100644 custom/pfe.cal create mode 100644 custom/u_pfe.c diff --git a/.gitignore b/.gitignore index 2b38e890e..03afefaa7 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ cal/test082.cal charbit.h chatbit chk_c +.cache/clangd conf.h const_tmp cscript/4dsphere @@ -53,6 +54,8 @@ cscript/simple cscript/square custom/.all custom/libcustcalc* +custom/.gitignore +compile_commands.json debug.out .dynamic endian diff --git a/CHANGES b/CHANGES index 6c3defc68..336298df8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +The following are the changes from calc version 2.15.0.7 to 2.15.0.8: + + Adding support for pipe/fork/exec via custom functions. + The following are the changes from calc version 2.15.0.6 to 2.15.0.7: Thanks to GitHub user @bambooleafz a critical bug (GitHub issue diff --git a/custom/Makefile b/custom/Makefile index 82b104ee7..8d94d26f2 100644 --- a/custom/Makefile +++ b/custom/Makefile @@ -85,13 +85,13 @@ include ${TARGET_MKF} # # Put your custom calc resource files here. # -CUSTOM_CALC_FILES= argv.cal halflen.cal pzasusb8.cal pmodm127.cal register.cal +CUSTOM_CALC_FILES= argv.cal halflen.cal pzasusb8.cal pmodm127.cal register.cal pfe.cal # The custom help files to install # # Put your custom help files here. # -CUSTOM_HELP= argv devnull help sysinfo pzasusb8 pmodm127 register +CUSTOM_HELP= argv devnull help sysinfo pzasusb8 pmodm127 register pfe # Any .h files that are needed by programs that use # libcustcalc${LIB_EXT_VERSION} @@ -110,7 +110,7 @@ CUSTOM_H_SRC= # Put your custom .c files here. # CUSTOM_SRC= c_argv.c c_devnull.c c_help.c c_sysinfo.c c_pzasusb8.c \ - c_pmodm127.c c_register.c + c_pmodm127.c c_register.c u_pfe.c # Any .o files that are needed by program that use # libcustcalc${LIB_EXT_VERSION}. @@ -122,7 +122,7 @@ CUSTOM_SRC= c_argv.c c_devnull.c c_help.c c_sysinfo.c c_pzasusb8.c \ # Put your custom .o files here. # CUSTOM_OBJ= c_argv.o c_devnull.o c_help.o c_sysinfo.o c_pzasusb8.o \ - c_pmodm127.o c_register.o + c_pmodm127.o c_register.o u_pfe.o ########################################################################## diff --git a/custom/custtbl.c b/custom/custtbl.c index 6d0b018b7..694cb7d15 100644 --- a/custom/custtbl.c +++ b/custom/custtbl.c @@ -79,6 +79,33 @@ E_FUNC VALUE c_pzasusb8(char*, int, VALUE**); E_FUNC VALUE c_pmodm127(char*, int, VALUE**); E_FUNC VALUE c_register(char*, int, VALUE**); +#define U_FUNC(name) E_FUNC VALUE name(char*, int, VALUE**); + +// pipe/fork/exec +U_FUNC(u_pfe_fork) +U_FUNC(u_pfe_pipe) +U_FUNC(u_pfe_close) +U_FUNC(u_pfe_execvp) +U_FUNC(u_pfe_dup) +U_FUNC(u_pfe_dup2) +U_FUNC(u_pfe_write) +U_FUNC(u_pfe_read) +U_FUNC(u_pfe_select) +U_FUNC(u_pfe_poll) + +U_FUNC(u_pfe_wait4) + +U_FUNC(u_pfe_pfe) +U_FUNC(u_pfe_pwrite) +U_FUNC(u_pfe_pread) + +// vike's various additions +U_FUNC(u_vadd_basename) +U_FUNC(u_vadd_dirname) +U_FUNC(u_vadd_getcwd) +U_FUNC(u_vadd_getpid) +U_FUNC(u_vadd_getppid) +U_FUNC(u_vadd_inputname) //cspell:ignore inputname #endif /* CUSTOM */ @@ -136,6 +163,50 @@ CONST struct custom cust[] = { { "register", "get or set customer registers", 1, 2, c_register }, + { "fork", "create process", + 0, 0, u_pfe_fork }, + { "pipe", "create descriptor pair for interprocess communication", + 0, 0, u_pfe_pipe }, + { "dup", "duplicate a file descriptor", + 1, 1, u_pfe_dup }, + { "dup2", "duplicate a file descriptor", + 2, 2, u_pfe_dup2 }, + { "close", "remove a file descriptor", + 1, 1, u_pfe_close }, + { "execvp", "execute a file", + 2, 2, u_pfe_execvp }, + { "write", "write output", + 2, 2, u_pfe_write }, + { "read", "read input", + 1, 2, u_pfe_read }, + { "select", "examine file descriptors", + 3, 4, u_pfe_select }, + { "poll", "synchronous I/O multiplexing", + 2, 3, u_pfe_poll }, + + { "wait4", "wait for process", + 1, 4, u_pfe_wait4 }, + + { "pfe", "pipe/fork/exec", + 4, 4, u_pfe_pfe }, + { "pwrite", "write and close", + 2, 2, u_pfe_pwrite }, + { "pread", "read until eof, close and wait for exit status", + 3, 3, u_pfe_pread }, + + { "getpid", "get calling process identification", + 0, 0, u_vadd_getpid }, + { "getppid", "get parent process identification", + 0, 0, u_vadd_getppid }, + { "getcwd", "get working directory pathname", + 0, 0, u_vadd_getcwd }, + { "inputname", "get name of input", + 0, 0, u_vadd_inputname }, + { "basename", "extract the base portion of a pathname", + 1, 1, u_vadd_basename }, + { "dirname", "extract the directory part of a pathname", + 1, 1, u_vadd_dirname }, + #endif /* CUSTOM */ diff --git a/custom/pfe b/custom/pfe new file mode 100755 index 000000000..d58e93f95 --- /dev/null +++ b/custom/pfe @@ -0,0 +1,91 @@ +NAME + pfe - pipe/fork/exec and friends + +SYNOPSIS + pipe = custom("pipe") ## create descriptor pair for interprocess communication + pid = custom("fork") ## create process + tgt = custom("dup", src) ## duplicate a file descriptor + tgt = custom("dup2", src, tgt) ## duplicate a file descriptor + e = custom("close", fd) ## remove a file descriptor + e = custom("execvp", arg0, args) ## execute a file + count = custom("write", fd, str) ## write output + str = custom("read", fd) ## read input + count = custom("select", rd, wt, exc[, timeout]) ## examine file descriptors + count = custom("poll", chk, &ret[, msecs]) ## synchronous I/O multiplexing + pid = custom("wait", [pid, ]&stt[, opts][, &usg]) ## wait for process + + pid = custom("pfe", &in, &out, &err, args) ## pipe/fork/exec + count = custom("pwrite", fd, str) ## write and close + e = custom("pread", pid, out, err) ## read until eof, close and wait for exit status + + str = custom("inputname") ## get name of input + path = custom("getcwd") ## get working directory pathname + + path = custom("basename", path) ## extract the base portion of a pathname + path = custom("dirname", path) ## extract the directory part of a pathname + + pid = custom("getpid") ## get calling process identification + pid = custom("getppid") ## get parent process identification + +TYPES + fd int num + pipe list of fd + pid int num + src tgt fd + arg0 str + args list of str + e int num + count int num + rd wt exc list of fd + in out err list of fd + timeout num + + arg1 str + ...argN str + chk list of list(fd[, arg1[, ...argN]]) + ret list of list(fd[, arg1[, ...argN]]) + msec int num + + stt assoc str => int num + opts list of str + usg assoc str => int num + + path str + +EXAMPLE + global i, o, e + if(pid = pfe(&i, &o, &e,list("sh","-c","read||:;echo $REPLY"))){ + pwrite(i,"test") + pread(pid,o,e)} + +LIMITS + calc must be built with ALLOW_CUSTOM= -DCUSTOM + calc must be executed with a -C arg. + +LIBRARY + none + +SEE ALSO + custom + +## Copyright (C) 2024 Viktor Bergquist +## +## Calc is open software; you can redistribute it and/or modify it under +## the terms of the version 2.1 of the GNU Lesser General Public License +## as published by the Free Software Foundation. +## +## Calc is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +## Public License for more details. +## +## A copy of version 2.1 of the GNU Lesser General Public License is +## distributed with calc under the filename COPYING-LGPL. You should have +## received a copy with calc; if not, write to Free Software Foundation, Inc. +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## Under source code control: 1997/03/09 20:28:01 +## File existed as early as: 1997 +## +## chongo /\oo/\ http://www.isthe.com/chongo/ +## Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/ diff --git a/custom/pfe.cal b/custom/pfe.cal new file mode 100644 index 000000000..091546800 --- /dev/null +++ b/custom/pfe.cal @@ -0,0 +1,199 @@ +/* + * pfe - pipe/fork/exec + * + * Copyright (c) 2024 Viktor Bergquist + * + * Calc is open software; you can redistribute it and/or modify it under + * the terms of the version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * Calc is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General + * Public License for more details. + * + * A copy of version 2.1 of the GNU Lesser General Public License is + * distributed with calc under the filename COPYING-LGPL. You should have + * received a copy with calc; if not, write to Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * This file is part of the custom sample calc files. + * + * NOTE: You must use a calc that was compiled with ALLOW_CUSTOM= -DCUSTOM + * and run with a -C arg. + */ +if (config("compile_custom") == 0) { + quit "calc compiled without -DCUSTOM"; +} else if (config("allow_custom") == 0) { + quit "calc was run without the -C command line option"; +} + + +define pfe_base_test() +{ + local file; + local fork = custom("fork"); + local fds = custom("pipe"); + if( fork){ + if( custom("write", fds[1], "test" )!=4) quit "error in write"; + if( custom("close", fds[1] ) ) quit "error in close"; + local rd = custom("read", fds[0] ); + local status = assoc + () ; custom("wait4", &status ); + if( rd != "test" ){ + file = fopen("/dev/stderr","w"); + fprintf(file,"mismatch of read: %s\n", rd); + quit; + } + if( status + ["exitstatus"]!= 0 ){ + file = fopen("/dev/stderr","w"); + fprintf(file,"mismatch of status: %d\n", status); + quit; + } + } else { + if( custom("close", fds[1]) ) quit "error in close"; + local args = list("sh", "-c", "{ read||:;}&&printf %s $REPLY"); + if( 0 > custom("dup2", fds[0],0 ) ) quit "error in dup2"; + if( ! custom("execvp", args[0], args ) ) quit "error in execvp"; + } +} + + ; define pipe ( ) = custom("pipe" ) + ; define fork ( ) = custom("fork" ) + ; define close (fd ) = custom("close" ,fd ) + ; define fds (rdl,wtl,exl,timeout) = custom("select" ,rdl,wtl,exl,timeout) + ; define poll ( in,out ,timeout) = custom("poll" , in,out ,timeout) + ; define dup (src ) = custom("dup" ,src ) + ; define dup2 (src,tgt ) = custom("dup2" ,src,tgt ) + ; define execvp (path,args ) = custom("execvp" ,path,args ) + ; define wt (fd,str ) = custom("write" ,fd,str ) + ; define rd (fd ) = custom("read" ,fd ) + ; define wait4 (pid,stt,opt,usg ) = custom("wait4" ,pid,stt,opt,usg ) + + ; define pfe (in,out,err,args ) = custom("pfe" ,in,out,err,args ) + ; define pwrite (fd,str ) = custom("pwrite" ,fd,str ) + ; define pread (pid,out,err ) = custom("pread" ,pid,out,err ) + + ; define pfe_test(){ + ; local r p i o e + ;if( p = pfe(& i,& o,& e,list("sh","-c","read -rd ''||e=$?;printf %s \"$REPLY\""))){ + ;if( pwrite( i,"test\n") != 5 ) quit "bad write" + ; r = pread(p, o, e) + ;if( r[0] != 0 ) quit "bad exit" + ;if( r[1] !="test\n" ) quit "bad read" + ;} + ;} + + ; define pfe_cal (in,out,err,args ){ + ; local di = pipe() ##// dn in + ; local uo = pipe() ##// up out + ; local ue = pipe() ##// up err + + ; *in = di[ 1 ] + ; *out= uo[ 0 ] + ; *err= ue[ 0 ] + + ; local e pid + ;if( pid = fork()){ + ;if( close ( di[ 0 ] ) ) quit "pfe: error in parent closing reading child input" + ;if( close ( ue[ 1 ] ) ) quit "pfe: error in parent closing writing child output" + ;if( close ( uo[ 1 ] ) ) quit "pfe: error in parent closing writing child error" + + ; return pid;} + else{ + ;if( close ( uo[ 0 ] ) ) quit "pfe: error in child closing reading output" + ;if( close ( ue[ 0 ] ) ) quit "pfe: error in child closing reading error" + ;if( close ( di[ 1 ] ) ) quit "pfe: error in child closing writing input" + + ;if( dup2 ( di[ 0 ],0)!=0 ) quit "pfe: mismatch in child duplication of input" + ;if( dup2 ( uo[ 1 ],1)!=1 ) quit "pfe: mismatch in child duplication of output" + ;if( dup2 ( ue[ 1 ],2)!=2 ) quit "pfe: mismatch in child duplication of error" + + ; e = execvp ( args[0] + , args );} + ;} + ; define pwrite_cal( in, str ){ + ; local w = wt ( in, str ) + ;if( w != strlen ( str ) ) quit "pwrite: mismatch" + ;if( close ( in ) ) quit "pwrite: error closing" + ;return w;} + ; define pread_cal( pid,out + , err ){ + ; local NULL= null () + + ; local rbl = list ( out + , err ) ##// read base list + + ; local oud = "" ##//out data + ; local erd = "" ##//err data + + ;while( local rbz = size + ( rbl ) ){ + ; local rcl + = rbl ##// read check list + ; local exl = list ( out + , err ) + + ; local fdc + = fds + ( & rcl ) + + ;if(0 < fdc ){ + ; local rcz = size + ( rcl ) ; + + ;for( local rcs = 0 + ; rcz>rcs + ; rcs++){ + + ; local rcd = rd + ( rcl[rcs]) + ;if( rcl[rcs] + == out + )if( rcd!=NULL + ) oud=strcat + ( oud + , rcd) + else delete + ( rbl + , search + (rbl, out)) ; + ;if( rcl[rcs] + == err + )if( rcd!=NULL + ) erd=strcat + ( erd + , rcd) + else delete + ( rbl + , search + (rbl, err)) ; + ;} + ;} + ;} + ; local stt = assoc() + ; pid = wait4( pid + ,& stt) + ;return list + ( (! stt["exited" ] + ?0: stt["exitstatus"] ) + + (! stt["stopped" ] + ?0: 128+stt["stopsig" ] ) + + (! stt["signaled" ] + ?0: 128+stt["termsig" ] ) + , oud + , erd );} + + ; define pfe_cal_test(){ + ; local r p i o e + ;if( p = pfe_cal(& i,& o,& e,list("sh","-c","read -rd ''||e=$?;printf %s \"$REPLY\""))){ + ;if( pwrite_cal( i,"test\n") != 5 ) quit "bad write" + ; r = pread_cal(p, o, e) + ;if( r[0] != 0 ) quit "bad exit" + ;if( r[1] !="test\n" ) quit "bad read" + ;} + ;} + diff --git a/custom/u_pfe.c b/custom/u_pfe.c new file mode 100644 index 000000000..d2006e0a2 --- /dev/null +++ b/custom/u_pfe.c @@ -0,0 +1,1378 @@ +/* + * u_pfe - pipe/fork/exec + * + * Copyright (c) 2024 Viktor Bergquist + * + * Calc is open software; you can redistribute it and/or modify it under + * the terms of the version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * Calc is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General + * Public License for more details. + * + * A copy of version 2.1 of the GNU Lesser General Public License is + * distributed with calc under the filename COPYING-LGPL. You should have + * received a copy with calc; if not, write to Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +//cspell:ignore qtoi itoq +//cspell:ignore ARGSUSED + +/* + * ISO C requires a translation unit to contain at least one declaration, + * so we declare a global variable whose value is based on if CUSTOM is defined. + */ +#include +#if defined(CUSTOM) +int u_pfe_allowed = 1; /* CUSTOM defined */ +#else /* CUSTOM */ +int u_pfe_allowed = 0; /* CUSTOM undefined */ +#endif /* CUSTOM */ + + +#if defined(CUSTOM) + +#include +#include +#include // MAXPATHLEN attow +#include +#include +#include +#include +#include +#include +#include + +#include "../have_const.h" +#include "../value.h" +#include "../custom.h" + +#include "../config.h" +#include "../calc.h" + +#include "../have_unused.h" + + +#include "../banned.h" /* include after system header <> includes */ + +const char* +type2str(short type) +{ + switch (type) { + case V_NULL: /* null value */ + return "null"; + break; + case V_INT: /* normal integer */ + return "int"; + break; + case V_NUM: /* number */ + return "rational_value"; + break; + case V_COM: /* complex number */ + return "complex_value"; + break; + case V_ADDR: /* address of variable value */ + return "address"; + break; + case V_STR: /* address of string */ + return "string"; + break; + case V_MAT: /* address of matrix structure */ + return "matrix"; + break; + case V_LIST: /* address of list structure */ + return "list"; + break; + case V_ASSOC: /* address of association structure */ + return "assoc"; + break; + case V_OBJ: /* address of object structure */ + return "object"; + break; + case V_FILE: /* opened file id */ + return "file"; + break; + case V_RAND: /* subtractive 100 random state */ + return "rand_state"; + break; + case V_RANDOM: /* address of Blum random state */ + return "random_state"; + break; + case V_CONFIG: /* configuration state */ + return "config_state"; + break; + case V_HASH: /* hash state */ + return "hash_state"; + break; + case V_BLOCK: /* memory block */ + return "octet_block"; + break; + case V_OCTET: /* octet (unsigned char) */ + return "octet"; + break; + default: + return "unknown"; + break; + } +} +const char* +value_type2str(VALUE value) { + return type2str(value.v_type); +} +const char* +value_ptr_type2str(VALUE*value) { + return type2str(value->v_type); +} + +/* + * u_pfe_fork - create process + * + * returns: + * pid + */ +/*ARGSUSED*/ +VALUE +u_pfe_fork(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) +{ + VALUE result; + int pid; + + pid = fork(); + + result.v_subtype = 0; + result.v_type = V_NUM; + result.v_num = itoq(pid); + return result; +} + +//cspell:ignore makenewstring +//cspell:ignore makestring +//makenewstring("0"); + +//cspell:ignore associndex +//cspell:ignore assocalloc + +VALUE* +associndex_int(ASSOC*assoc, long index) +{ + VALUE i; + VALUE indices[1]; + + i.v_type = V_NUM; + i.v_num = itoq(index); + + indices[0] = i; + return associndex(assoc, TRUE, 1, indices); +} + +VALUE* +associndex_str(ASSOC*assoc, STRING* index) +{ + VALUE i; + VALUE indices[1]; + + i.v_type = V_STR; + i.v_str = index; + + indices[0] = i; + return associndex(assoc, TRUE, 1, indices); +} + +void +associndex_int_int(ASSOC*assoc, long index, long value) +{ + VALUE*i = associndex_int(assoc, index); + i->v_type = V_NUM; + i->v_num = itoq(value); +} + +void +associndex_str_int(ASSOC*assoc, STRING* index, long value) +{ + VALUE*i = associndex_str(assoc, index); + i->v_type = V_NUM; + i->v_num = itoq(value); +} + +/* + * u_pfe_pipe - create descriptor pair for interprocess communication + * + * returns: + * assoc { [0] = reading, [1] = writing } + */ +/*ARGSUSED*/ +VALUE +u_pfe_pipe(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) +{ + const char* custname = "pipe"; + + int fds[2]; + if (pipe(fds)) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); + + ASSOC* assoc = assocalloc(2); + + associndex_int_int(assoc, 0, fds[0]); + associndex_int_int(assoc, 1, fds[1]); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_ASSOC; + result.v_assoc = assoc; + return result; +} + +//cspell:ignore custname +typedef enum { + VALV_OPT_OOB, + VALV_OPT_NULL, + VALV_OPT_GOOD, + VALV_OPT_BAD, + VALV_OPT_REF_NULL, +} valv_opt; + +valv_opt +valv_optional_type_check(int count, VALUE **vals, int idx, const char* UNUSED(name), short wanted) { + if (idx > count) return VALV_OPT_OOB; + if (vals[idx]->v_type == V_NULL) return VALV_OPT_NULL; + if (vals[idx]->v_type == wanted) return VALV_OPT_GOOD; + return VALV_OPT_BAD; +} +valv_opt +valv_optional_ref_type_check(int count, VALUE **vals, int idx, const char* UNUSED(name), short wanted) { + if (idx > count) return VALV_OPT_OOB; + if (vals[idx]->v_type == V_NULL) return VALV_OPT_NULL; + if (vals[idx]->v_type != V_VPTR) return VALV_OPT_BAD; + if (vals[idx]->v_addr->v_type == V_NULL) return VALV_OPT_REF_NULL; + if (vals[idx]->v_addr->v_type == wanted) return VALV_OPT_GOOD; + return VALV_OPT_BAD; +} +bool +valv_type_check(int UNUSED(count), VALUE **vals, int idx, const char* UNUSED(name), short wanted) { + return vals[idx]->v_type == wanted; +} +void +valv_type_require(const char* custname, int count, VALUE **vals, int idx, const char* name, short wanted) { + if (!valv_type_check(count, vals, idx, name, wanted)) math_error("%s: argment %d (%s) must be of type %s (%s given)", custname, idx+1, name, type2str(wanted), value_ptr_type2str(vals[idx])); +} +bool +valv_ref_type_check(int UNUSED(count), VALUE **vals, int idx, const char* UNUSED(name), short wanted) { + return vals[idx]->v_addr->v_type == wanted; +} +void +valv_ref_type_require(const char* custname, int count, VALUE **vals, int idx, const char* name, short wanted) { + if (!valv_type_check(count, vals, idx, name, V_VPTR)) math_error("%s: argment %d (%s) must be address (%s given) of type %s", custname, idx+1, name, value_ptr_type2str(vals[idx]), type2str(wanted)); + if (!valv_ref_type_check(count, vals, idx, name, wanted)) math_error("%s: argment %d (%s) must be address of type %s (%s given)", custname, idx+1, name, type2str(wanted), value_ptr_type2str(vals[idx]->v_addr)); +} + +long +valv_get_num_long(const char* custname, int count, VALUE **vals, int idx, const char* name) { + valv_type_require(custname, count, vals, idx, name, V_NUM); + return qtoi(vals[idx]->v_num); +} +VALUE* +valv_optional_get_num(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { + valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_NUM); + switch (chk) { + case VALV_OPT_BAD: return dflt; + case VALV_OPT_NULL: *idx += 1; // fall-thru + case VALV_OPT_OOB: return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD: ; // fall-thru + } + VALUE* num = vals[*idx]; + *idx += 1; + return num; +} +VALUE* +valv_optional_ref_num(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { + valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_NUM); + switch (chk) { + case VALV_OPT_BAD: return dflt; + case VALV_OPT_NULL: *idx += 1; // fall-thru + case VALV_OPT_OOB: return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD: ; // fall-thru + } + VALUE* num = vals[*idx]->v_addr; + if (chk == VALV_OPT_REF_NULL) { + num->v_type = V_NUM; + num->v_num = dflt->v_num; + } + *idx += 1; + return num; +} +VALUE* +valv_ref_num(const char* custname, int count, VALUE **vals, int idx, const char* name) { + valv_ref_type_require(custname, count, vals, idx, name, V_NUM); + return vals[idx]->v_addr; +} +VALUE* +valv_get_num(const char* custname, int count, VALUE **vals, int idx, const char* name) { + valv_type_require(custname, count, vals, idx, name, V_NUM); + return vals[idx]; +} +char* +valv_get_str(const char* custname, int count, VALUE **vals, int idx, const char* name) { + valv_type_require(custname, count, vals, idx, name, V_STR); + return vals[idx]->v_str->s_str; +} +//cspell:ignore strp +VALUE* +valv_get_strp(const char* custname, int count, VALUE **vals, int idx, const char* name) { + valv_type_require(custname, count, vals, idx, name, V_STR); + return vals[idx]; +} +VALUE* +valv_optional_ref_list(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { + valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_LIST); + switch (chk) { + case VALV_OPT_BAD: return dflt; + case VALV_OPT_NULL: *idx += 1; // fall-thru + case VALV_OPT_OOB: return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD: ; // fall-thru + } + VALUE* list = vals[*idx]->v_addr; + if (chk == VALV_OPT_REF_NULL) { + list->v_type = V_LIST; + list->v_list = dflt->v_list; + } + *idx += 1; + return list; +} +VALUE* +valv_optional_get_list(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { + valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_LIST); + switch (chk) { + case VALV_OPT_BAD: return dflt; + case VALV_OPT_NULL: *idx += 1; // fall-thru + case VALV_OPT_OOB: return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD: ; // fall-thru + } + VALUE* list = vals[*idx]; + *idx += 1; + return list; +} +VALUE* +valv_get_list(const char* custname, int count, VALUE **vals, int idx, const char* name) { + valv_type_require(custname, count, vals, idx, name, V_LIST); + return vals[idx]; +} +VALUE* +valv_ref_list(const char* custname, int count, VALUE **vals, int idx, const char* name) { + valv_ref_type_require(custname, count, vals, idx, name, V_LIST); + return vals[idx]->v_addr; +} +VALUE* +valv_optional_get_assoc(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { + valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_ASSOC); + switch (chk) { + case VALV_OPT_BAD: return dflt; + case VALV_OPT_NULL: *idx += 1; // fall-thru + case VALV_OPT_OOB: return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD: ; // fall-thru + } + VALUE* assoc = vals[*idx]; + *idx += 1; + return assoc; +} +VALUE* +valv_optional_ref_assoc(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { + valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_ASSOC); + switch (chk) { + case VALV_OPT_BAD: return dflt; + case VALV_OPT_NULL: *idx += 1; // fall-thru + case VALV_OPT_OOB: return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD: ; // fall-thru + } + VALUE* assoc = vals[*idx]->v_addr; + *idx += 1; + return assoc; +} +VALUE* +valv_get_assoc(const char* custname, int count, VALUE **vals, int idx, const char* name) { + valv_type_require(custname, count, vals, idx, name, V_ASSOC); + return vals[idx]; +} +VALUE* +valv_ref_assoc(const char* custname, int count, VALUE **vals, int idx, const char* name) { + valv_ref_type_require(custname, count, vals, idx, name, V_ASSOC); + return vals[idx]->v_addr; +} + +/* + * u_pfe_execvp - execute a file, possibly looking in paths from environment or system + * + * given: + * vals[0] file + * vals[1] list(arg0,...) + * + * returns: + * 0 on success + */ +/*ARGSUSED*/ +VALUE +u_pfe_execvp(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "execvp"; + + char* path = valv_get_str (custname, count, vals, 0, "file"); + VALUE* args_list = valv_get_list (custname, count, vals, 1, "args"); + + char** args; + if (!(args = malloc(sizeof(char*) * args_list->v_list->l_count))) math_error("%s: "__FILE__": %d: malloc: %s", custname, __LINE__, strerror(errno)); + + LISTELEM* el = args_list->v_list->l_first; + int s = 0; + for (; + el != NULL; + el = el->e_next, + s++ + ) { + if (el->e_value.v_type != V_STR) math_error("%s: argment 2 (args) element %d must be of type string (%s given)", custname, s, value_type2str(el->e_value)); + + args[s] = el->e_value.v_str->s_str; + } + + if (execvp(path, args)) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); + + free(args); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(errno); + return result; +} + +/* + * u_pfe_dup - duplicate a file descriptor + * + * given: + * vals[0] source fd + * + * returns: + * target fd + */ +/*ARGSUSED*/ +VALUE +u_pfe_dup(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "dup"; + + int fd = dup( + valv_get_num_long(custname, count, vals, 0, "source")); + + if (fd < 0) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(fd); + return result; +} + +/* + * u_pfe_dup2 - duplicate a file descriptor + * + * given: + * vals[0] source fd + * vals[1] target fd + * + * returns: + * target fd + */ +/*ARGSUSED*/ +VALUE +u_pfe_dup2(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "dup2"; + + int fd = dup2( + valv_get_num_long(custname, count, vals, 0, "source"), + valv_get_num_long(custname, count, vals, 1, "target")); + + if (fd < 0) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(fd); + return result; +} + +/* + * u_pfe_close - delete a file descriptor + * + * given: + * vals[0] fd + * + * returns: + * 0 on success + */ +/*ARGSUSED*/ +VALUE +u_pfe_close(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "close"; + + int e = close(valv_get_num_long(custname, count, vals, 0, "fd")); + + if (e) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(e); + return result; +} + +/* + * u_pfe_write - write output + * + * given: + * vals[0] fd + * vals[1] string + * + * returns: + * count of bytes written + */ +/*ARGSUSED*/ +VALUE +u_pfe_write(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "write"; + + VALUE* strp = valv_get_strp(custname, count, vals, 1, "string"); + + ssize_t written = write( + valv_get_num_long(custname, count, vals, 0, "fd"), + strp->v_str->s_str, + strp->v_str->s_len); + + if (written < 0) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(written); + return result; +} + +#define u_pfe_read_STRL_DFLT 1024 + +/* + * u_pfe_read - write output + * + * given: + * vals[0] fd + * vals[1] count defaulting to 1024 + * + * returns: + * count of bytes read + */ +/*ARGSUSED*/ +VALUE +u_pfe_read(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "read"; + + int strl = count < 2 ? u_pfe_read_STRL_DFLT : valv_get_num_long(custname, count, vals, 1, "count"); + + char* str = malloc((strl+1)*sizeof(char)); + + ssize_t r = read( + valv_get_num_long(custname, count, vals, 0, "fd"), + str, strl); + str[r] = '\0'; + + if (r < 0) { free(str); math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); } + + VALUE result; + result.v_subtype = 0; + result.v_type = !r ? V_NULL : V_STR; + if (r) + result.v_str = makestring(str); + return result; +} + +VALUE* +optional_valv_ref_list2fd_set(const char* custname, int count, VALUE **vals, int* idx, const char* name, fd_set* fds, int* setsize) { + valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_LIST); + switch (chk) { + case VALV_OPT_BAD: return NULL; + case VALV_OPT_NULL: *idx += 1; // fall-thru + case VALV_OPT_OOB: return NULL; + case VALV_OPT_REF_NULL: math_error("%s: argument %d (%s) address of type null is not allowed", custname, *idx, name); + case VALV_OPT_GOOD: ; // fall-thru + } + VALUE* list = vals[*idx]->v_addr; + *idx += 1; + LISTELEM* el = list->v_list->l_first; + int s = 0; + for (; + el != NULL; + el = el->e_next, + s++ + ) { + if (el->e_value.v_type != V_NUM) math_error("%s: argument %d (%s) element %d must be of type number (%s given)", custname, *idx, name, s, value_type2str(el->e_value)); + + int i = qtoi(el->e_value.v_num); + if (*setsize < i+1) + *setsize = i+1; + FD_SET(i, fds); + } + return list; +} + +VALUE* +alloc_list(LIST* list) { + VALUE* result = malloc(sizeof(VALUE)); + result->v_type = V_LIST; + + result->v_list = list; + return result; +} + +VALUE* +alloc_assoc(ASSOC* assoc) { + VALUE* result = malloc(sizeof(VALUE)); + result->v_type = V_ASSOC; + + result->v_assoc = assoc; + return result; +} + +//cspell:ignore listalloc copyvalue insertlistlast + +VALUE* +list_fd_get(LIST* in, fd_set* fds) { + VALUE* out = alloc_list(listalloc()); + LISTELEM* el = in->l_first; + int s = 0; + for (; + el != NULL; + el = el->e_next, + s++ + ) { + int i = qtoi(el->e_value.v_num); + if (FD_ISSET(i, fds)){ + VALUE o; + copyvalue(&el->e_value, &o); + insertlistlast(out->v_list, &o); + } + } + return out; +} + +VALUE* +alloc_num(NUMBER* num) { + VALUE* result = malloc(sizeof(VALUE)); + result->v_type = V_NUM; + + result->v_num = num; + return result; +} + +VALUE* +alloc_str(STRING* str) { + VALUE* result = malloc(sizeof(VALUE)); + result->v_type = V_STR; + + result->v_str = str; + return result; +} + +VALUE* pfe_select_TIMEOUT_DFLT = NULL; + +//cspell:ignore qisneg qisint ztoi qscale qfree + +/* + * u_pfe_select - examine file descriptors + * + * given: + * vals[l1+0] null or address of list (inout\ref) of fds for reading, wh/ l1 is zero-index of 1st list + * vals[l1+1] null or address of list (inout\ref) of fds for writing, wh/ l1 is zero-index of 1st list + * vals[l1+2] null or address of list (inout\ref) of fds for exceptional, wh/ l1 is zero-index of 1st list + * vals[lZ+1] null or timeout defaulting to -1, wh/ lZ is zero-index of last list + * + * returns: + * count of fds w/ status + */ +/*ARGSUSED*/ +VALUE +u_pfe_select(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "select"; + int v = 0; + + int ssz = 0; + fd_set rds; FD_ZERO(&rds); VALUE* rdl = optional_valv_ref_list2fd_set(custname, count, vals, &v, "reading" ,&rds,&ssz); + fd_set wts; FD_ZERO(&wts); VALUE* wtl = optional_valv_ref_list2fd_set(custname, count, vals, &v, "writing" ,&wts,&ssz); + fd_set ers; FD_ZERO(&ers); VALUE* erl = optional_valv_ref_list2fd_set(custname, count, vals, &v, "exceptional" ,&ers,&ssz); + + if (!pfe_select_TIMEOUT_DFLT) pfe_select_TIMEOUT_DFLT = alloc_num(itoq(-1)); + + VALUE* tv = valv_optional_get_num(count, vals, &v, "timeout", pfe_select_TIMEOUT_DFLT); + + NUMBER* tn = tv->v_num; + struct timeval t; + struct timeval* tp; + // originally from f_sleep() in ../func.c + if (qisneg(tn)) { + tp = NULL; + } else if (qisint(tn)) { + if (zge31b(tn->num)) + math_error("sizeof(timeout) > 31 bytes"); + t.tv_sec = ztoi(tn->num); + t.tv_usec = 0; + tp = &t; + } else { + NUMBER *q1, *q2; + q1 = qscale(tn, 20); // 2^20 = 1 Mi + q2 = qint(q1); + qfree(q1); + if (zge31b(q2->num)) { + qfree(q2); + math_error("sizeof(timeout as microseconds) > 31 bytes"); + } + long usec = ztoi(q2->num); + t.tv_sec = usec / 1000000; + t.tv_usec = usec - t.tv_sec * 1000000; + tp = &t; + qfree(q2); + } + + int r = select(ssz, &rds, &wts, &ers, tp); + + if (r < 0) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); + + if (rdl) *rdl = *list_fd_get(rdl->v_list, &rds); + if (wtl) *wtl = *list_fd_get(wtl->v_list, &wts); + if (erl) *erl = *list_fd_get(erl->v_list, &ers); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(r); + return result; +} + +VALUE* u_pfe_poll_TIMEOUT_DFLT = NULL; + +/* + * u_pfe_poll - synchronous I/O multiplexing + * + * tested manually only slightly (as it turned out it wasn't suitable for why it was written) + * + * TODO unit/feature test + * + * given: + * vals[0] list of list(fd[, event1[, ...eventN]]) + * vals[1] address of list, appended with list(fd[, event1[, ...eventN]]) + * vals[2] null or integer millisecond timeout defaulting to -1 + * + * returns: + * count of fds w/ status + */ +/*ARGSUSED*/ +VALUE +u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "poll"; + const char* i_name = "list of list(fd[, event1[, ...eventN]])"; + + VALUE* iv = valv_get_list(custname, count, vals, 0, i_name); + VALUE* ov = valv_ref_list(custname, count, vals, 1, "list"); + + if (!u_pfe_poll_TIMEOUT_DFLT) u_pfe_poll_TIMEOUT_DFLT = alloc_num(itoq(-1)); + int v = 2; + VALUE* tv = valv_optional_get_num(count, vals, &v, "timeout", u_pfe_poll_TIMEOUT_DFLT); + NUMBER* tn = tv->v_num; + if (!qisint(tn)) math_error("%s: argument 2 (timeout) must be integer", custname); + int t = qtoi(tn); + + LIST* il = iv->v_list; + struct pollfd* pollfds = malloc(il->l_count*sizeof(struct pollfd)); //cspell:ignore pollfds + + LISTELEM* el = il->l_first; + int s = 0; + for (; + el != NULL; + el = el->e_next, + s++ + ) { + if ( el ->e_value.v_type != V_LIST ) { free(pollfds); + math_error("%s: argument %d (%s) element %d must be of type list (%s given)", + custname, 1, i_name, s, value_type2str(el->e_value)); } + + LIST* el_list = el->e_value.v_list; + LISTELEM* el_el; + + el_el = el_list->l_first; + + if ( el_el ->e_value.v_type != V_NUM ) { free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be of type number (%s given)", + custname, 1, i_name, s, 1, value_type2str(el_el->e_value)); } + if (!qisint(el_el ->e_value.v_num) ) { free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be integer (%s given)", + custname, 1, i_name, s, 1, value_type2str(el_el->e_value)); } + pollfds[s].fd = qtoi(el_el->e_value.v_num); + + pollfds[s].events = 0; + + el_el = el_el->e_next; + + int el_el_s = 1; + for (; + el_el != NULL; + el_el = el_el->e_next, + el_el_s++ + ) { + if ( el_el ->e_value.v_type != V_STR ) { free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be of type string (%s given)", + custname, 1, i_name, s, el_el_s, value_type2str(el_el->e_value)); } + + char* el_el_str = el_el->e_value.v_str->s_str; + if (FALSE); // man poll|gawk 'match($0,"^\\s*POLL([A-Z]+)",m){print(tolower(m[1]))}' + else if (!strcmp(el_el_str, "err" )) pollfds[s].events |= POLLERR; + else if (!strcmp(el_el_str, "hup" )) pollfds[s].events |= POLLHUP; + else if (!strcmp(el_el_str, "in" )) pollfds[s].events |= POLLIN; + else if (!strcmp(el_el_str, "nval" )) pollfds[s].events |= POLLNVAL; //cspell:ignore nval + else if (!strcmp(el_el_str, "out" )) pollfds[s].events |= POLLOUT; + else if (!strcmp(el_el_str, "pri" )) pollfds[s].events |= POLLPRI; + else if (!strcmp(el_el_str, "rdband" )) pollfds[s].events |= POLLRDBAND; //cspell:ignore rdband + else if (!strcmp(el_el_str, "rdnorm" )) pollfds[s].events |= POLLRDNORM; //cspell:ignore rdnorm + else if (!strcmp(el_el_str, "wrband" )) pollfds[s].events |= POLLWRBAND; //cspell:ignore wrband + else if (!strcmp(el_el_str, "wrnorm" )) pollfds[s].events |= POLLWRNORM; //cspell:ignore wrnorm + else { free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be a string containing one of the event names from POSIX poll.h or the manual for poll, lowercase without poll prefix (%s given)", + custname, 1, i_name, s, el_el_s, el_el->e_value.v_str->s_str); } + } + + pollfds[s].revents = 0; + } + + int r = poll(pollfds, il->l_count, t); + + if (r < 0) { free(pollfds); math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); } + + LIST* ol = listalloc(); + + for (s = 0; s < il->l_count; s++) { + VALUE* o = alloc_assoc(assocalloc(0)); + + if ((pollfds[s].revents & POLLERR ) == POLLERR ) associndex_str_int(o->v_assoc, makenewstring("err" ), POLLERR ); + if ((pollfds[s].revents & POLLHUP ) == POLLHUP ) associndex_str_int(o->v_assoc, makenewstring("hup" ), POLLHUP ); + if ((pollfds[s].revents & POLLIN ) == POLLIN ) associndex_str_int(o->v_assoc, makenewstring("in" ), POLLIN ); + if ((pollfds[s].revents & POLLNVAL ) == POLLNVAL ) associndex_str_int(o->v_assoc, makenewstring("nval" ), POLLNVAL ); + if ((pollfds[s].revents & POLLOUT ) == POLLOUT ) associndex_str_int(o->v_assoc, makenewstring("out" ), POLLOUT ); + if ((pollfds[s].revents & POLLPRI ) == POLLPRI ) associndex_str_int(o->v_assoc, makenewstring("pri" ), POLLPRI ); + if ((pollfds[s].revents & POLLRDBAND) == POLLRDBAND ) associndex_str_int(o->v_assoc, makenewstring("rdband" ), POLLRDBAND ); + if ((pollfds[s].revents & POLLRDNORM) == POLLRDNORM ) associndex_str_int(o->v_assoc, makenewstring("rdnorm" ), POLLRDNORM ); + if ((pollfds[s].revents & POLLWRBAND) == POLLWRBAND ) associndex_str_int(o->v_assoc, makenewstring("wrband" ), POLLWRBAND ); + if ((pollfds[s].revents & POLLWRNORM) == POLLWRNORM ) associndex_str_int(o->v_assoc, makenewstring("wrnorm" ), POLLWRNORM ); + + insertlistlast(ol, o); + } + + ov->v_list = ol; + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(r); + return result; +} + +/* + * u_pfe_wait4 - wait for process termination + * + * wh/ n1 is zero-index of 1st number, + * given: + * vals[n1+0] pid wh/ null() means any children à la man 2 wait # aka wait(2) and only vals[n1+1] allowed + * vals[n1+1] address of assoc of status w/ one pair of key with companion(s): "exited" &then "exitstatus", "signaled" &then "termsig" & "coredump", "stopped" &then "stopsig" acc2 man 2 wait # aka wait(2) + * vals[n1+2] null or list of options "nohang" or "untraced" acc2 man TODO test + * vals[n1+3] null or address of assoc of usage TODO handle + * + * returns: + * pid or 0 w/ "nohang" + */ +/*ARGSUSED*/ +VALUE +u_pfe_wait4(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "wait4"; + int v = 0; + VALUE* pid_num = valv_optional_get_num ( count, vals, &v, "pid" , NULL ); + VALUE* stt_assoc = valv_ref_assoc(custname, count, vals, v++, "status" ); // stat in + VALUE* opt_list = valv_optional_get_list ( count, vals, &v, "options" , NULL ); + VALUE* usg_assoc = valv_optional_ref_assoc ( count, vals, &v, "usage" , NULL ); + + if (!pid_num && opt_list ) math_error("%s: argument 1 (pid) being null doesn't support options list", custname); + if (!pid_num && usg_assoc ) math_error("%s: argument 1 (pid) being null doesn't support usage assoc", custname); + + int opts = 0; + if (opt_list) { + LISTELEM* el = opt_list->v_list->l_first; + int s = 0; + for (; + el != NULL; + el = el->e_next, + s++ + ) { + if (el->e_value.v_type != V_STR) math_error("%s: options list element %d must be of type string (%s given)", custname, s, value_type2str(el->e_value)); + + char* opt_str = el->e_value.v_str->s_str; + if (FALSE); + else if (!strcmp(opt_str, "nohang" )) opts |= WNOHANG; + else if (!strcmp(opt_str, "untraced" )) opts |= WUNTRACED; + else math_error("%s: options list element %d must be one of \"nohang\" or \"untraced\" (%s given)", custname, s, opt_str); + } + } + + int stt = 0; + struct rusage usg; + struct rusage* usg_p = usg_assoc ? &usg : NULL; + pid_t r = pid_num ? wait4(qtoi(pid_num->v_num), &stt, opts, usg_p) : wait(&stt); + + if (0 > r) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); + + if ( WIFEXITED (stt) ){ + associndex_str_int (stt_assoc->v_assoc, makenewstring("exited" ), TRUE ); + associndex_str_int (stt_assoc->v_assoc, makenewstring("exitstatus" ), WEXITSTATUS (stt) );} + if ( WIFSIGNALED (stt) ){ + associndex_str_int (stt_assoc->v_assoc, makenewstring("signaled" ), TRUE ); + associndex_str_int (stt_assoc->v_assoc, makenewstring("termsig" ), WTERMSIG (stt) ); + associndex_str_int (stt_assoc->v_assoc, makenewstring("coredump" ), WCOREDUMP (stt) );} + if ( WIFSTOPPED (stt) ){ + associndex_str_int (stt_assoc->v_assoc, makenewstring("stopped" ), TRUE ); + associndex_str_int (stt_assoc->v_assoc, makenewstring("stopsig" ), WSTOPSIG (stt) );} + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(r); + return result; +} + +/* + * u_pfe_pfe - pipe/fork/exec + * + * given: + * vals[0] address of fd for in + * vals[1] address of fd for out + * vals[2] address of fd for err + * vals[3] list of args + * + * returns: + * forked pid + */ +/*ARGSUSED*/ +VALUE +u_pfe_pfe(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "pfe"; + + // in, out, err arrays + int ia[2];if (pipe(ia)) math_error("%s: "__FILE__": %d: (in) pipe: %s", custname, __LINE__, strerror(errno)); + int oa[2];if (pipe(oa)) math_error("%s: "__FILE__": %d: (out) pipe: %s", custname, __LINE__, strerror(errno)); + int ea[2];if (pipe(ea)) math_error("%s: "__FILE__": %d: (err) pipe: %s", custname, __LINE__, strerror(errno)); + // in, out, err values + VALUE* iv = valv_ref_num(custname, count, vals, 0, "in"); + VALUE* ov = valv_ref_num(custname, count, vals, 1, "out"); + VALUE* ev = valv_ref_num(custname, count, vals, 2, "err"); + iv->v_num = itoq(ia[1]); + ov->v_num = itoq(oa[0]); + ev->v_num = itoq(ea[0]); + + pid_t child = fork(); + if (child) { + + // child: close (parent in, out, err) + int cci = !close(ia[0]) ? 0 : errno; + int cco = !close(oa[1]) ? 0 : errno; + int cce = !close(ea[1]) ? 0 : errno; + + if (cci) math_error("%s: "__FILE__": %d: child: (parent in) close: %s", custname, __LINE__, strerror(cci)); + if (cco) math_error("%s: "__FILE__": %d: child: (parent out) close: %s", custname, __LINE__, strerror(cco)); + if (cce) math_error("%s: "__FILE__": %d: child: (parent err) close: %s", custname, __LINE__, strerror(cce)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(child); + return result; + + } else { + + // parent: close (child in, out, err) + int pci = !close(ia[1]) ? 0 : errno; + int pco = !close(oa[0]) ? 0 : errno; + int pce = !close(ea[0]) ? 0 : errno; + + if (pci) math_error("%s: "__FILE__": %d: parent: (child in) close: %s", custname, __LINE__, strerror(pci)); + if (pco) math_error("%s: "__FILE__": %d: parent: (child out) close: %s", custname, __LINE__, strerror(pco)); + if (pce) math_error("%s: "__FILE__": %d: parent: (child err) close: %s", custname, __LINE__, strerror(pce)); + + if (dup2(ia[0], 0)!=0) math_error("%s: "__FILE__": %d: mismatch: (in) dup2: %s", custname, __LINE__, strerror(errno)); + if (dup2(oa[1], 1)!=1) math_error("%s: "__FILE__": %d: mismatch: (out) dup2: %s", custname, __LINE__, strerror(errno)); + if (dup2(ea[1], 2)!=2) math_error("%s: "__FILE__": %d: mismatch: (err) dup2: %s", custname, __LINE__, strerror(errno)); + + VALUE* args_list = valv_get_list(custname, count, vals, 3, "args"); + + char** args; + if (!(args = malloc(sizeof(char*) * args_list->v_list->l_count))) math_error("%s: "__FILE__": %d: malloc: %s", custname, __LINE__, strerror(errno)); + + LISTELEM* el = args_list->v_list->l_first; + int s = 0; + for (; + el != NULL; + el = el->e_next, + s++ + ) { + if (el->e_value.v_type != V_STR) math_error("%s: argment 2 (args) element %d must be of type string (%s given)", custname, s, value_type2str(el->e_value)); + + args[s] = el->e_value.v_str->s_str; + } + + if (execvp(args[0], args)) math_error("%s: "__FILE__": %d: execvp: %s", custname, __LINE__, strerror(errno)); + + free(args); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(errno); + return result; + } +} + +/* + * u_pfe_pwrite - write and close + * + * given: + * vals[0] fd + * vals[1] string + * + * returns: + * count of bytes written + */ +/*ARGSUSED*/ +VALUE +u_pfe_pwrite(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "pwrite"; + + VALUE* strp = valv_get_strp(custname, count, vals, 1, "string"); + + int fd = valv_get_num_long(custname, count, vals, 0, "fd"); + + ssize_t w = write(fd, + strp->v_str->s_str, + strp->v_str->s_len); + + if (w < 0) math_error("%s: "__FILE__": %d: write: %s", custname, __LINE__, strerror(errno)); + + int e = close(fd); + + if (e) math_error("%s: "__FILE__": %d: close: %s", custname, __LINE__, strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(w); + return result; +} + +#define pfe_pfe_SIZE_BUFFER 4096 +#define pfe_pfe_SIZE_INIT 4096 + + // next func is verbatim, apart from dprintf, strcat-fix->strlcat and spacing, from ~vike/∂/xcode/vmdbTx-objc/main.m //cspell:ignore strext + char * strext + ( char ** subject + , char * with + ){ // dprintf(2, "strext(s, w) wh/ |s| = %lu, |w| = %lu, |s| = “%s”, & w = “%s”\n", strlen(*subject), strlen(with), *subject, with) + ; size_t n= strlen( *subject) + + strlen( with) ;if ( ( *subject + = reallocf( *subject + , n+1) ) == NULL + ) return NULL +// ; dprintf(2, "strext(s, w) wh/ n+1 = %lu = (|s| = %lu) + (|w| = %lu) + 1, |s| = “%s”, & w = “%s”\n", n+1, strlen(*subject), strlen(with), *subject, with) + ; strlcat( *subject + , with + , n+1) // pretty useless use of strlcat but strncat and strcat are "poisoned" giving error attow (w/ -Wall I guess, I dunno), tho we just realloc'd acc2 strlen, what the heck + ; return*subject;} + +//#define u_pfe_pread_DEBUG(r, n) dprintf(2, "r = %d;will do strext("#n", "#n"b) wh/ |"#n"| = %lu, |"#n"b| = %lu, "#n" = “%s”, & "#n"b = “%s”\n", r, strlen(n), strlen(n##b), n, n##b) + +/* + * u_pfe_pread - read until eof, close and wait for exit status + * + * if wait4() encounters a signalled process, this function returns the signal + 128, like bash(1). + * + * given: + * vals[0] pid + * vals[1] out + * vals[1] err + * + * returns: + * list(status, stdout_string, stderr_string) + */ +/*ARGSUSED*/ +VALUE +u_pfe_pread(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "pread"; + + int pid = valv_get_num_long(custname, count, vals, 0, "pid"); + int out = valv_get_num_long(custname, count, vals, 1, "out"); + int err = valv_get_num_long(custname, count, vals, 2, "err"); + + fd_set nvm; FD_ZERO(&nvm); // never mind + fd_set rbs; FD_ZERO(&rbs); // read base set + int ssz = 0; + FD_SET(out, &rbs); if (out > ssz) ssz = out; + FD_SET(err, &rbs); if (err > ssz) ssz = err; + + // Keep track of rbs + bool eoo = NULL; // end of out + bool eoe = NULL; // end of err + + char* o = malloc(pfe_pfe_SIZE_INIT*sizeof(char)); o[0] = '\0'; + char* e = malloc(pfe_pfe_SIZE_INIT*sizeof(char)); e[0] = '\0'; + + char ob[pfe_pfe_SIZE_BUFFER]; // out buffer + char eb[pfe_pfe_SIZE_BUFFER]; // err buffer + + int pco = 0; + int pce = 0; + + fd_set rcs; // read check set + while (!eoo || !eoe) { + FD_COPY(&rbs, &rcs); + + int r = select(1+ssz, &rcs, &nvm, &nvm, NULL); + if (r < 0) math_error("%s: "__FILE__": %d: select: %s", custname, __LINE__, strerror(errno)); + + if (FD_ISSET(out, &rcs)) { + r = read(out, &ob, pfe_pfe_SIZE_BUFFER); +// u_pfe_pread_DEBUG(r, o); + if (r < 0) math_error("%s: "__FILE__": %d: (out, %lu) read: %s", custname, __LINE__, strlen(o), strerror(errno)); + if (r) { + ob[r] = '\0'; + strext(&o, ob); + } else { + if(close(out)) pco = errno; + FD_CLR(out, &rbs); + eoo = TRUE; + } + } + if (FD_ISSET(err, &rcs)) { + r = read(err, &eb, pfe_pfe_SIZE_BUFFER); +// u_pfe_pread_DEBUG(r, e); + if (r < 0) math_error("%s: "__FILE__": %d: (err, %lu) read: %s", custname, __LINE__, strlen(e), strerror(errno)); + if (r) { + eb[r] = '\0'; + strext(&e, eb); + } else { + if(close(err)) pce = errno; + FD_CLR(err, &rbs); + eoe = TRUE; + } + } + } + + if (pco) math_error("%s: "__FILE__": %d: (out) close: %s", custname, __LINE__, strerror(pco)); + if (pce) math_error("%s: "__FILE__": %d: (err) close: %s", custname, __LINE__, strerror(pce)); + + int stt = 0; + pid_t w = wait4(pid, &stt, 0, NULL); + + if (0 > w) math_error("%s: "__FILE__": %d: wait4: %s", custname, __LINE__, strerror(errno)); + + NUMBER* r = itoq + ( ( ! WIFEXITED (stt) + ?0: WEXITSTATUS (stt) ) + + ( ! WIFSTOPPED (stt) + ?0:128+ WSTOPSIG (stt) ) + + ( ! WIFSIGNALED (stt) + ?0:128+ WTERMSIG (stt) )); + + LIST* list = listalloc(); + insertlistlast(list, alloc_num( r )); + insertlistlast(list, alloc_str(makestring( o) )); + insertlistlast(list, alloc_str(makestring( e) )); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_LIST; + + result.v_list = list; + return result; +} + +/* + * u_vadd_getpid - get calling process identification + * + * returns: + * pid + */ +/*ARGSUSED*/ +VALUE +u_vadd_getpid(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) +{ + const char* UNUSED(custname) = "getpid"; + + pid_t pid = getpid(); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(pid); + return result; +} + +/* + * u_vadd_getppid - get parent process identification + * + * returns: + * pid + */ +/*ARGSUSED*/ +VALUE +u_vadd_getppid(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) +{ + const char* UNUSED(custname) = "getppid"; + + pid_t pid = getppid(); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(pid); + return result; +} + +/* + * u_vadd_getcwd - get working directory pathname + * + * returns: + * path + */ +/*ARGSUSED*/ +VALUE +u_vadd_getcwd(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) +{ + const char* custname = "getcwd"; + + char* buf = getcwd(NULL, -1); // doing equiv(malloc) COULD use MAXPATHLEN from and s/makestring/makenewstring/ below I guess + if (!buf) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_STR; + + result.v_str = makestring(buf); + return result; +} + +/* + * u_vadd_inputname - get working directory pathname + * + * returns: + * name + */ +/*ARGSUSED*/ +VALUE +u_vadd_inputname(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) //cspell:ignore inputname +{ + const char* UNUSED(custname) = "inputname"; + + char* buf = inputname(); + if (!buf) buf = inputisterminal() ? "" : ""; //cspell:ignore inputisterminal + + VALUE result; + result.v_subtype = 0; + result.v_type = V_STR; + + result.v_str = makenewstring(buf); + return result; +} + +/* + * u_vadd_basename - extract the base portion of a pathname + * + * given: + * vals[0] path + * + * returns: + * path + */ +/*ARGSUSED*/ +VALUE +u_vadd_basename(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "basename"; + + VALUE* strp = valv_get_strp(custname, count, vals, 0, "path"); + + char buf[MAXPATHLEN]; + if (!basename_r(strp->v_str->s_str, buf)) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_STR; + + result.v_str = makenewstring(buf); + return result; +} + +/* + * u_vadd_dirname - extract the base portion of a pathname + * + * given: + * vals[0] path + * + * returns: + * path + */ +/*ARGSUSED*/ +VALUE +u_vadd_dirname(char *UNUSED(name), int count, VALUE **vals) +{ + const char* custname = "dirname"; + + VALUE* strp = valv_get_strp(custname, count, vals, 0, "path"); + + char buf[MAXPATHLEN]; + if (!dirname_r(strp->v_str->s_str, buf)) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_STR; + + result.v_str = makenewstring(buf); + return result; +} + +#endif /* CUSTOM */ From 3f106bf3799a56048b42bb23b98f370edc4fd361 Mon Sep 17 00:00:00 2001 From: vike Date: Thu, 11 Jul 2024 16:44:16 +0200 Subject: [PATCH 02/21] adding custom *pfe* development files --- .vscode/launch.json | 52 +++++++++++ .vscode/launch/.env | 8 ++ .vscode/launch/_env.py | 3 + .vscode/launch/env.py | 25 +++++ .vscode/tasks.json | 19 ++++ compile_flags.txt | 2 + custom/pfe+conf.cal | 11 +++ custom/pfe-dev.cal | 203 +++++++++++++++++++++++++++++++++++++++++ custom/pfe-launch.cal | 8 ++ custom/pfe-v.cal | 12 +++ custom/pfe-v.sh | 24 +++++ 11 files changed, 367 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 .vscode/launch/.env create mode 100644 .vscode/launch/_env.py create mode 100644 .vscode/launch/env.py create mode 100644 .vscode/tasks.json create mode 100644 compile_flags.txt create mode 100644 custom/pfe+conf.cal create mode 100644 custom/pfe-dev.cal create mode 100644 custom/pfe-launch.cal create mode 100644 custom/pfe-v.cal create mode 100755 custom/pfe-v.sh diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..fe8c265f7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,52 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "lldb launch", + "cwd": "${workspaceFolder}", + "program": "./calc", + "env": { + "DYLD_LIBRARY_PATH": ".", + }, + "preRunCommands": [ + "command script import .vscode/launch/_env.py .vscode/launch/env.py", + ], + "args": ["-Cpf", "custom/pfe-launch.cal"], + }, + { + "preLaunchTask": "compiledb make clobber all #DEBUG=… w/ macports readline", + "type": "lldb", + "request": "launch", + "name": "lldb launch + compiledb make clobber all #DEBUG=… w/ macports readline", + "cwd": "${workspaceFolder}", + "program": "./calc", + "env": { + "DYLD_LIBRARY_PATH": ".", + }, + "preRunCommands": [ + "command script import .vscode/launch/_env.py .vscode/launch/env.py", + ], + "args": ["-Cpf", "custom/pfe-launch.cal"], + }, + { + "preLaunchTask": "compiledb make clobber all #… w/ macports readline", + "type": "lldb", + "request": "launch", + "name": "lldb launch + compiledb make clobber all #… w/ macports readline", + "cwd": "${workspaceFolder}", + "program": "./calc", + "env": { + "DYLD_LIBRARY_PATH": ".", + }, + "preRunCommands": [ + "command script import .vscode/launch/_env.py .vscode/launch/env.py", + ], + "args": ["-Cpf", "custom/pfe-launch.cal"], + }, + ] +} \ No newline at end of file diff --git a/.vscode/launch/.env b/.vscode/launch/.env new file mode 100644 index 000000000..5b09ebe8a --- /dev/null +++ b/.vscode/launch/.env @@ -0,0 +1,8 @@ + +# customized dotenv format allowing for any space in key to align keys and values but retain any space in values + +# general + verbose =1 +# specific + wait =1 + leaks =0 \ No newline at end of file diff --git a/.vscode/launch/_env.py b/.vscode/launch/_env.py new file mode 100644 index 000000000..2984bb24f --- /dev/null +++ b/.vscode/launch/_env.py @@ -0,0 +1,3 @@ +import os + +os.environ['ENV_PY'] = '.vscode/launch/.env' diff --git a/.vscode/launch/env.py b/.vscode/launch/env.py new file mode 100644 index 000000000..f6c50003f --- /dev/null +++ b/.vscode/launch/env.py @@ -0,0 +1,25 @@ +import sys +import os +import re +import lldb +#from pprint import pprint + +class EnvPyFormatException(Exception): + pass + +env_array = [] + +with open(os.path.join(os.environ['ENV_PY'])) as file: + for line in file: + if not re.match("^\s*(#.*)?$" , line): + if m := re.match("^\s*(?P\S+)\s*=(?P.*)$" , line): + env_array.append(m.group('key')+"="+m.group('value')) + else: + raise EnvPyFormatException("Line doesn't match ` `, ` # comment` or ` key =value` where space is optional:" + , line) + +target = lldb.debugger.GetSelectedTarget() + +launch_info = target.GetLaunchInfo() +launch_info.SetEnvironmentEntries(env_array, True) +target.SetLaunchInfo(launch_info) diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..087abd3f2 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,19 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "compiledb make clobber all #… w/ macports readline", + "type": "shell", + "command": "~/Library/Python/3.8/bin/compiledb make clobber all READLINE_INCLUDE=' -I/opt/local/include/readline' READLINE_LIB=' -L/opt/local/lib -l''readline'", + "problemMatcher": ["$gcc"] + }, + { + "label": "compiledb make clobber all #DEBUG=… w/ macports readline", + "type": "shell", + "command": "~/Library/Python/3.8/bin/compiledb make clobber all DEBUG='-O0 -g' READLINE_INCLUDE=' -I/opt/local/include/readline' READLINE_LIB=' -L/opt/local/lib -l''readline'", + "problemMatcher": ["$gcc"] + }, + ] +} \ No newline at end of file diff --git a/compile_flags.txt b/compile_flags.txt new file mode 100644 index 000000000..8f91f619b --- /dev/null +++ b/compile_flags.txt @@ -0,0 +1,2 @@ +-DCALC_SRC +-DCUSTOM diff --git a/custom/pfe+conf.cal b/custom/pfe+conf.cal new file mode 100644 index 000000000..2761d68e8 --- /dev/null +++ b/custom/pfe+conf.cal @@ -0,0 +1,11 @@ + + ; _ = config("resource_debug" ,0) +## ; _ = config("trace" ,2) + ; _ = config("tilde" ,0) + ; _ = config("display" ,8) + + ; define inputname ( ) = custom("inputname" ) + ; define dirname (path ) = custom("dirname",path ) + ; p = strcat(dirname(inputname()),"/pfe.cal" ) + ;read $p + diff --git a/custom/pfe-dev.cal b/custom/pfe-dev.cal new file mode 100644 index 000000000..1c2d8265d --- /dev/null +++ b/custom/pfe-dev.cal @@ -0,0 +1,203 @@ + ##//cspell:ignore strprintf + + ; _ = config("resource_debug" ,0) + ; define inputname ( ) = custom("inputname" ) + ; define dirname (path ) = custom("dirname",path ) + ; p = strcat(dirname(inputname()),"/pfe+conf.cal" ) + ;read $p + + ; NULL = null() + ; TRUE = 1 + ; FALSE = 0 + + ; err = 2 + ; out = 1 + ; in = 0 + + ; LEAKS = eval(getenv("leaks" )||"" ) + + ; WRITE = eval(getenv("write" )||"1" ) + ; WAIT = eval(getenv("wait" )||"" ) + + ; v = eval(getenv("verbose" )||"" ) + + ; di = pipe() ##// dn in + ; uo = pipe() ##// up out + ; ue = pipe() ##// up err + + ;if( pid = fork()){ + ; e = close ( di[ in ] ) + ; e = close ( ue[ out ] ) + ; e = close ( uo[ out ] ) + /* + ; wtl = list ( di[ out ] ) + ; s = fds (null(),wtl) + ; print "parent wtl bef. wt:":wtl + /**/##end + ; if( v) print "parent writing to child" + ;if( WRITE + ) c = wt ( di[ out ] ,"parent to child") + ; e = close ( di[ out ] ) + /* + ; rcl = list ( uo[ in ] + , ue[ in ] ) + ; s = fds \ + ( rcl ) + ; print "parent rcl aft. wt bef. sleep:":rcl + + ; s = 1 + ; sleep ( s) + + ; rcl = list ( uo[ in ] + , ue[ in ] ) + ; s = fds \ + ( rcl ) + ; print "parent rcl bef. rd:":rcl + /**/##end + ; rbl = list ( uo[ in ] + , ue[ in ] ) ##// read base list + ; s = -1 + ;while( rbz = size \ + ( rbl ) ){ + /**/ + ;if( v && s == -1 + ) s\ + = WAIT + ;else if( s){ + ; if( v) printf( "parent ------ sleep %d; read base size %d\n" + , s + , rbz ) + ; sleep ( s ) ;} + /**/##end + ; rcl\ + = rbl ##// read check list + ; exl = list ( uo[ in ] + , ue[ in ] ) + ; if( v) print "parent before select" + (! WAIT + ?"" :strprintf ( " waiting %f" + , WAIT/2)) + /**/ + ; fdc\ + = fds\ + ( & rcl,! WAIT + ? NULL: WAIT/2) + /*##else + ; fdc\ + = fds\ + ( rcl + , NULL + , exl, WAIT) + /**/##end + ;if(0 < fdc ){ + ; rcz = size \ + ( rcl ) ; + ; if( v) print "parent select read size"\ + : ":" rcz ; + ;for( rcs = 0 + ; rcs + < rcz + ; rcs++){ + ; if( v) print "parent select read "\ + : rcs \ + :":" \ + : rcl \ + [ rcs] ; + ; rcd = rd \ + ( rcl + [ rcs]) + ;if( rcl + [ rcs] + == uo[ in ] + )if( rcd!=NULL) print ##"out:\n" + : rcd: + else{ delete \ + ( rbl + , search + (rbl, uo[ in ])) + ; if( v) print "parent read eof - child out" + ;} + ;if( rcl + [ rcs] + == ue[ in ] + )if( rcd!=NULL) print ##"err:\n" + : rcd: + else{ delete \ + ( rbl + , search + (rbl, ue[ in ])) + ; if( v) print "parent read eof - child err" + ;} + ;} + /* + ; exz = size \ + ( exl ) ; + ; print "parent select exception size"\ + : ":" exz ; + ;for( exs = 0 + ; exs + < exz + ; exs++){ + ; print "parent select exception "\ + : exs \ + :":" \ + : exl \ + [ exs] ; + ;} + /**/##end + ;} + ;} + ; stt = assoc() + ; w = wait4(pid,& stt) + ;if( v && stt["exited" ] ){ + ; print "parent: child exited with status" + :" ": stt["exitstatus"];} + ;if( v && stt["signaled" ] ){ + ; print "parent: child signaled by " + : stt["termsig" ] + : ( stt["coredump" ] + ? " (with dump)" + : " (no dump)" ) ;} + ;if( v && stt["stopped" ] ){ + ; print "parent: child stopped by " + : stt["stopsig" ] ;} + ;print "stt" \ + : (! stt["exited" ] + ?0: stt["exitstatus"] ) + + (! stt["stopped" ] + ?0: 127+stt["stopsig" ] ) + + (! stt["signaled" ] + ?0: 127+stt["termsig" ] ) + ;}\ + else{ + ; e = close ( uo[ in ] ) + ; e = close ( ue[ in ] ) + ; e = close ( di[ out ] ) + + ; scpt\ + = strprintf("read; echo \"outA:$REPLY\"; echo 'errA' >&2;%s echo 'outZ'; exec >&-; echo 'errZ' >&2; exec 2>&-;exit 2" + , ! WAIT ? "" : strprintf(" sleep %d;" + , floor ( WAIT*2.5) )) + ; if( v) print scpt + + ; args = list\ + ( "bash" + , "-c") + ; append ( args, scpt) + + ; d = dup2 ( di[ in ] + , in ) + ; d = dup2 ( uo[ out ] + , out ) + ; d = dup2 ( ue[ out ] + , err ) + + ; e = execvp ( args[0] + , args) + + ;} + + ;if( LEAKS ){ + ; print getpid() + ; rd ( in ) + ;} \ No newline at end of file diff --git a/custom/pfe-launch.cal b/custom/pfe-launch.cal new file mode 100644 index 000000000..91d330cee --- /dev/null +++ b/custom/pfe-launch.cal @@ -0,0 +1,8 @@ + ; null( config("resource_debug" ,0)) + ; define inputname ( ) = custom("inputname" ) + ; define dirname (path ) = custom("dirname",path ) + ; p = strcat(dirname(inputname()),"/pfe+conf.cal" ) + ;read $p + + ;pfe_test() + diff --git a/custom/pfe-v.cal b/custom/pfe-v.cal new file mode 100644 index 000000000..f47d28f9c --- /dev/null +++ b/custom/pfe-v.cal @@ -0,0 +1,12 @@ + ; null( config("resource_debug" ,0)); + ; define inputname ( ) = custom("inputname" ) + ; define dirname (path ) = custom("dirname",path ) + ; p = strcat(dirname(inputname()),"/pfe+conf.cal" ) + ;read $p + + ##// executing personal file with `#!/usr/bin/env bash` in dirs under PATH; vbash cause-of vscode fails to retrieve env (for PATH) + ;define vbhu(a1,a2,a3,a4,a5){local i,o,e,z,s,args=list("/Users/vike/shell/library/script/system/vbash","vbhu",a1,a2,a3,a4,a5);for(z=size(args),s=0;s1))&&f=-v||f=+conf;};}&&cd1 /∂/git/calc custom/pfe-v.sh custom/pfe$f.cal "$(((dev))||([[ ${test+?} ]]&&echo ";pfe${test:+_$test}_test()"))$(((dev>1))||echo ';custom("help","pfe")')") From 1d70a1fda2d830882430240b9c2152fd167db16f Mon Sep 17 00:00:00 2001 From: vike Date: Thu, 11 Jul 2024 16:44:30 +0200 Subject: [PATCH 03/21] =?UTF-8?q?fixing=20`(char*)=E2=80=A6->v=5Fstr`=20by?= =?UTF-8?q?=20appending=20`->s=5Fstr`=20in=20custom/c=5Fhelp.c,=20and=20sy?= =?UTF-8?q?mlinking=20custhelp=20for=20uninstalled=20testing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- custhelp | 1 + custom/c_help.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 120000 custhelp diff --git a/custhelp b/custhelp new file mode 120000 index 000000000..8f4052a5c --- /dev/null +++ b/custhelp @@ -0,0 +1 @@ +custom \ No newline at end of file diff --git a/custom/c_help.c b/custom/c_help.c index 21cca1255..a3f71eb9d 100644 --- a/custom/c_help.c +++ b/custom/c_help.c @@ -88,7 +88,7 @@ c_help(char *UNUSED(name), int UNUSED(count), VALUE **vals) /* * give the help */ - customhelp((char *)vals[0]->v_str); + customhelp((char *)vals[0]->v_str->s_str); /* * return NULL From 70d93c2db3c472e35c244b6dc8ef42fead2b4599 Mon Sep 17 00:00:00 2001 From: vike Date: Thu, 11 Jul 2024 16:44:42 +0200 Subject: [PATCH 04/21] fixing file.h includes --- file.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/file.h b/file.h index d03d1faf3..ad8811fb3 100644 --- a/file.h +++ b/file.h @@ -31,9 +31,13 @@ #define INCLUDE_FILE_H +#include + #if defined(CALC_SRC) /* if we are building from the calc source tree */ +# include "value.h" # include "have_fgetsetpos.h" #else +# include # include #endif From 2d89d7f8823c814595a8d4addf367b03b62ee126 Mon Sep 17 00:00:00 2001 From: vike Date: Thu, 11 Jul 2024 20:39:58 +0200 Subject: [PATCH 05/21] removing custom *pfe* development files --- .gitignore | 2 + .vscode/launch.json | 52 ----------- .vscode/launch/.env | 8 -- .vscode/launch/_env.py | 3 - .vscode/launch/env.py | 25 ----- .vscode/tasks.json | 19 ---- compile_flags.txt | 2 - custom/pfe+conf.cal | 11 --- custom/pfe-dev.cal | 203 ----------------------------------------- custom/pfe-launch.cal | 8 -- custom/pfe-v.cal | 12 --- custom/pfe-v.sh | 24 ----- 12 files changed, 2 insertions(+), 367 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/launch/.env delete mode 100644 .vscode/launch/_env.py delete mode 100644 .vscode/launch/env.py delete mode 100644 .vscode/tasks.json delete mode 100644 compile_flags.txt delete mode 100644 custom/pfe+conf.cal delete mode 100644 custom/pfe-dev.cal delete mode 100644 custom/pfe-launch.cal delete mode 100644 custom/pfe-v.cal delete mode 100755 custom/pfe-v.sh diff --git a/.gitignore b/.gitignore index 03afefaa7..3156aeeec 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ custom/.all custom/libcustcalc* custom/.gitignore compile_commands.json +compile_flags.txt debug.out .dynamic endian @@ -187,4 +188,5 @@ unused_tmp ustat_tmp ver_calc vs_tmp +.vscode win32/ diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index fe8c265f7..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "lldb", - "request": "launch", - "name": "lldb launch", - "cwd": "${workspaceFolder}", - "program": "./calc", - "env": { - "DYLD_LIBRARY_PATH": ".", - }, - "preRunCommands": [ - "command script import .vscode/launch/_env.py .vscode/launch/env.py", - ], - "args": ["-Cpf", "custom/pfe-launch.cal"], - }, - { - "preLaunchTask": "compiledb make clobber all #DEBUG=… w/ macports readline", - "type": "lldb", - "request": "launch", - "name": "lldb launch + compiledb make clobber all #DEBUG=… w/ macports readline", - "cwd": "${workspaceFolder}", - "program": "./calc", - "env": { - "DYLD_LIBRARY_PATH": ".", - }, - "preRunCommands": [ - "command script import .vscode/launch/_env.py .vscode/launch/env.py", - ], - "args": ["-Cpf", "custom/pfe-launch.cal"], - }, - { - "preLaunchTask": "compiledb make clobber all #… w/ macports readline", - "type": "lldb", - "request": "launch", - "name": "lldb launch + compiledb make clobber all #… w/ macports readline", - "cwd": "${workspaceFolder}", - "program": "./calc", - "env": { - "DYLD_LIBRARY_PATH": ".", - }, - "preRunCommands": [ - "command script import .vscode/launch/_env.py .vscode/launch/env.py", - ], - "args": ["-Cpf", "custom/pfe-launch.cal"], - }, - ] -} \ No newline at end of file diff --git a/.vscode/launch/.env b/.vscode/launch/.env deleted file mode 100644 index 5b09ebe8a..000000000 --- a/.vscode/launch/.env +++ /dev/null @@ -1,8 +0,0 @@ - -# customized dotenv format allowing for any space in key to align keys and values but retain any space in values - -# general - verbose =1 -# specific - wait =1 - leaks =0 \ No newline at end of file diff --git a/.vscode/launch/_env.py b/.vscode/launch/_env.py deleted file mode 100644 index 2984bb24f..000000000 --- a/.vscode/launch/_env.py +++ /dev/null @@ -1,3 +0,0 @@ -import os - -os.environ['ENV_PY'] = '.vscode/launch/.env' diff --git a/.vscode/launch/env.py b/.vscode/launch/env.py deleted file mode 100644 index f6c50003f..000000000 --- a/.vscode/launch/env.py +++ /dev/null @@ -1,25 +0,0 @@ -import sys -import os -import re -import lldb -#from pprint import pprint - -class EnvPyFormatException(Exception): - pass - -env_array = [] - -with open(os.path.join(os.environ['ENV_PY'])) as file: - for line in file: - if not re.match("^\s*(#.*)?$" , line): - if m := re.match("^\s*(?P\S+)\s*=(?P.*)$" , line): - env_array.append(m.group('key')+"="+m.group('value')) - else: - raise EnvPyFormatException("Line doesn't match ` `, ` # comment` or ` key =value` where space is optional:" - , line) - -target = lldb.debugger.GetSelectedTarget() - -launch_info = target.GetLaunchInfo() -launch_info.SetEnvironmentEntries(env_array, True) -target.SetLaunchInfo(launch_info) diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 087abd3f2..000000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "compiledb make clobber all #… w/ macports readline", - "type": "shell", - "command": "~/Library/Python/3.8/bin/compiledb make clobber all READLINE_INCLUDE=' -I/opt/local/include/readline' READLINE_LIB=' -L/opt/local/lib -l''readline'", - "problemMatcher": ["$gcc"] - }, - { - "label": "compiledb make clobber all #DEBUG=… w/ macports readline", - "type": "shell", - "command": "~/Library/Python/3.8/bin/compiledb make clobber all DEBUG='-O0 -g' READLINE_INCLUDE=' -I/opt/local/include/readline' READLINE_LIB=' -L/opt/local/lib -l''readline'", - "problemMatcher": ["$gcc"] - }, - ] -} \ No newline at end of file diff --git a/compile_flags.txt b/compile_flags.txt deleted file mode 100644 index 8f91f619b..000000000 --- a/compile_flags.txt +++ /dev/null @@ -1,2 +0,0 @@ --DCALC_SRC --DCUSTOM diff --git a/custom/pfe+conf.cal b/custom/pfe+conf.cal deleted file mode 100644 index 2761d68e8..000000000 --- a/custom/pfe+conf.cal +++ /dev/null @@ -1,11 +0,0 @@ - - ; _ = config("resource_debug" ,0) -## ; _ = config("trace" ,2) - ; _ = config("tilde" ,0) - ; _ = config("display" ,8) - - ; define inputname ( ) = custom("inputname" ) - ; define dirname (path ) = custom("dirname",path ) - ; p = strcat(dirname(inputname()),"/pfe.cal" ) - ;read $p - diff --git a/custom/pfe-dev.cal b/custom/pfe-dev.cal deleted file mode 100644 index 1c2d8265d..000000000 --- a/custom/pfe-dev.cal +++ /dev/null @@ -1,203 +0,0 @@ - ##//cspell:ignore strprintf - - ; _ = config("resource_debug" ,0) - ; define inputname ( ) = custom("inputname" ) - ; define dirname (path ) = custom("dirname",path ) - ; p = strcat(dirname(inputname()),"/pfe+conf.cal" ) - ;read $p - - ; NULL = null() - ; TRUE = 1 - ; FALSE = 0 - - ; err = 2 - ; out = 1 - ; in = 0 - - ; LEAKS = eval(getenv("leaks" )||"" ) - - ; WRITE = eval(getenv("write" )||"1" ) - ; WAIT = eval(getenv("wait" )||"" ) - - ; v = eval(getenv("verbose" )||"" ) - - ; di = pipe() ##// dn in - ; uo = pipe() ##// up out - ; ue = pipe() ##// up err - - ;if( pid = fork()){ - ; e = close ( di[ in ] ) - ; e = close ( ue[ out ] ) - ; e = close ( uo[ out ] ) - /* - ; wtl = list ( di[ out ] ) - ; s = fds (null(),wtl) - ; print "parent wtl bef. wt:":wtl - /**/##end - ; if( v) print "parent writing to child" - ;if( WRITE - ) c = wt ( di[ out ] ,"parent to child") - ; e = close ( di[ out ] ) - /* - ; rcl = list ( uo[ in ] - , ue[ in ] ) - ; s = fds \ - ( rcl ) - ; print "parent rcl aft. wt bef. sleep:":rcl - - ; s = 1 - ; sleep ( s) - - ; rcl = list ( uo[ in ] - , ue[ in ] ) - ; s = fds \ - ( rcl ) - ; print "parent rcl bef. rd:":rcl - /**/##end - ; rbl = list ( uo[ in ] - , ue[ in ] ) ##// read base list - ; s = -1 - ;while( rbz = size \ - ( rbl ) ){ - /**/ - ;if( v && s == -1 - ) s\ - = WAIT - ;else if( s){ - ; if( v) printf( "parent ------ sleep %d; read base size %d\n" - , s - , rbz ) - ; sleep ( s ) ;} - /**/##end - ; rcl\ - = rbl ##// read check list - ; exl = list ( uo[ in ] - , ue[ in ] ) - ; if( v) print "parent before select" - (! WAIT - ?"" :strprintf ( " waiting %f" - , WAIT/2)) - /**/ - ; fdc\ - = fds\ - ( & rcl,! WAIT - ? NULL: WAIT/2) - /*##else - ; fdc\ - = fds\ - ( rcl - , NULL - , exl, WAIT) - /**/##end - ;if(0 < fdc ){ - ; rcz = size \ - ( rcl ) ; - ; if( v) print "parent select read size"\ - : ":" rcz ; - ;for( rcs = 0 - ; rcs - < rcz - ; rcs++){ - ; if( v) print "parent select read "\ - : rcs \ - :":" \ - : rcl \ - [ rcs] ; - ; rcd = rd \ - ( rcl - [ rcs]) - ;if( rcl - [ rcs] - == uo[ in ] - )if( rcd!=NULL) print ##"out:\n" - : rcd: - else{ delete \ - ( rbl - , search - (rbl, uo[ in ])) - ; if( v) print "parent read eof - child out" - ;} - ;if( rcl - [ rcs] - == ue[ in ] - )if( rcd!=NULL) print ##"err:\n" - : rcd: - else{ delete \ - ( rbl - , search - (rbl, ue[ in ])) - ; if( v) print "parent read eof - child err" - ;} - ;} - /* - ; exz = size \ - ( exl ) ; - ; print "parent select exception size"\ - : ":" exz ; - ;for( exs = 0 - ; exs - < exz - ; exs++){ - ; print "parent select exception "\ - : exs \ - :":" \ - : exl \ - [ exs] ; - ;} - /**/##end - ;} - ;} - ; stt = assoc() - ; w = wait4(pid,& stt) - ;if( v && stt["exited" ] ){ - ; print "parent: child exited with status" - :" ": stt["exitstatus"];} - ;if( v && stt["signaled" ] ){ - ; print "parent: child signaled by " - : stt["termsig" ] - : ( stt["coredump" ] - ? " (with dump)" - : " (no dump)" ) ;} - ;if( v && stt["stopped" ] ){ - ; print "parent: child stopped by " - : stt["stopsig" ] ;} - ;print "stt" \ - : (! stt["exited" ] - ?0: stt["exitstatus"] ) - + (! stt["stopped" ] - ?0: 127+stt["stopsig" ] ) - + (! stt["signaled" ] - ?0: 127+stt["termsig" ] ) - ;}\ - else{ - ; e = close ( uo[ in ] ) - ; e = close ( ue[ in ] ) - ; e = close ( di[ out ] ) - - ; scpt\ - = strprintf("read; echo \"outA:$REPLY\"; echo 'errA' >&2;%s echo 'outZ'; exec >&-; echo 'errZ' >&2; exec 2>&-;exit 2" - , ! WAIT ? "" : strprintf(" sleep %d;" - , floor ( WAIT*2.5) )) - ; if( v) print scpt - - ; args = list\ - ( "bash" - , "-c") - ; append ( args, scpt) - - ; d = dup2 ( di[ in ] - , in ) - ; d = dup2 ( uo[ out ] - , out ) - ; d = dup2 ( ue[ out ] - , err ) - - ; e = execvp ( args[0] - , args) - - ;} - - ;if( LEAKS ){ - ; print getpid() - ; rd ( in ) - ;} \ No newline at end of file diff --git a/custom/pfe-launch.cal b/custom/pfe-launch.cal deleted file mode 100644 index 91d330cee..000000000 --- a/custom/pfe-launch.cal +++ /dev/null @@ -1,8 +0,0 @@ - ; null( config("resource_debug" ,0)) - ; define inputname ( ) = custom("inputname" ) - ; define dirname (path ) = custom("dirname",path ) - ; p = strcat(dirname(inputname()),"/pfe+conf.cal" ) - ;read $p - - ;pfe_test() - diff --git a/custom/pfe-v.cal b/custom/pfe-v.cal deleted file mode 100644 index f47d28f9c..000000000 --- a/custom/pfe-v.cal +++ /dev/null @@ -1,12 +0,0 @@ - ; null( config("resource_debug" ,0)); - ; define inputname ( ) = custom("inputname" ) - ; define dirname (path ) = custom("dirname",path ) - ; p = strcat(dirname(inputname()),"/pfe+conf.cal" ) - ;read $p - - ##// executing personal file with `#!/usr/bin/env bash` in dirs under PATH; vbash cause-of vscode fails to retrieve env (for PATH) - ;define vbhu(a1,a2,a3,a4,a5){local i,o,e,z,s,args=list("/Users/vike/shell/library/script/system/vbash","vbhu",a1,a2,a3,a4,a5);for(z=size(args),s=0;s1))&&f=-v||f=+conf;};}&&cd1 /∂/git/calc custom/pfe-v.sh custom/pfe$f.cal "$(((dev))||([[ ${test+?} ]]&&echo ";pfe${test:+_$test}_test()"))$(((dev>1))||echo ';custom("help","pfe")')") From 6217a66455b8368977f8958710f44b7d03297f17 Mon Sep 17 00:00:00 2001 From: vike Date: Thu, 11 Jul 2024 20:54:42 +0200 Subject: [PATCH 06/21] removing ~chongo specifics from custom/pfe help file --- custom/pfe | 6 ------ 1 file changed, 6 deletions(-) diff --git a/custom/pfe b/custom/pfe index d58e93f95..fe4d85071 100755 --- a/custom/pfe +++ b/custom/pfe @@ -83,9 +83,3 @@ SEE ALSO ## distributed with calc under the filename COPYING-LGPL. You should have ## received a copy with calc; if not, write to Free Software Foundation, Inc. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -## -## Under source code control: 1997/03/09 20:28:01 -## File existed as early as: 1997 -## -## chongo /\oo/\ http://www.isthe.com/chongo/ -## Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/ From fb70358a0ff1633173790ea46c3a53eb25632595 Mon Sep 17 00:00:00 2001 From: vike Date: Thu, 11 Jul 2024 23:58:49 +0200 Subject: [PATCH 07/21] fixing some formatting in custom/pfe.cal --- custom/pfe.cal | 266 ++++++++++++++++++++++--------------------------- 1 file changed, 119 insertions(+), 147 deletions(-) diff --git a/custom/pfe.cal b/custom/pfe.cal index 091546800..5c8c84143 100644 --- a/custom/pfe.cal +++ b/custom/pfe.cal @@ -33,167 +33,139 @@ if (config("compile_custom") == 0) { define pfe_base_test() { - local file; - local fork = custom("fork"); - local fds = custom("pipe"); - if( fork){ - if( custom("write", fds[1], "test" )!=4) quit "error in write"; - if( custom("close", fds[1] ) ) quit "error in close"; - local rd = custom("read", fds[0] ); - local status = assoc - () ; custom("wait4", &status ); - if( rd != "test" ){ - file = fopen("/dev/stderr","w"); - fprintf(file,"mismatch of read: %s\n", rd); + local file; + local fork = custom("fork"); + local fds = custom("pipe"); + if (fork) { + if (custom("write", fds[1], "test") != 4) quit "error in write"; + if (custom("close", fds[1])) quit "error in close"; + local rd = custom("read", fds[0]); + local status = assoc(); + custom("wait4", &status); + if (rd != "test") { + file = fopen("/dev/stderr", "w"); + fprintf(file, "mismatch of read: %s\n", rd); quit; } - if( status - ["exitstatus"]!= 0 ){ - file = fopen("/dev/stderr","w"); - fprintf(file,"mismatch of status: %d\n", status); + if (status["exitstatus"] != 0) { + file = fopen("/dev/stderr", "w"); + fprintf(file, "mismatch of status: %d\n", status); quit; } } else { - if( custom("close", fds[1]) ) quit "error in close"; - local args = list("sh", "-c", "{ read||:;}&&printf %s $REPLY"); - if( 0 > custom("dup2", fds[0],0 ) ) quit "error in dup2"; - if( ! custom("execvp", args[0], args ) ) quit "error in execvp"; + if (custom("close", fds[1])) quit "error in close"; + local args = list("sh", "-c", "{ read||:;}&&printf %s $REPLY"); + if (0 > custom("dup2", fds[0], 0)) quit "error in dup2"; + if (!custom("execvp", args[0], args)) quit "error in execvp"; } } - ; define pipe ( ) = custom("pipe" ) - ; define fork ( ) = custom("fork" ) - ; define close (fd ) = custom("close" ,fd ) - ; define fds (rdl,wtl,exl,timeout) = custom("select" ,rdl,wtl,exl,timeout) - ; define poll ( in,out ,timeout) = custom("poll" , in,out ,timeout) - ; define dup (src ) = custom("dup" ,src ) - ; define dup2 (src,tgt ) = custom("dup2" ,src,tgt ) - ; define execvp (path,args ) = custom("execvp" ,path,args ) - ; define wt (fd,str ) = custom("write" ,fd,str ) - ; define rd (fd ) = custom("read" ,fd ) - ; define wait4 (pid,stt,opt,usg ) = custom("wait4" ,pid,stt,opt,usg ) - - ; define pfe (in,out,err,args ) = custom("pfe" ,in,out,err,args ) - ; define pwrite (fd,str ) = custom("pwrite" ,fd,str ) - ; define pread (pid,out,err ) = custom("pread" ,pid,out,err ) +define pipe() = custom("pipe"); +define fork() = custom("fork"); +define close(fd) = custom("close", fd); +define fds(rdl, wtl, exl, timeout) = custom("select", rdl, wtl, exl, timeout); +define poll(in, out, timeout) = custom("poll", in, out, timeout); +define dup(src) = custom("dup", src); +define dup2(src, tgt) = custom("dup2", src, tgt); +define execvp(path, args) = custom("execvp", path, args); +define wt(fd, str) = custom("write", fd, str); +define rd(fd) = custom("read", fd); +define wait4(pid, stt, opt, usg) = custom("wait4", pid, stt, opt, usg); + +define pfe(in, out, err, args) = custom("pfe", in, out, err, args); +define pwrite(fd, str) = custom("pwrite", fd, str); +define pread(pid, out, err) = custom("pread", pid, out, err); + +define pfe_test() { + local r p i o e; + if (p = pfe(&i, &o, &e, list("sh", "-c", "read -rd '' || e=$?; printf %s \"$REPLY\""))) { + if (pwrite(i, "test\n") != 5) quit "bad write"; + r = pread(p, o, e); + if (r[0] != 0 ) quit "bad exit"; + if (r[1] != "test\n") quit "bad read"; + } +} + +define pfe_cal(in, out, err, args) { + local di = pipe(); ##// dn in + local uo = pipe(); ##// up out + local ue = pipe(); ##// up err - ; define pfe_test(){ - ; local r p i o e - ;if( p = pfe(& i,& o,& e,list("sh","-c","read -rd ''||e=$?;printf %s \"$REPLY\""))){ - ;if( pwrite( i,"test\n") != 5 ) quit "bad write" - ; r = pread(p, o, e) - ;if( r[0] != 0 ) quit "bad exit" - ;if( r[1] !="test\n" ) quit "bad read" - ;} - ;} + *in = di[1]; + *out = uo[0]; + *err = ue[0]; - ; define pfe_cal (in,out,err,args ){ - ; local di = pipe() ##// dn in - ; local uo = pipe() ##// up out - ; local ue = pipe() ##// up err + local e pid; + if (pid = fork()) { + if (close(di[0])) quit "pfe: error in parent closing reading child input"; + if (close(ue[1])) quit "pfe: error in parent closing writing child output"; + if (close(uo[1])) quit "pfe: error in parent closing writing child error"; - ; *in = di[ 1 ] - ; *out= uo[ 0 ] - ; *err= ue[ 0 ] + return pid; + } else { + if (close(uo[0])) quit "pfe: error in child closing reading output"; + if (close(ue[0])) quit "pfe: error in child closing reading error"; + if (close(di[1])) quit "pfe: error in child closing writing input"; - ; local e pid - ;if( pid = fork()){ - ;if( close ( di[ 0 ] ) ) quit "pfe: error in parent closing reading child input" - ;if( close ( ue[ 1 ] ) ) quit "pfe: error in parent closing writing child output" - ;if( close ( uo[ 1 ] ) ) quit "pfe: error in parent closing writing child error" - - ; return pid;} - else{ - ;if( close ( uo[ 0 ] ) ) quit "pfe: error in child closing reading output" - ;if( close ( ue[ 0 ] ) ) quit "pfe: error in child closing reading error" - ;if( close ( di[ 1 ] ) ) quit "pfe: error in child closing writing input" - - ;if( dup2 ( di[ 0 ],0)!=0 ) quit "pfe: mismatch in child duplication of input" - ;if( dup2 ( uo[ 1 ],1)!=1 ) quit "pfe: mismatch in child duplication of output" - ;if( dup2 ( ue[ 1 ],2)!=2 ) quit "pfe: mismatch in child duplication of error" - - ; e = execvp ( args[0] - , args );} - ;} - ; define pwrite_cal( in, str ){ - ; local w = wt ( in, str ) - ;if( w != strlen ( str ) ) quit "pwrite: mismatch" - ;if( close ( in ) ) quit "pwrite: error closing" - ;return w;} - ; define pread_cal( pid,out - , err ){ - ; local NULL= null () + if (dup2(di[0], 0) != 0) quit "pfe: mismatch in child duplication of input"; + if (dup2(uo[1], 1) != 1) quit "pfe: mismatch in child duplication of output"; + if (dup2(ue[1], 2) != 2) quit "pfe: mismatch in child duplication of error"; - ; local rbl = list ( out - , err ) ##// read base list + e = execvp(args[0], args); + } +;} +define pwrite_cal(in, str) { + local w = wt(in, str); + if (w != strlen(str)) quit "pwrite: mismatch"; + if (close(in)) quit "pwrite: error closing"; + return w; +} +define pread_cal(pid, out, err) { + local NULL = null(); + + local rbl = list(out, err); ##// read base list + + local oud = ""; ##// out data + local erd = ""; ##// err data + + while (local rbz = size(rbl)) { + local rcl = rbl; ##// read check list + local exl = list(out, err); - ; local oud = "" ##//out data - ; local erd = "" ##//err data + local fdc = fds(&rcl); - ;while( local rbz = size - ( rbl ) ){ - ; local rcl - = rbl ##// read check list - ; local exl = list ( out - , err ) - - ; local fdc - = fds - ( & rcl ) + if (0 < fdc) { + local rcz = size(rcl); - ;if(0 < fdc ){ - ; local rcz = size - ( rcl ) ; + for (local rcs = 0; rcz > rcs; rcs++) { - ;for( local rcs = 0 - ; rcz>rcs - ; rcs++){ - - ; local rcd = rd - ( rcl[rcs]) - ;if( rcl[rcs] - == out - )if( rcd!=NULL - ) oud=strcat - ( oud - , rcd) - else delete - ( rbl - , search - (rbl, out)) ; - ;if( rcl[rcs] - == err - )if( rcd!=NULL - ) erd=strcat - ( erd - , rcd) - else delete - ( rbl - , search - (rbl, err)) ; - ;} - ;} - ;} - ; local stt = assoc() - ; pid = wait4( pid - ,& stt) - ;return list - ( (! stt["exited" ] - ?0: stt["exitstatus"] ) - + (! stt["stopped" ] - ?0: 128+stt["stopsig" ] ) - + (! stt["signaled" ] - ?0: 128+stt["termsig" ] ) - , oud - , erd );} - - ; define pfe_cal_test(){ - ; local r p i o e - ;if( p = pfe_cal(& i,& o,& e,list("sh","-c","read -rd ''||e=$?;printf %s \"$REPLY\""))){ - ;if( pwrite_cal( i,"test\n") != 5 ) quit "bad write" - ; r = pread_cal(p, o, e) - ;if( r[0] != 0 ) quit "bad exit" - ;if( r[1] !="test\n" ) quit "bad read" - ;} - ;} - + local rcd = rd(rcl[rcs]); + if (rcl[rcs] == out) + if (rcd != NULL) oud = strcat(oud, rcd); + else delete(rbl, search(rbl, out)); + if (rcl[rcs] == err) + if (rcd != NULL) erd = strcat(erd, rcd); + else delete(rbl, search(rbl, err)); + } + } + } + local stt = assoc(); + pid = wait4(pid, &stt); + return list( + (!stt["exited"] ? 0 : stt["exitstatus"]) + + (!stt["stopped"] ? 0 : 128 + stt["stopsig"]) + + (!stt["signaled"] ? 0 : 128 + stt["termsig"]), + oud, erd + ); +} + +define pfe_cal_test() { + local r p i o e; + if (p = pfe_cal(&i, &o, &e, list("sh", "-c", "read -rd '' || e=$?; printf %s \"$REPLY\""))) { + if (pwrite_cal(i, "test\n") != 5) quit "bad write"; + r = pread_cal(p, o, e); + if (r[0] != 0) quit "bad exit"; + if (r[1] != "test\n") quit "bad read"; + } +} + From 6d25ccc6833ae94e708d0029be6d11f8519be11d Mon Sep 17 00:00:00 2001 From: vike Date: Fri, 12 Jul 2024 00:52:29 +0200 Subject: [PATCH 08/21] fixing some formatting in custom/u_pfe.c; also removing some comments and commented out code --- custom/u_pfe.c | 143 +++++++++++++++++++++++++++---------------------- 1 file changed, 79 insertions(+), 64 deletions(-) diff --git a/custom/u_pfe.c b/custom/u_pfe.c index d2006e0a2..8bf318290 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -814,21 +814,27 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) el = el->e_next, s++ ) { - if ( el ->e_value.v_type != V_LIST ) { free(pollfds); - math_error("%s: argument %d (%s) element %d must be of type list (%s given)", - custname, 1, i_name, s, value_type2str(el->e_value)); } + if ( el ->e_value.v_type != V_LIST ) { + free(pollfds); + math_error("%s: argument %d (%s) element %d must be of type list (%s given)", + custname, 1, i_name, s, value_type2str(el->e_value)); + } LIST* el_list = el->e_value.v_list; LISTELEM* el_el; el_el = el_list->l_first; - if ( el_el ->e_value.v_type != V_NUM ) { free(pollfds); - math_error("%s: argument %d (%s) element %d element %d must be of type number (%s given)", - custname, 1, i_name, s, 1, value_type2str(el_el->e_value)); } - if (!qisint(el_el ->e_value.v_num) ) { free(pollfds); - math_error("%s: argument %d (%s) element %d element %d must be integer (%s given)", - custname, 1, i_name, s, 1, value_type2str(el_el->e_value)); } + if ( el_el ->e_value.v_type != V_NUM ) { + free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be of type number (%s given)", + custname, 1, i_name, s, 1, value_type2str(el_el->e_value)); + } + if (!qisint(el_el ->e_value.v_num) ) { + free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be integer (%s given)", + custname, 1, i_name, s, 1, value_type2str(el_el->e_value)); + } pollfds[s].fd = qtoi(el_el->e_value.v_num); pollfds[s].events = 0; @@ -841,25 +847,39 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) el_el = el_el->e_next, el_el_s++ ) { - if ( el_el ->e_value.v_type != V_STR ) { free(pollfds); - math_error("%s: argument %d (%s) element %d element %d must be of type string (%s given)", - custname, 1, i_name, s, el_el_s, value_type2str(el_el->e_value)); } + if ( el_el ->e_value.v_type != V_STR ) { + free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be of type string (%s given)", + custname, 1, i_name, s, el_el_s, value_type2str(el_el->e_value)); + } char* el_el_str = el_el->e_value.v_str->s_str; if (FALSE); // man poll|gawk 'match($0,"^\\s*POLL([A-Z]+)",m){print(tolower(m[1]))}' - else if (!strcmp(el_el_str, "err" )) pollfds[s].events |= POLLERR; - else if (!strcmp(el_el_str, "hup" )) pollfds[s].events |= POLLHUP; - else if (!strcmp(el_el_str, "in" )) pollfds[s].events |= POLLIN; - else if (!strcmp(el_el_str, "nval" )) pollfds[s].events |= POLLNVAL; //cspell:ignore nval - else if (!strcmp(el_el_str, "out" )) pollfds[s].events |= POLLOUT; - else if (!strcmp(el_el_str, "pri" )) pollfds[s].events |= POLLPRI; - else if (!strcmp(el_el_str, "rdband" )) pollfds[s].events |= POLLRDBAND; //cspell:ignore rdband - else if (!strcmp(el_el_str, "rdnorm" )) pollfds[s].events |= POLLRDNORM; //cspell:ignore rdnorm - else if (!strcmp(el_el_str, "wrband" )) pollfds[s].events |= POLLWRBAND; //cspell:ignore wrband - else if (!strcmp(el_el_str, "wrnorm" )) pollfds[s].events |= POLLWRNORM; //cspell:ignore wrnorm - else { free(pollfds); - math_error("%s: argument %d (%s) element %d element %d must be a string containing one of the event names from POSIX poll.h or the manual for poll, lowercase without poll prefix (%s given)", - custname, 1, i_name, s, el_el_s, el_el->e_value.v_str->s_str); } + else if (!strcmp(el_el_str, "err")) + pollfds[s].events |= POLLERR; + else if (!strcmp(el_el_str, "hup")) + pollfds[s].events |= POLLHUP; + else if (!strcmp(el_el_str, "in")) + pollfds[s].events |= POLLIN; + else if (!strcmp(el_el_str, "nval")) + pollfds[s].events |= POLLNVAL; //cspell:ignore nval + else if (!strcmp(el_el_str, "out")) + pollfds[s].events |= POLLOUT; + else if (!strcmp(el_el_str, "pri")) + pollfds[s].events |= POLLPRI; + else if (!strcmp(el_el_str, "rdband")) + pollfds[s].events |= POLLRDBAND; //cspell:ignore rdband + else if (!strcmp(el_el_str, "rdnorm")) + pollfds[s].events |= POLLRDNORM; //cspell:ignore rdnorm + else if (!strcmp(el_el_str, "wrband")) + pollfds[s].events |= POLLWRBAND; //cspell:ignore wrband + else if (!strcmp(el_el_str, "wrnorm")) + pollfds[s].events |= POLLWRNORM; //cspell:ignore wrnorm + else { + free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be a string containing one of the event names from POSIX poll.h or the manual for poll, lowercase without poll prefix (%s given)", + custname, 1, i_name, s, el_el_s, el_el->e_value.v_str->s_str); + } } pollfds[s].revents = 0; @@ -874,16 +894,26 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) for (s = 0; s < il->l_count; s++) { VALUE* o = alloc_assoc(assocalloc(0)); - if ((pollfds[s].revents & POLLERR ) == POLLERR ) associndex_str_int(o->v_assoc, makenewstring("err" ), POLLERR ); - if ((pollfds[s].revents & POLLHUP ) == POLLHUP ) associndex_str_int(o->v_assoc, makenewstring("hup" ), POLLHUP ); - if ((pollfds[s].revents & POLLIN ) == POLLIN ) associndex_str_int(o->v_assoc, makenewstring("in" ), POLLIN ); - if ((pollfds[s].revents & POLLNVAL ) == POLLNVAL ) associndex_str_int(o->v_assoc, makenewstring("nval" ), POLLNVAL ); - if ((pollfds[s].revents & POLLOUT ) == POLLOUT ) associndex_str_int(o->v_assoc, makenewstring("out" ), POLLOUT ); - if ((pollfds[s].revents & POLLPRI ) == POLLPRI ) associndex_str_int(o->v_assoc, makenewstring("pri" ), POLLPRI ); - if ((pollfds[s].revents & POLLRDBAND) == POLLRDBAND ) associndex_str_int(o->v_assoc, makenewstring("rdband" ), POLLRDBAND ); - if ((pollfds[s].revents & POLLRDNORM) == POLLRDNORM ) associndex_str_int(o->v_assoc, makenewstring("rdnorm" ), POLLRDNORM ); - if ((pollfds[s].revents & POLLWRBAND) == POLLWRBAND ) associndex_str_int(o->v_assoc, makenewstring("wrband" ), POLLWRBAND ); - if ((pollfds[s].revents & POLLWRNORM) == POLLWRNORM ) associndex_str_int(o->v_assoc, makenewstring("wrnorm" ), POLLWRNORM ); + if ((pollfds[s].revents & POLLERR ) == POLLERR ) + associndex_str_int(o->v_assoc, makenewstring("err" ), POLLERR ); + if ((pollfds[s].revents & POLLHUP ) == POLLHUP ) + associndex_str_int(o->v_assoc, makenewstring("hup" ), POLLHUP ); + if ((pollfds[s].revents & POLLIN ) == POLLIN ) + associndex_str_int(o->v_assoc, makenewstring("in" ), POLLIN ); + if ((pollfds[s].revents & POLLNVAL ) == POLLNVAL ) + associndex_str_int(o->v_assoc, makenewstring("nval" ), POLLNVAL ); + if ((pollfds[s].revents & POLLOUT ) == POLLOUT ) + associndex_str_int(o->v_assoc, makenewstring("out" ), POLLOUT ); + if ((pollfds[s].revents & POLLPRI ) == POLLPRI ) + associndex_str_int(o->v_assoc, makenewstring("pri" ), POLLPRI ); + if ((pollfds[s].revents & POLLRDBAND) == POLLRDBAND ) + associndex_str_int(o->v_assoc, makenewstring("rdband" ), POLLRDBAND ); + if ((pollfds[s].revents & POLLRDNORM) == POLLRDNORM ) + associndex_str_int(o->v_assoc, makenewstring("rdnorm" ), POLLRDNORM ); + if ((pollfds[s].revents & POLLWRBAND) == POLLWRBAND ) + associndex_str_int(o->v_assoc, makenewstring("wrband" ), POLLWRBAND ); + if ((pollfds[s].revents & POLLWRNORM) == POLLWRNORM ) + associndex_str_int(o->v_assoc, makenewstring("wrnorm" ), POLLWRNORM ); insertlistlast(ol, o); } @@ -1105,23 +1135,12 @@ u_pfe_pwrite(char *UNUSED(name), int count, VALUE **vals) #define pfe_pfe_SIZE_BUFFER 4096 #define pfe_pfe_SIZE_INIT 4096 - // next func is verbatim, apart from dprintf, strcat-fix->strlcat and spacing, from ~vike/∂/xcode/vmdbTx-objc/main.m //cspell:ignore strext - char * strext - ( char ** subject - , char * with - ){ // dprintf(2, "strext(s, w) wh/ |s| = %lu, |w| = %lu, |s| = “%s”, & w = “%s”\n", strlen(*subject), strlen(with), *subject, with) - ; size_t n= strlen( *subject) - + strlen( with) ;if ( ( *subject - = reallocf( *subject - , n+1) ) == NULL - ) return NULL -// ; dprintf(2, "strext(s, w) wh/ n+1 = %lu = (|s| = %lu) + (|w| = %lu) + 1, |s| = “%s”, & w = “%s”\n", n+1, strlen(*subject), strlen(with), *subject, with) - ; strlcat( *subject - , with - , n+1) // pretty useless use of strlcat but strncat and strcat are "poisoned" giving error attow (w/ -Wall I guess, I dunno), tho we just realloc'd acc2 strlen, what the heck - ; return*subject;} - -//#define u_pfe_pread_DEBUG(r, n) dprintf(2, "r = %d;will do strext("#n", "#n"b) wh/ |"#n"| = %lu, |"#n"b| = %lu, "#n" = “%s”, & "#n"b = “%s”\n", r, strlen(n), strlen(n##b), n, n##b) +char* strext(char** subject, char* with) { + size_t n = strlen(*subject) + strlen(with); + if ((*subject = reallocf(*subject, n+1)) == NULL) return NULL; + strlcat(*subject, with, n+1); + return *subject; +} /* * u_pfe_pread - read until eof, close and wait for exit status @@ -1174,7 +1193,6 @@ u_pfe_pread(char *UNUSED(name), int count, VALUE **vals) if (FD_ISSET(out, &rcs)) { r = read(out, &ob, pfe_pfe_SIZE_BUFFER); -// u_pfe_pread_DEBUG(r, o); if (r < 0) math_error("%s: "__FILE__": %d: (out, %lu) read: %s", custname, __LINE__, strlen(o), strerror(errno)); if (r) { ob[r] = '\0'; @@ -1187,7 +1205,6 @@ u_pfe_pread(char *UNUSED(name), int count, VALUE **vals) } if (FD_ISSET(err, &rcs)) { r = read(err, &eb, pfe_pfe_SIZE_BUFFER); -// u_pfe_pread_DEBUG(r, e); if (r < 0) math_error("%s: "__FILE__": %d: (err, %lu) read: %s", custname, __LINE__, strlen(e), strerror(errno)); if (r) { eb[r] = '\0'; @@ -1208,18 +1225,16 @@ u_pfe_pread(char *UNUSED(name), int count, VALUE **vals) if (0 > w) math_error("%s: "__FILE__": %d: wait4: %s", custname, __LINE__, strerror(errno)); - NUMBER* r = itoq - ( ( ! WIFEXITED (stt) - ?0: WEXITSTATUS (stt) ) - + ( ! WIFSTOPPED (stt) - ?0:128+ WSTOPSIG (stt) ) - + ( ! WIFSIGNALED (stt) - ?0:128+ WTERMSIG (stt) )); + NUMBER* r = itoq( + (!WIFEXITED(stt) ? 0 : WEXITSTATUS(stt)) + + (!WIFSTOPPED(stt) ? 0 : 128 + WSTOPSIG(stt)) + + (!WIFSIGNALED(stt) ? 0 : 128 + WTERMSIG(stt)) + ); LIST* list = listalloc(); - insertlistlast(list, alloc_num( r )); - insertlistlast(list, alloc_str(makestring( o) )); - insertlistlast(list, alloc_str(makestring( e) )); + insertlistlast(list, alloc_num(r)); + insertlistlast(list, alloc_str(makestring(o))); + insertlistlast(list, alloc_str(makestring(e))); VALUE result; result.v_subtype = 0; From f64f199103e5ea908f66de8472267d6d50b506d9 Mon Sep 17 00:00:00 2001 From: vike Date: Tue, 23 Jul 2024 23:31:07 +0200 Subject: [PATCH 09/21] textually shortening type2str and helpers w/ zero-sum on length of calls --- custom/u_pfe.c | 103 ++++++++++++++----------------------------------- 1 file changed, 30 insertions(+), 73 deletions(-) diff --git a/custom/u_pfe.c b/custom/u_pfe.c index 8bf318290..6aa6217e0 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -61,71 +61,28 @@ int u_pfe_allowed = 0; /* CUSTOM undefined */ const char* type2str(short type) { + // originally from c_argv.c switch (type) { - case V_NULL: /* null value */ - return "null"; - break; - case V_INT: /* normal integer */ - return "int"; - break; - case V_NUM: /* number */ - return "rational_value"; - break; - case V_COM: /* complex number */ - return "complex_value"; - break; - case V_ADDR: /* address of variable value */ - return "address"; - break; - case V_STR: /* address of string */ - return "string"; - break; - case V_MAT: /* address of matrix structure */ - return "matrix"; - break; - case V_LIST: /* address of list structure */ - return "list"; - break; - case V_ASSOC: /* address of association structure */ - return "assoc"; - break; - case V_OBJ: /* address of object structure */ - return "object"; - break; - case V_FILE: /* opened file id */ - return "file"; - break; - case V_RAND: /* subtractive 100 random state */ - return "rand_state"; - break; - case V_RANDOM: /* address of Blum random state */ - return "random_state"; - break; - case V_CONFIG: /* configuration state */ - return "config_state"; - break; - case V_HASH: /* hash state */ - return "hash_state"; - break; - case V_BLOCK: /* memory block */ - return "octet_block"; - break; - case V_OCTET: /* octet (unsigned char) */ - return "octet"; - break; - default: - return "unknown"; - break; + case V_NULL: return "null"; // null value + case V_INT: return "int"; // normal integer + case V_NUM: return "rational_value"; // number + case V_COM: return "complex_value"; // complex number + case V_ADDR: return "address"; // address of variable value + case V_STR: return "string"; // address of string + case V_MAT: return "matrix"; // address of matrix structure + case V_LIST: return "list"; // address of list structure + case V_ASSOC: return "assoc"; // address of association structure + case V_OBJ: return "object"; // address of object structure + case V_FILE: return "file"; // opened file id + case V_RAND: return "rand_state"; // subtractive 100 random state + case V_RANDOM: return "random_state"; // address of Blum random state + case V_CONFIG: return "config_state"; // configuration state + case V_HASH: return "hash_state"; // hash state + case V_BLOCK: return "octet_block"; // memory block + case V_OCTET: return "octet"; // octet (unsigned char) + default: return "unknown"; } } -const char* -value_type2str(VALUE value) { - return type2str(value.v_type); -} -const char* -value_ptr_type2str(VALUE*value) { - return type2str(value->v_type); -} /* * u_pfe_fork - create process @@ -255,7 +212,7 @@ valv_type_check(int UNUSED(count), VALUE **vals, int idx, const char* UNUSED(nam } void valv_type_require(const char* custname, int count, VALUE **vals, int idx, const char* name, short wanted) { - if (!valv_type_check(count, vals, idx, name, wanted)) math_error("%s: argment %d (%s) must be of type %s (%s given)", custname, idx+1, name, type2str(wanted), value_ptr_type2str(vals[idx])); + if (!valv_type_check(count, vals, idx, name, wanted)) math_error("%s: argment %d (%s) must be of type %s (%s given)", custname, idx+1, name, type2str(wanted), type2str(vals[idx]->v_type)); } bool valv_ref_type_check(int UNUSED(count), VALUE **vals, int idx, const char* UNUSED(name), short wanted) { @@ -263,8 +220,8 @@ valv_ref_type_check(int UNUSED(count), VALUE **vals, int idx, const char* UNUSED } void valv_ref_type_require(const char* custname, int count, VALUE **vals, int idx, const char* name, short wanted) { - if (!valv_type_check(count, vals, idx, name, V_VPTR)) math_error("%s: argment %d (%s) must be address (%s given) of type %s", custname, idx+1, name, value_ptr_type2str(vals[idx]), type2str(wanted)); - if (!valv_ref_type_check(count, vals, idx, name, wanted)) math_error("%s: argment %d (%s) must be address of type %s (%s given)", custname, idx+1, name, type2str(wanted), value_ptr_type2str(vals[idx]->v_addr)); + if (!valv_type_check(count, vals, idx, name, V_VPTR)) math_error("%s: argment %d (%s) must be address (%s given) of type %s", custname, idx+1, name, type2str(vals[idx]->v_type), type2str(wanted)); + if (!valv_ref_type_check(count, vals, idx, name, wanted)) math_error("%s: argment %d (%s) must be address of type %s (%s given)", custname, idx+1, name, type2str(wanted), type2str(vals[idx]->v_addr->v_type)); } long @@ -435,7 +392,7 @@ u_pfe_execvp(char *UNUSED(name), int count, VALUE **vals) el = el->e_next, s++ ) { - if (el->e_value.v_type != V_STR) math_error("%s: argment 2 (args) element %d must be of type string (%s given)", custname, s, value_type2str(el->e_value)); + if (el->e_value.v_type != V_STR) math_error("%s: argment 2 (args) element %d must be of type string (%s given)", custname, s, type2str(el->e_value.v_type)); args[s] = el->e_value.v_str->s_str; } @@ -626,7 +583,7 @@ optional_valv_ref_list2fd_set(const char* custname, int count, VALUE **vals, int el = el->e_next, s++ ) { - if (el->e_value.v_type != V_NUM) math_error("%s: argument %d (%s) element %d must be of type number (%s given)", custname, *idx, name, s, value_type2str(el->e_value)); + if (el->e_value.v_type != V_NUM) math_error("%s: argument %d (%s) element %d must be of type number (%s given)", custname, *idx, name, s, type2str(el->e_value.v_type)); int i = qtoi(el->e_value.v_num); if (*setsize < i+1) @@ -817,7 +774,7 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) if ( el ->e_value.v_type != V_LIST ) { free(pollfds); math_error("%s: argument %d (%s) element %d must be of type list (%s given)", - custname, 1, i_name, s, value_type2str(el->e_value)); + custname, 1, i_name, s, type2str(el->e_value.v_type)); } LIST* el_list = el->e_value.v_list; @@ -828,12 +785,12 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) if ( el_el ->e_value.v_type != V_NUM ) { free(pollfds); math_error("%s: argument %d (%s) element %d element %d must be of type number (%s given)", - custname, 1, i_name, s, 1, value_type2str(el_el->e_value)); + custname, 1, i_name, s, 1, type2str(el_el->e_value.v_type)); } if (!qisint(el_el ->e_value.v_num) ) { free(pollfds); math_error("%s: argument %d (%s) element %d element %d must be integer (%s given)", - custname, 1, i_name, s, 1, value_type2str(el_el->e_value)); + custname, 1, i_name, s, 1, type2str(el_el->e_value.v_type)); } pollfds[s].fd = qtoi(el_el->e_value.v_num); @@ -850,7 +807,7 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) if ( el_el ->e_value.v_type != V_STR ) { free(pollfds); math_error("%s: argument %d (%s) element %d element %d must be of type string (%s given)", - custname, 1, i_name, s, el_el_s, value_type2str(el_el->e_value)); + custname, 1, i_name, s, el_el_s, type2str(el_el->e_value.v_type)); } char* el_el_str = el_el->e_value.v_str->s_str; @@ -964,7 +921,7 @@ u_pfe_wait4(char *UNUSED(name), int count, VALUE **vals) el = el->e_next, s++ ) { - if (el->e_value.v_type != V_STR) math_error("%s: options list element %d must be of type string (%s given)", custname, s, value_type2str(el->e_value)); + if (el->e_value.v_type != V_STR) math_error("%s: options list element %d must be of type string (%s given)", custname, s, type2str(el->e_value.v_type)); char* opt_str = el->e_value.v_str->s_str; if (FALSE); @@ -1076,7 +1033,7 @@ u_pfe_pfe(char *UNUSED(name), int count, VALUE **vals) el = el->e_next, s++ ) { - if (el->e_value.v_type != V_STR) math_error("%s: argment 2 (args) element %d must be of type string (%s given)", custname, s, value_type2str(el->e_value)); + if (el->e_value.v_type != V_STR) math_error("%s: argment 2 (args) element %d must be of type string (%s given)", custname, s, type2str(el->e_value.v_type)); args[s] = el->e_value.v_str->s_str; } From 7891cbd9c3854e9e694fc942b0ad4ee2d1568e2f Mon Sep 17 00:00:00 2001 From: vike Date: Wed, 24 Jul 2024 02:24:03 +0200 Subject: [PATCH 10/21] clang-format of custom/u_pfe.c --- custom/u_pfe.c | 2021 ++++++++++++++++++++++++++---------------------- 1 file changed, 1101 insertions(+), 920 deletions(-) diff --git a/custom/u_pfe.c b/custom/u_pfe.c index 6aa6217e0..e05971365 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -27,61 +27,79 @@ */ #include #if defined(CUSTOM) -int u_pfe_allowed = 1; /* CUSTOM defined */ -#else /* CUSTOM */ -int u_pfe_allowed = 0; /* CUSTOM undefined */ -#endif /* CUSTOM */ +int u_pfe_allowed = 1; /* CUSTOM defined */ +#else /* CUSTOM */ +int u_pfe_allowed = 0; /* CUSTOM undefined */ +#endif /* CUSTOM */ #if defined(CUSTOM) -#include -#include -#include // MAXPATHLEN attow -#include -#include -#include -#include -#include -#include -#include + #include + #include + #include // MAXPATHLEN attow + #include + #include + #include + #include + #include + #include + #include -#include "../have_const.h" -#include "../value.h" -#include "../custom.h" + #include "../have_const.h" + #include "../value.h" + #include "../custom.h" -#include "../config.h" -#include "../calc.h" + #include "../config.h" + #include "../calc.h" -#include "../have_unused.h" + #include "../have_unused.h" -#include "../banned.h" /* include after system header <> includes */ + #include "../banned.h" /* include after system header <> includes */ -const char* +const char * type2str(short type) { - // originally from c_argv.c - switch (type) { - case V_NULL: return "null"; // null value - case V_INT: return "int"; // normal integer - case V_NUM: return "rational_value"; // number - case V_COM: return "complex_value"; // complex number - case V_ADDR: return "address"; // address of variable value - case V_STR: return "string"; // address of string - case V_MAT: return "matrix"; // address of matrix structure - case V_LIST: return "list"; // address of list structure - case V_ASSOC: return "assoc"; // address of association structure - case V_OBJ: return "object"; // address of object structure - case V_FILE: return "file"; // opened file id - case V_RAND: return "rand_state"; // subtractive 100 random state - case V_RANDOM: return "random_state"; // address of Blum random state - case V_CONFIG: return "config_state"; // configuration state - case V_HASH: return "hash_state"; // hash state - case V_BLOCK: return "octet_block"; // memory block - case V_OCTET: return "octet"; // octet (unsigned char) - default: return "unknown"; - } + // originally from c_argv.c + switch (type) { + case V_NULL: + return "null"; // null value + case V_INT: + return "int"; // normal integer + case V_NUM: + return "rational_value"; // number + case V_COM: + return "complex_value"; // complex number + case V_ADDR: + return "address"; // address of variable value + case V_STR: + return "string"; // address of string + case V_MAT: + return "matrix"; // address of matrix structure + case V_LIST: + return "list"; // address of list structure + case V_ASSOC: + return "assoc"; // address of association structure + case V_OBJ: + return "object"; // address of object structure + case V_FILE: + return "file"; // opened file id + case V_RAND: + return "rand_state"; // subtractive 100 random state + case V_RANDOM: + return "random_state"; // address of Blum random state + case V_CONFIG: + return "config_state"; // configuration state + case V_HASH: + return "hash_state"; // hash state + case V_BLOCK: + return "octet_block"; // memory block + case V_OCTET: + return "octet"; // octet (unsigned char) + default: + return "unknown"; + } } /* @@ -94,15 +112,15 @@ type2str(short type) VALUE u_pfe_fork(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) { - VALUE result; - int pid; + VALUE result; + int pid; - pid = fork(); + pid = fork(); - result.v_subtype = 0; - result.v_type = V_NUM; - result.v_num = itoq(pid); - return result; + result.v_subtype = 0; + result.v_type = V_NUM; + result.v_num = itoq(pid); + return result; } //cspell:ignore makenewstring @@ -112,46 +130,46 @@ u_pfe_fork(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) //cspell:ignore associndex //cspell:ignore assocalloc -VALUE* -associndex_int(ASSOC*assoc, long index) +VALUE * +associndex_int(ASSOC *assoc, long index) { - VALUE i; - VALUE indices[1]; - - i.v_type = V_NUM; - i.v_num = itoq(index); - - indices[0] = i; - return associndex(assoc, TRUE, 1, indices); + VALUE i; + VALUE indices[1]; + + i.v_type = V_NUM; + i.v_num = itoq(index); + + indices[0] = i; + return associndex(assoc, TRUE, 1, indices); } -VALUE* -associndex_str(ASSOC*assoc, STRING* index) +VALUE * +associndex_str(ASSOC *assoc, STRING *index) { - VALUE i; - VALUE indices[1]; - - i.v_type = V_STR; - i.v_str = index; - - indices[0] = i; - return associndex(assoc, TRUE, 1, indices); + VALUE i; + VALUE indices[1]; + + i.v_type = V_STR; + i.v_str = index; + + indices[0] = i; + return associndex(assoc, TRUE, 1, indices); } void -associndex_int_int(ASSOC*assoc, long index, long value) +associndex_int_int(ASSOC *assoc, long index, long value) { - VALUE*i = associndex_int(assoc, index); - i->v_type = V_NUM; - i->v_num = itoq(value); + VALUE *i = associndex_int(assoc, index); + i->v_type = V_NUM; + i->v_num = itoq(value); } void -associndex_str_int(ASSOC*assoc, STRING* index, long value) +associndex_str_int(ASSOC *assoc, STRING *index, long value) { - VALUE*i = associndex_str(assoc, index); - i->v_type = V_NUM; - i->v_num = itoq(value); + VALUE *i = associndex_str(assoc, index); + i->v_type = V_NUM; + i->v_num = itoq(value); } /* @@ -164,203 +182,273 @@ associndex_str_int(ASSOC*assoc, STRING* index, long value) VALUE u_pfe_pipe(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) { - const char* custname = "pipe"; - - int fds[2]; - if (pipe(fds)) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); - - ASSOC* assoc = assocalloc(2); - - associndex_int_int(assoc, 0, fds[0]); - associndex_int_int(assoc, 1, fds[1]); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_ASSOC; - result.v_assoc = assoc; - return result; + const char *custname = "pipe"; + + int fds[2]; + if (pipe(fds)) + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + + ASSOC *assoc = assocalloc(2); + + associndex_int_int(assoc, 0, fds[0]); + associndex_int_int(assoc, 1, fds[1]); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_ASSOC; + result.v_assoc = assoc; + return result; } //cspell:ignore custname typedef enum { - VALV_OPT_OOB, - VALV_OPT_NULL, - VALV_OPT_GOOD, - VALV_OPT_BAD, - VALV_OPT_REF_NULL, + VALV_OPT_OOB, + VALV_OPT_NULL, + VALV_OPT_GOOD, + VALV_OPT_BAD, + VALV_OPT_REF_NULL, } valv_opt; valv_opt -valv_optional_type_check(int count, VALUE **vals, int idx, const char* UNUSED(name), short wanted) { - if (idx > count) return VALV_OPT_OOB; - if (vals[idx]->v_type == V_NULL) return VALV_OPT_NULL; - if (vals[idx]->v_type == wanted) return VALV_OPT_GOOD; - return VALV_OPT_BAD; +valv_optional_type_check(int count, VALUE **vals, int idx, + const char *UNUSED(name), short wanted) +{ + if (idx > count) return VALV_OPT_OOB; + if (vals[idx]->v_type == V_NULL) return VALV_OPT_NULL; + if (vals[idx]->v_type == wanted) return VALV_OPT_GOOD; + return VALV_OPT_BAD; } valv_opt -valv_optional_ref_type_check(int count, VALUE **vals, int idx, const char* UNUSED(name), short wanted) { - if (idx > count) return VALV_OPT_OOB; - if (vals[idx]->v_type == V_NULL) return VALV_OPT_NULL; - if (vals[idx]->v_type != V_VPTR) return VALV_OPT_BAD; - if (vals[idx]->v_addr->v_type == V_NULL) return VALV_OPT_REF_NULL; - if (vals[idx]->v_addr->v_type == wanted) return VALV_OPT_GOOD; - return VALV_OPT_BAD; +valv_optional_ref_type_check(int count, VALUE **vals, int idx, + const char *UNUSED(name), short wanted) +{ + if (idx > count) return VALV_OPT_OOB; + if (vals[idx]->v_type == V_NULL) return VALV_OPT_NULL; + if (vals[idx]->v_type != V_VPTR) return VALV_OPT_BAD; + if (vals[idx]->v_addr->v_type == V_NULL) return VALV_OPT_REF_NULL; + if (vals[idx]->v_addr->v_type == wanted) return VALV_OPT_GOOD; + return VALV_OPT_BAD; } bool -valv_type_check(int UNUSED(count), VALUE **vals, int idx, const char* UNUSED(name), short wanted) { - return vals[idx]->v_type == wanted; +valv_type_check(int UNUSED(count), VALUE **vals, int idx, + const char *UNUSED(name), short wanted) +{ + return vals[idx]->v_type == wanted; } void -valv_type_require(const char* custname, int count, VALUE **vals, int idx, const char* name, short wanted) { - if (!valv_type_check(count, vals, idx, name, wanted)) math_error("%s: argment %d (%s) must be of type %s (%s given)", custname, idx+1, name, type2str(wanted), type2str(vals[idx]->v_type)); +valv_type_require(const char *custname, int count, VALUE **vals, int idx, + const char *name, short wanted) +{ + if (!valv_type_check(count, vals, idx, name, wanted)) + math_error("%s: argment %d (%s) must be of type %s (%s given)", custname, + idx + 1, name, type2str(wanted), type2str(vals[idx]->v_type)); } bool -valv_ref_type_check(int UNUSED(count), VALUE **vals, int idx, const char* UNUSED(name), short wanted) { - return vals[idx]->v_addr->v_type == wanted; +valv_ref_type_check(int UNUSED(count), VALUE **vals, int idx, + const char *UNUSED(name), short wanted) +{ + return vals[idx]->v_addr->v_type == wanted; } void -valv_ref_type_require(const char* custname, int count, VALUE **vals, int idx, const char* name, short wanted) { - if (!valv_type_check(count, vals, idx, name, V_VPTR)) math_error("%s: argment %d (%s) must be address (%s given) of type %s", custname, idx+1, name, type2str(vals[idx]->v_type), type2str(wanted)); - if (!valv_ref_type_check(count, vals, idx, name, wanted)) math_error("%s: argment %d (%s) must be address of type %s (%s given)", custname, idx+1, name, type2str(wanted), type2str(vals[idx]->v_addr->v_type)); +valv_ref_type_require(const char *custname, int count, VALUE **vals, int idx, + const char *name, short wanted) +{ + if (!valv_type_check(count, vals, idx, name, V_VPTR)) + math_error("%s: argment %d (%s) must be address (%s given) of type %s", + custname, idx + 1, name, type2str(vals[idx]->v_type), + type2str(wanted)); + if (!valv_ref_type_check(count, vals, idx, name, wanted)) + math_error("%s: argment %d (%s) must be address of type %s (%s given)", + custname, idx + 1, name, type2str(wanted), + type2str(vals[idx]->v_addr->v_type)); } long -valv_get_num_long(const char* custname, int count, VALUE **vals, int idx, const char* name) { - valv_type_require(custname, count, vals, idx, name, V_NUM); - return qtoi(vals[idx]->v_num); +valv_get_num_long(const char *custname, int count, VALUE **vals, int idx, + const char *name) +{ + valv_type_require(custname, count, vals, idx, name, V_NUM); + return qtoi(vals[idx]->v_num); } -VALUE* -valv_optional_get_num(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { - valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_NUM); - switch (chk) { - case VALV_OPT_BAD: return dflt; - case VALV_OPT_NULL: *idx += 1; // fall-thru - case VALV_OPT_OOB: return dflt; - case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD: ; // fall-thru - } - VALUE* num = vals[*idx]; - *idx += 1; - return num; +VALUE * +valv_optional_get_num(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt) +{ + valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_NUM); + switch (chk) { + case VALV_OPT_BAD: + return dflt; + case VALV_OPT_NULL: + *idx += 1; // fall-thru + case VALV_OPT_OOB: + return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD:; // fall-thru + } + VALUE *num = vals[*idx]; + *idx += 1; + return num; } -VALUE* -valv_optional_ref_num(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { - valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_NUM); - switch (chk) { - case VALV_OPT_BAD: return dflt; - case VALV_OPT_NULL: *idx += 1; // fall-thru - case VALV_OPT_OOB: return dflt; - case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD: ; // fall-thru - } - VALUE* num = vals[*idx]->v_addr; - if (chk == VALV_OPT_REF_NULL) { - num->v_type = V_NUM; - num->v_num = dflt->v_num; - } - *idx += 1; - return num; +VALUE * +valv_optional_ref_num(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt) +{ + valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_NUM); + switch (chk) { + case VALV_OPT_BAD: + return dflt; + case VALV_OPT_NULL: + *idx += 1; // fall-thru + case VALV_OPT_OOB: + return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD:; // fall-thru + } + VALUE *num = vals[*idx]->v_addr; + if (chk == VALV_OPT_REF_NULL) { + num->v_type = V_NUM; + num->v_num = dflt->v_num; + } + *idx += 1; + return num; } -VALUE* -valv_ref_num(const char* custname, int count, VALUE **vals, int idx, const char* name) { - valv_ref_type_require(custname, count, vals, idx, name, V_NUM); - return vals[idx]->v_addr; +VALUE * +valv_ref_num(const char *custname, int count, VALUE **vals, int idx, + const char *name) +{ + valv_ref_type_require(custname, count, vals, idx, name, V_NUM); + return vals[idx]->v_addr; } -VALUE* -valv_get_num(const char* custname, int count, VALUE **vals, int idx, const char* name) { - valv_type_require(custname, count, vals, idx, name, V_NUM); - return vals[idx]; +VALUE * +valv_get_num(const char *custname, int count, VALUE **vals, int idx, + const char *name) +{ + valv_type_require(custname, count, vals, idx, name, V_NUM); + return vals[idx]; } -char* -valv_get_str(const char* custname, int count, VALUE **vals, int idx, const char* name) { - valv_type_require(custname, count, vals, idx, name, V_STR); - return vals[idx]->v_str->s_str; +char * +valv_get_str(const char *custname, int count, VALUE **vals, int idx, + const char *name) +{ + valv_type_require(custname, count, vals, idx, name, V_STR); + return vals[idx]->v_str->s_str; } //cspell:ignore strp -VALUE* -valv_get_strp(const char* custname, int count, VALUE **vals, int idx, const char* name) { - valv_type_require(custname, count, vals, idx, name, V_STR); - return vals[idx]; +VALUE * +valv_get_strp(const char *custname, int count, VALUE **vals, int idx, + const char *name) +{ + valv_type_require(custname, count, vals, idx, name, V_STR); + return vals[idx]; } -VALUE* -valv_optional_ref_list(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { - valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_LIST); - switch (chk) { - case VALV_OPT_BAD: return dflt; - case VALV_OPT_NULL: *idx += 1; // fall-thru - case VALV_OPT_OOB: return dflt; - case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD: ; // fall-thru - } - VALUE* list = vals[*idx]->v_addr; - if (chk == VALV_OPT_REF_NULL) { - list->v_type = V_LIST; - list->v_list = dflt->v_list; - } - *idx += 1; - return list; +VALUE * +valv_optional_ref_list(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt) +{ + valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_LIST); + switch (chk) { + case VALV_OPT_BAD: + return dflt; + case VALV_OPT_NULL: + *idx += 1; // fall-thru + case VALV_OPT_OOB: + return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD:; // fall-thru + } + VALUE *list = vals[*idx]->v_addr; + if (chk == VALV_OPT_REF_NULL) { + list->v_type = V_LIST; + list->v_list = dflt->v_list; + } + *idx += 1; + return list; } -VALUE* -valv_optional_get_list(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { - valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_LIST); - switch (chk) { - case VALV_OPT_BAD: return dflt; - case VALV_OPT_NULL: *idx += 1; // fall-thru - case VALV_OPT_OOB: return dflt; - case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD: ; // fall-thru - } - VALUE* list = vals[*idx]; - *idx += 1; - return list; +VALUE * +valv_optional_get_list(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt) +{ + valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_LIST); + switch (chk) { + case VALV_OPT_BAD: + return dflt; + case VALV_OPT_NULL: + *idx += 1; // fall-thru + case VALV_OPT_OOB: + return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD:; // fall-thru + } + VALUE *list = vals[*idx]; + *idx += 1; + return list; } -VALUE* -valv_get_list(const char* custname, int count, VALUE **vals, int idx, const char* name) { - valv_type_require(custname, count, vals, idx, name, V_LIST); - return vals[idx]; +VALUE * +valv_get_list(const char *custname, int count, VALUE **vals, int idx, + const char *name) +{ + valv_type_require(custname, count, vals, idx, name, V_LIST); + return vals[idx]; } -VALUE* -valv_ref_list(const char* custname, int count, VALUE **vals, int idx, const char* name) { - valv_ref_type_require(custname, count, vals, idx, name, V_LIST); - return vals[idx]->v_addr; +VALUE * +valv_ref_list(const char *custname, int count, VALUE **vals, int idx, + const char *name) +{ + valv_ref_type_require(custname, count, vals, idx, name, V_LIST); + return vals[idx]->v_addr; } -VALUE* -valv_optional_get_assoc(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { - valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_ASSOC); - switch (chk) { - case VALV_OPT_BAD: return dflt; - case VALV_OPT_NULL: *idx += 1; // fall-thru - case VALV_OPT_OOB: return dflt; - case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD: ; // fall-thru - } - VALUE* assoc = vals[*idx]; - *idx += 1; - return assoc; +VALUE * +valv_optional_get_assoc(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt) +{ + valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_ASSOC); + switch (chk) { + case VALV_OPT_BAD: + return dflt; + case VALV_OPT_NULL: + *idx += 1; // fall-thru + case VALV_OPT_OOB: + return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD:; // fall-thru + } + VALUE *assoc = vals[*idx]; + *idx += 1; + return assoc; } -VALUE* -valv_optional_ref_assoc(int count, VALUE **vals, int* idx, const char* name, VALUE* dflt) { - valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_ASSOC); - switch (chk) { - case VALV_OPT_BAD: return dflt; - case VALV_OPT_NULL: *idx += 1; // fall-thru - case VALV_OPT_OOB: return dflt; - case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD: ; // fall-thru - } - VALUE* assoc = vals[*idx]->v_addr; - *idx += 1; - return assoc; +VALUE * +valv_optional_ref_assoc(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt) +{ + valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_ASSOC); + switch (chk) { + case VALV_OPT_BAD: + return dflt; + case VALV_OPT_NULL: + *idx += 1; // fall-thru + case VALV_OPT_OOB: + return dflt; + case VALV_OPT_REF_NULL: + case VALV_OPT_GOOD:; // fall-thru + } + VALUE *assoc = vals[*idx]->v_addr; + *idx += 1; + return assoc; } -VALUE* -valv_get_assoc(const char* custname, int count, VALUE **vals, int idx, const char* name) { - valv_type_require(custname, count, vals, idx, name, V_ASSOC); - return vals[idx]; +VALUE * +valv_get_assoc(const char *custname, int count, VALUE **vals, int idx, + const char *name) +{ + valv_type_require(custname, count, vals, idx, name, V_ASSOC); + return vals[idx]; } -VALUE* -valv_ref_assoc(const char* custname, int count, VALUE **vals, int idx, const char* name) { - valv_ref_type_require(custname, count, vals, idx, name, V_ASSOC); - return vals[idx]->v_addr; +VALUE * +valv_ref_assoc(const char *custname, int count, VALUE **vals, int idx, + const char *name) +{ + valv_ref_type_require(custname, count, vals, idx, name, V_ASSOC); + return vals[idx]->v_addr; } /* @@ -377,36 +465,38 @@ valv_ref_assoc(const char* custname, int count, VALUE **vals, int idx, const cha VALUE u_pfe_execvp(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "execvp"; - - char* path = valv_get_str (custname, count, vals, 0, "file"); - VALUE* args_list = valv_get_list (custname, count, vals, 1, "args"); - - char** args; - if (!(args = malloc(sizeof(char*) * args_list->v_list->l_count))) math_error("%s: "__FILE__": %d: malloc: %s", custname, __LINE__, strerror(errno)); - - LISTELEM* el = args_list->v_list->l_first; - int s = 0; - for (; - el != NULL; - el = el->e_next, - s++ - ) { - if (el->e_value.v_type != V_STR) math_error("%s: argment 2 (args) element %d must be of type string (%s given)", custname, s, type2str(el->e_value.v_type)); - - args[s] = el->e_value.v_str->s_str; - } - - if (execvp(path, args)) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); - - free(args); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(errno); - return result; + const char *custname = "execvp"; + + char *path = valv_get_str(custname, count, vals, 0, "file"); + VALUE *args_list = valv_get_list(custname, count, vals, 1, "args"); + + char **args; + if (!(args = malloc(sizeof(char *) * args_list->v_list->l_count))) + math_error("%s: "__FILE__ ": %d: malloc: %s", custname, __LINE__, + strerror(errno)); + + LISTELEM *el = args_list->v_list->l_first; + int s = 0; + for (; el != NULL; el = el->e_next, s++) { + if (el->e_value.v_type != V_STR) + math_error("%s: argment 2 (args) element %d must be of type string (%s given)", + custname, s, type2str(el->e_value.v_type)); + + args[s] = el->e_value.v_str->s_str; + } + + if (execvp(path, args)) + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + + free(args); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(errno); + return result; } /* @@ -422,19 +512,20 @@ u_pfe_execvp(char *UNUSED(name), int count, VALUE **vals) VALUE u_pfe_dup(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "dup"; - - int fd = dup( - valv_get_num_long(custname, count, vals, 0, "source")); - - if (fd < 0) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(fd); - return result; + const char *custname = "dup"; + + int fd = dup(valv_get_num_long(custname, count, vals, 0, "source")); + + if (fd < 0) + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(fd); + return result; } /* @@ -451,20 +542,21 @@ u_pfe_dup(char *UNUSED(name), int count, VALUE **vals) VALUE u_pfe_dup2(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "dup2"; - - int fd = dup2( - valv_get_num_long(custname, count, vals, 0, "source"), - valv_get_num_long(custname, count, vals, 1, "target")); - - if (fd < 0) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(fd); - return result; + const char *custname = "dup2"; + + int fd = dup2(valv_get_num_long(custname, count, vals, 0, "source"), + valv_get_num_long(custname, count, vals, 1, "target")); + + if (fd < 0) + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(fd); + return result; } /* @@ -480,18 +572,20 @@ u_pfe_dup2(char *UNUSED(name), int count, VALUE **vals) VALUE u_pfe_close(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "close"; - - int e = close(valv_get_num_long(custname, count, vals, 0, "fd")); - - if (e) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(e); - return result; + const char *custname = "close"; + + int e = close(valv_get_num_long(custname, count, vals, 0, "fd")); + + if (e) + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(e); + return result; } /* @@ -508,26 +602,26 @@ u_pfe_close(char *UNUSED(name), int count, VALUE **vals) VALUE u_pfe_write(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "write"; - - VALUE* strp = valv_get_strp(custname, count, vals, 1, "string"); - - ssize_t written = write( - valv_get_num_long(custname, count, vals, 0, "fd"), - strp->v_str->s_str, - strp->v_str->s_len); - - if (written < 0) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(written); - return result; + const char *custname = "write"; + + VALUE *strp = valv_get_strp(custname, count, vals, 1, "string"); + + ssize_t written = write(valv_get_num_long(custname, count, vals, 0, "fd"), + strp->v_str->s_str, strp->v_str->s_len); + + if (written < 0) + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(written); + return result; } -#define u_pfe_read_STRL_DFLT 1024 + #define u_pfe_read_STRL_DFLT 1024 /* * u_pfe_read - write output @@ -543,115 +637,123 @@ u_pfe_write(char *UNUSED(name), int count, VALUE **vals) VALUE u_pfe_read(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "read"; - - int strl = count < 2 ? u_pfe_read_STRL_DFLT : valv_get_num_long(custname, count, vals, 1, "count"); - - char* str = malloc((strl+1)*sizeof(char)); - - ssize_t r = read( - valv_get_num_long(custname, count, vals, 0, "fd"), - str, strl); - str[r] = '\0'; - - if (r < 0) { free(str); math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); } - - VALUE result; - result.v_subtype = 0; - result.v_type = !r ? V_NULL : V_STR; - if (r) - result.v_str = makestring(str); - return result; + const char *custname = "read"; + + int strl = count < 2 ? u_pfe_read_STRL_DFLT + : valv_get_num_long(custname, count, vals, 1, "count"); + + char *str = malloc((strl + 1) * sizeof(char)); + + ssize_t r = read(valv_get_num_long(custname, count, vals, 0, "fd"), str, + strl); + str[r] = '\0'; + + if (r < 0) { + free(str); + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + } + + VALUE result; + result.v_subtype = 0; + result.v_type = !r ? V_NULL : V_STR; + if (r) result.v_str = makestring(str); + return result; } -VALUE* -optional_valv_ref_list2fd_set(const char* custname, int count, VALUE **vals, int* idx, const char* name, fd_set* fds, int* setsize) { - valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_LIST); - switch (chk) { - case VALV_OPT_BAD: return NULL; - case VALV_OPT_NULL: *idx += 1; // fall-thru - case VALV_OPT_OOB: return NULL; - case VALV_OPT_REF_NULL: math_error("%s: argument %d (%s) address of type null is not allowed", custname, *idx, name); - case VALV_OPT_GOOD: ; // fall-thru - } - VALUE* list = vals[*idx]->v_addr; - *idx += 1; - LISTELEM* el = list->v_list->l_first; - int s = 0; - for (; - el != NULL; - el = el->e_next, - s++ - ) { - if (el->e_value.v_type != V_NUM) math_error("%s: argument %d (%s) element %d must be of type number (%s given)", custname, *idx, name, s, type2str(el->e_value.v_type)); - - int i = qtoi(el->e_value.v_num); - if (*setsize < i+1) - *setsize = i+1; - FD_SET(i, fds); - } - return list; +VALUE * +optional_valv_ref_list2fd_set(const char *custname, int count, VALUE **vals, + int *idx, const char *name, fd_set *fds, int *setsize) +{ + valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_LIST); + switch (chk) { + case VALV_OPT_BAD: + return NULL; + case VALV_OPT_NULL: + *idx += 1; // fall-thru + case VALV_OPT_OOB: + return NULL; + case VALV_OPT_REF_NULL: + math_error("%s: argument %d (%s) address of type null is not allowed", + custname, *idx, name); + case VALV_OPT_GOOD:; // fall-thru + } + VALUE *list = vals[*idx]->v_addr; + *idx += 1; + LISTELEM *el = list->v_list->l_first; + int s = 0; + for (; el != NULL; el = el->e_next, s++) { + if (el->e_value.v_type != V_NUM) + math_error("%s: argument %d (%s) element %d must be of type number (%s given)", + custname, *idx, name, s, type2str(el->e_value.v_type)); + + int i = qtoi(el->e_value.v_num); + if (*setsize < i + 1) *setsize = i + 1; + FD_SET(i, fds); + } + return list; } -VALUE* -alloc_list(LIST* list) { - VALUE* result = malloc(sizeof(VALUE)); - result->v_type = V_LIST; - - result->v_list = list; - return result; +VALUE * +alloc_list(LIST *list) +{ + VALUE *result = malloc(sizeof(VALUE)); + result->v_type = V_LIST; + + result->v_list = list; + return result; } -VALUE* -alloc_assoc(ASSOC* assoc) { - VALUE* result = malloc(sizeof(VALUE)); - result->v_type = V_ASSOC; - - result->v_assoc = assoc; - return result; +VALUE * +alloc_assoc(ASSOC *assoc) +{ + VALUE *result = malloc(sizeof(VALUE)); + result->v_type = V_ASSOC; + + result->v_assoc = assoc; + return result; } //cspell:ignore listalloc copyvalue insertlistlast -VALUE* -list_fd_get(LIST* in, fd_set* fds) { - VALUE* out = alloc_list(listalloc()); - LISTELEM* el = in->l_first; - int s = 0; - for (; - el != NULL; - el = el->e_next, - s++ - ) { - int i = qtoi(el->e_value.v_num); - if (FD_ISSET(i, fds)){ - VALUE o; - copyvalue(&el->e_value, &o); - insertlistlast(out->v_list, &o); - } - } - return out; +VALUE * +list_fd_get(LIST *in, fd_set *fds) +{ + VALUE *out = alloc_list(listalloc()); + LISTELEM *el = in->l_first; + int s = 0; + for (; el != NULL; el = el->e_next, s++) { + int i = qtoi(el->e_value.v_num); + if (FD_ISSET(i, fds)) { + VALUE o; + copyvalue(&el->e_value, &o); + insertlistlast(out->v_list, &o); + } + } + return out; } -VALUE* -alloc_num(NUMBER* num) { - VALUE* result = malloc(sizeof(VALUE)); - result->v_type = V_NUM; - - result->v_num = num; - return result; +VALUE * +alloc_num(NUMBER *num) +{ + VALUE *result = malloc(sizeof(VALUE)); + result->v_type = V_NUM; + + result->v_num = num; + return result; } -VALUE* -alloc_str(STRING* str) { - VALUE* result = malloc(sizeof(VALUE)); - result->v_type = V_STR; - - result->v_str = str; - return result; +VALUE * +alloc_str(STRING *str) +{ + VALUE *result = malloc(sizeof(VALUE)); + result->v_type = V_STR; + + result->v_str = str; + return result; } -VALUE* pfe_select_TIMEOUT_DFLT = NULL; +VALUE *pfe_select_TIMEOUT_DFLT = NULL; //cspell:ignore qisneg qisint ztoi qscale qfree @@ -671,63 +773,74 @@ VALUE* pfe_select_TIMEOUT_DFLT = NULL; VALUE u_pfe_select(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "select"; - int v = 0; - - int ssz = 0; - fd_set rds; FD_ZERO(&rds); VALUE* rdl = optional_valv_ref_list2fd_set(custname, count, vals, &v, "reading" ,&rds,&ssz); - fd_set wts; FD_ZERO(&wts); VALUE* wtl = optional_valv_ref_list2fd_set(custname, count, vals, &v, "writing" ,&wts,&ssz); - fd_set ers; FD_ZERO(&ers); VALUE* erl = optional_valv_ref_list2fd_set(custname, count, vals, &v, "exceptional" ,&ers,&ssz); - - if (!pfe_select_TIMEOUT_DFLT) pfe_select_TIMEOUT_DFLT = alloc_num(itoq(-1)); - - VALUE* tv = valv_optional_get_num(count, vals, &v, "timeout", pfe_select_TIMEOUT_DFLT); - - NUMBER* tn = tv->v_num; - struct timeval t; - struct timeval* tp; - // originally from f_sleep() in ../func.c - if (qisneg(tn)) { - tp = NULL; - } else if (qisint(tn)) { - if (zge31b(tn->num)) - math_error("sizeof(timeout) > 31 bytes"); - t.tv_sec = ztoi(tn->num); - t.tv_usec = 0; - tp = &t; - } else { - NUMBER *q1, *q2; - q1 = qscale(tn, 20); // 2^20 = 1 Mi - q2 = qint(q1); - qfree(q1); - if (zge31b(q2->num)) { - qfree(q2); - math_error("sizeof(timeout as microseconds) > 31 bytes"); - } - long usec = ztoi(q2->num); - t.tv_sec = usec / 1000000; - t.tv_usec = usec - t.tv_sec * 1000000; - tp = &t; - qfree(q2); - } - - int r = select(ssz, &rds, &wts, &ers, tp); - - if (r < 0) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); - - if (rdl) *rdl = *list_fd_get(rdl->v_list, &rds); - if (wtl) *wtl = *list_fd_get(wtl->v_list, &wts); - if (erl) *erl = *list_fd_get(erl->v_list, &ers); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(r); - return result; + const char *custname = "select"; + int v = 0; + + int ssz = 0; + fd_set rds; + FD_ZERO(&rds); + VALUE *rdl = optional_valv_ref_list2fd_set(custname, count, vals, &v, + "reading", &rds, &ssz); + fd_set wts; + FD_ZERO(&wts); + VALUE *wtl = optional_valv_ref_list2fd_set(custname, count, vals, &v, + "writing", &wts, &ssz); + fd_set ers; + FD_ZERO(&ers); + VALUE *erl = optional_valv_ref_list2fd_set(custname, count, vals, &v, + "exceptional", &ers, &ssz); + + if (!pfe_select_TIMEOUT_DFLT) pfe_select_TIMEOUT_DFLT = alloc_num(itoq(-1)); + + VALUE *tv = valv_optional_get_num(count, vals, &v, "timeout", + pfe_select_TIMEOUT_DFLT); + + NUMBER *tn = tv->v_num; + struct timeval t; + struct timeval *tp; + // originally from f_sleep() in ../func.c + if (qisneg(tn)) { + tp = NULL; + } else if (qisint(tn)) { + if (zge31b(tn->num)) math_error("sizeof(timeout) > 31 bytes"); + t.tv_sec = ztoi(tn->num); + t.tv_usec = 0; + tp = &t; + } else { + NUMBER *q1, *q2; + q1 = qscale(tn, 20); // 2^20 = 1 Mi + q2 = qint(q1); + qfree(q1); + if (zge31b(q2->num)) { + qfree(q2); + math_error("sizeof(timeout as microseconds) > 31 bytes"); + } + long usec = ztoi(q2->num); + t.tv_sec = usec / 1000000; + t.tv_usec = usec - t.tv_sec * 1000000; + tp = &t; + qfree(q2); + } + + int r = select(ssz, &rds, &wts, &ers, tp); + + if (r < 0) + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + + if (rdl) *rdl = *list_fd_get(rdl->v_list, &rds); + if (wtl) *wtl = *list_fd_get(wtl->v_list, &wts); + if (erl) *erl = *list_fd_get(erl->v_list, &ers); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(r); + return result; } -VALUE* u_pfe_poll_TIMEOUT_DFLT = NULL; +VALUE *u_pfe_poll_TIMEOUT_DFLT = NULL; /* * u_pfe_poll - synchronous I/O multiplexing @@ -748,141 +861,137 @@ VALUE* u_pfe_poll_TIMEOUT_DFLT = NULL; VALUE u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "poll"; - const char* i_name = "list of list(fd[, event1[, ...eventN]])"; - - VALUE* iv = valv_get_list(custname, count, vals, 0, i_name); - VALUE* ov = valv_ref_list(custname, count, vals, 1, "list"); - - if (!u_pfe_poll_TIMEOUT_DFLT) u_pfe_poll_TIMEOUT_DFLT = alloc_num(itoq(-1)); - int v = 2; - VALUE* tv = valv_optional_get_num(count, vals, &v, "timeout", u_pfe_poll_TIMEOUT_DFLT); - NUMBER* tn = tv->v_num; - if (!qisint(tn)) math_error("%s: argument 2 (timeout) must be integer", custname); - int t = qtoi(tn); - - LIST* il = iv->v_list; - struct pollfd* pollfds = malloc(il->l_count*sizeof(struct pollfd)); //cspell:ignore pollfds - - LISTELEM* el = il->l_first; - int s = 0; - for (; - el != NULL; - el = el->e_next, - s++ - ) { - if ( el ->e_value.v_type != V_LIST ) { - free(pollfds); - math_error("%s: argument %d (%s) element %d must be of type list (%s given)", - custname, 1, i_name, s, type2str(el->e_value.v_type)); - } - - LIST* el_list = el->e_value.v_list; - LISTELEM* el_el; - - el_el = el_list->l_first; - - if ( el_el ->e_value.v_type != V_NUM ) { - free(pollfds); - math_error("%s: argument %d (%s) element %d element %d must be of type number (%s given)", - custname, 1, i_name, s, 1, type2str(el_el->e_value.v_type)); - } - if (!qisint(el_el ->e_value.v_num) ) { - free(pollfds); - math_error("%s: argument %d (%s) element %d element %d must be integer (%s given)", - custname, 1, i_name, s, 1, type2str(el_el->e_value.v_type)); - } - pollfds[s].fd = qtoi(el_el->e_value.v_num); - - pollfds[s].events = 0; - - el_el = el_el->e_next; - - int el_el_s = 1; - for (; - el_el != NULL; - el_el = el_el->e_next, - el_el_s++ - ) { - if ( el_el ->e_value.v_type != V_STR ) { - free(pollfds); - math_error("%s: argument %d (%s) element %d element %d must be of type string (%s given)", - custname, 1, i_name, s, el_el_s, type2str(el_el->e_value.v_type)); - } - - char* el_el_str = el_el->e_value.v_str->s_str; - if (FALSE); // man poll|gawk 'match($0,"^\\s*POLL([A-Z]+)",m){print(tolower(m[1]))}' - else if (!strcmp(el_el_str, "err")) - pollfds[s].events |= POLLERR; - else if (!strcmp(el_el_str, "hup")) - pollfds[s].events |= POLLHUP; - else if (!strcmp(el_el_str, "in")) - pollfds[s].events |= POLLIN; - else if (!strcmp(el_el_str, "nval")) - pollfds[s].events |= POLLNVAL; //cspell:ignore nval - else if (!strcmp(el_el_str, "out")) - pollfds[s].events |= POLLOUT; - else if (!strcmp(el_el_str, "pri")) - pollfds[s].events |= POLLPRI; - else if (!strcmp(el_el_str, "rdband")) - pollfds[s].events |= POLLRDBAND; //cspell:ignore rdband - else if (!strcmp(el_el_str, "rdnorm")) - pollfds[s].events |= POLLRDNORM; //cspell:ignore rdnorm - else if (!strcmp(el_el_str, "wrband")) - pollfds[s].events |= POLLWRBAND; //cspell:ignore wrband - else if (!strcmp(el_el_str, "wrnorm")) - pollfds[s].events |= POLLWRNORM; //cspell:ignore wrnorm - else { - free(pollfds); - math_error("%s: argument %d (%s) element %d element %d must be a string containing one of the event names from POSIX poll.h or the manual for poll, lowercase without poll prefix (%s given)", - custname, 1, i_name, s, el_el_s, el_el->e_value.v_str->s_str); - } - } - - pollfds[s].revents = 0; - } - - int r = poll(pollfds, il->l_count, t); - - if (r < 0) { free(pollfds); math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); } - - LIST* ol = listalloc(); - - for (s = 0; s < il->l_count; s++) { - VALUE* o = alloc_assoc(assocalloc(0)); - - if ((pollfds[s].revents & POLLERR ) == POLLERR ) - associndex_str_int(o->v_assoc, makenewstring("err" ), POLLERR ); - if ((pollfds[s].revents & POLLHUP ) == POLLHUP ) - associndex_str_int(o->v_assoc, makenewstring("hup" ), POLLHUP ); - if ((pollfds[s].revents & POLLIN ) == POLLIN ) - associndex_str_int(o->v_assoc, makenewstring("in" ), POLLIN ); - if ((pollfds[s].revents & POLLNVAL ) == POLLNVAL ) - associndex_str_int(o->v_assoc, makenewstring("nval" ), POLLNVAL ); - if ((pollfds[s].revents & POLLOUT ) == POLLOUT ) - associndex_str_int(o->v_assoc, makenewstring("out" ), POLLOUT ); - if ((pollfds[s].revents & POLLPRI ) == POLLPRI ) - associndex_str_int(o->v_assoc, makenewstring("pri" ), POLLPRI ); - if ((pollfds[s].revents & POLLRDBAND) == POLLRDBAND ) - associndex_str_int(o->v_assoc, makenewstring("rdband" ), POLLRDBAND ); - if ((pollfds[s].revents & POLLRDNORM) == POLLRDNORM ) - associndex_str_int(o->v_assoc, makenewstring("rdnorm" ), POLLRDNORM ); - if ((pollfds[s].revents & POLLWRBAND) == POLLWRBAND ) - associndex_str_int(o->v_assoc, makenewstring("wrband" ), POLLWRBAND ); - if ((pollfds[s].revents & POLLWRNORM) == POLLWRNORM ) - associndex_str_int(o->v_assoc, makenewstring("wrnorm" ), POLLWRNORM ); - - insertlistlast(ol, o); - } - - ov->v_list = ol; - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(r); - return result; + const char *custname = "poll"; + const char *i_name = "list of list(fd[, event1[, ...eventN]])"; + + VALUE *iv = valv_get_list(custname, count, vals, 0, i_name); + VALUE *ov = valv_ref_list(custname, count, vals, 1, "list"); + + if (!u_pfe_poll_TIMEOUT_DFLT) u_pfe_poll_TIMEOUT_DFLT = alloc_num(itoq(-1)); + int v = 2; + VALUE *tv = valv_optional_get_num(count, vals, &v, "timeout", + u_pfe_poll_TIMEOUT_DFLT); + NUMBER *tn = tv->v_num; + if (!qisint(tn)) + math_error("%s: argument 2 (timeout) must be integer", custname); + int t = qtoi(tn); + + LIST *il = iv->v_list; + struct pollfd *pollfds = malloc(il->l_count + * sizeof(struct pollfd)); //cspell:ignore pollfds + + LISTELEM *el = il->l_first; + int s = 0; + for (; el != NULL; el = el->e_next, s++) { + if (el->e_value.v_type != V_LIST) { + free(pollfds); + math_error("%s: argument %d (%s) element %d must be of type list (%s given)", + custname, 1, i_name, s, type2str(el->e_value.v_type)); + } + + LIST *el_list = el->e_value.v_list; + LISTELEM *el_el; + + el_el = el_list->l_first; + + if (el_el->e_value.v_type != V_NUM) { + free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be of type number (%s given)", + custname, 1, i_name, s, 1, type2str(el_el->e_value.v_type)); + } + if (!qisint(el_el->e_value.v_num)) { + free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be integer (%s given)", + custname, 1, i_name, s, 1, type2str(el_el->e_value.v_type)); + } + pollfds[s].fd = qtoi(el_el->e_value.v_num); + + pollfds[s].events = 0; + + el_el = el_el->e_next; + + int el_el_s = 1; + for (; el_el != NULL; el_el = el_el->e_next, el_el_s++) { + if (el_el->e_value.v_type != V_STR) { + free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be of type string (%s given)", + custname, 1, i_name, s, el_el_s, + type2str(el_el->e_value.v_type)); + } + + char *el_el_str = el_el->e_value.v_str->s_str; + if (FALSE) + ; // man poll|gawk 'match($0,"^\\s*POLL([A-Z]+)",m){print(tolower(m[1]))}' + else if (!strcmp(el_el_str, "err")) pollfds[s].events |= POLLERR; + else if (!strcmp(el_el_str, "hup")) pollfds[s].events |= POLLHUP; + else if (!strcmp(el_el_str, "in")) pollfds[s].events |= POLLIN; + else if (!strcmp(el_el_str, "nval")) + pollfds[s].events |= POLLNVAL; //cspell:ignore nval + else if (!strcmp(el_el_str, "out")) pollfds[s].events |= POLLOUT; + else if (!strcmp(el_el_str, "pri")) pollfds[s].events |= POLLPRI; + else if (!strcmp(el_el_str, "rdband")) + pollfds[s].events |= POLLRDBAND; //cspell:ignore rdband + else if (!strcmp(el_el_str, "rdnorm")) + pollfds[s].events |= POLLRDNORM; //cspell:ignore rdnorm + else if (!strcmp(el_el_str, "wrband")) + pollfds[s].events |= POLLWRBAND; //cspell:ignore wrband + else if (!strcmp(el_el_str, "wrnorm")) + pollfds[s].events |= POLLWRNORM; //cspell:ignore wrnorm + else { + free(pollfds); + math_error("%s: argument %d (%s) element %d element %d must be a string containing one of the event names from POSIX poll.h or the manual for poll, lowercase without poll prefix (%s given)", + custname, 1, i_name, s, el_el_s, el_el->e_value.v_str->s_str); + } + } + + pollfds[s].revents = 0; + } + + int r = poll(pollfds, il->l_count, t); + + if (r < 0) { + free(pollfds); + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + } + + LIST *ol = listalloc(); + + for (s = 0; s < il->l_count; s++) { + VALUE *o = alloc_assoc(assocalloc(0)); + + if ((pollfds[s].revents & POLLERR) == POLLERR) + associndex_str_int(o->v_assoc, makenewstring("err"), POLLERR); + if ((pollfds[s].revents & POLLHUP) == POLLHUP) + associndex_str_int(o->v_assoc, makenewstring("hup"), POLLHUP); + if ((pollfds[s].revents & POLLIN) == POLLIN) + associndex_str_int(o->v_assoc, makenewstring("in"), POLLIN); + if ((pollfds[s].revents & POLLNVAL) == POLLNVAL) + associndex_str_int(o->v_assoc, makenewstring("nval"), POLLNVAL); + if ((pollfds[s].revents & POLLOUT) == POLLOUT) + associndex_str_int(o->v_assoc, makenewstring("out"), POLLOUT); + if ((pollfds[s].revents & POLLPRI) == POLLPRI) + associndex_str_int(o->v_assoc, makenewstring("pri"), POLLPRI); + if ((pollfds[s].revents & POLLRDBAND) == POLLRDBAND) + associndex_str_int(o->v_assoc, makenewstring("rdband"), POLLRDBAND); + if ((pollfds[s].revents & POLLRDNORM) == POLLRDNORM) + associndex_str_int(o->v_assoc, makenewstring("rdnorm"), POLLRDNORM); + if ((pollfds[s].revents & POLLWRBAND) == POLLWRBAND) + associndex_str_int(o->v_assoc, makenewstring("wrband"), POLLWRBAND); + if ((pollfds[s].revents & POLLWRNORM) == POLLWRNORM) + associndex_str_int(o->v_assoc, makenewstring("wrnorm"), POLLWRNORM); + + insertlistlast(ol, o); + } + + ov->v_list = ol; + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(r); + return result; } /* @@ -902,59 +1011,75 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) VALUE u_pfe_wait4(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "wait4"; - int v = 0; - VALUE* pid_num = valv_optional_get_num ( count, vals, &v, "pid" , NULL ); - VALUE* stt_assoc = valv_ref_assoc(custname, count, vals, v++, "status" ); // stat in - VALUE* opt_list = valv_optional_get_list ( count, vals, &v, "options" , NULL ); - VALUE* usg_assoc = valv_optional_ref_assoc ( count, vals, &v, "usage" , NULL ); - - if (!pid_num && opt_list ) math_error("%s: argument 1 (pid) being null doesn't support options list", custname); - if (!pid_num && usg_assoc ) math_error("%s: argument 1 (pid) being null doesn't support usage assoc", custname); - - int opts = 0; - if (opt_list) { - LISTELEM* el = opt_list->v_list->l_first; - int s = 0; - for (; - el != NULL; - el = el->e_next, - s++ - ) { - if (el->e_value.v_type != V_STR) math_error("%s: options list element %d must be of type string (%s given)", custname, s, type2str(el->e_value.v_type)); - - char* opt_str = el->e_value.v_str->s_str; - if (FALSE); - else if (!strcmp(opt_str, "nohang" )) opts |= WNOHANG; - else if (!strcmp(opt_str, "untraced" )) opts |= WUNTRACED; - else math_error("%s: options list element %d must be one of \"nohang\" or \"untraced\" (%s given)", custname, s, opt_str); - } - } - - int stt = 0; - struct rusage usg; - struct rusage* usg_p = usg_assoc ? &usg : NULL; - pid_t r = pid_num ? wait4(qtoi(pid_num->v_num), &stt, opts, usg_p) : wait(&stt); - - if (0 > r) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); - - if ( WIFEXITED (stt) ){ - associndex_str_int (stt_assoc->v_assoc, makenewstring("exited" ), TRUE ); - associndex_str_int (stt_assoc->v_assoc, makenewstring("exitstatus" ), WEXITSTATUS (stt) );} - if ( WIFSIGNALED (stt) ){ - associndex_str_int (stt_assoc->v_assoc, makenewstring("signaled" ), TRUE ); - associndex_str_int (stt_assoc->v_assoc, makenewstring("termsig" ), WTERMSIG (stt) ); - associndex_str_int (stt_assoc->v_assoc, makenewstring("coredump" ), WCOREDUMP (stt) );} - if ( WIFSTOPPED (stt) ){ - associndex_str_int (stt_assoc->v_assoc, makenewstring("stopped" ), TRUE ); - associndex_str_int (stt_assoc->v_assoc, makenewstring("stopsig" ), WSTOPSIG (stt) );} - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(r); - return result; + const char *custname = "wait4"; + int v = 0; + VALUE *pid_num = valv_optional_get_num(count, vals, &v, "pid", NULL); + VALUE *stt_assoc = valv_ref_assoc(custname, count, vals, v++, + "status"); // stat in + VALUE *opt_list = valv_optional_get_list(count, vals, &v, "options", NULL); + VALUE *usg_assoc = valv_optional_ref_assoc(count, vals, &v, "usage", NULL); + + if (!pid_num && opt_list) + math_error("%s: argument 1 (pid) being null doesn't support options list", + custname); + if (!pid_num && usg_assoc) + math_error("%s: argument 1 (pid) being null doesn't support usage assoc", + custname); + + int opts = 0; + if (opt_list) { + LISTELEM *el = opt_list->v_list->l_first; + int s = 0; + for (; el != NULL; el = el->e_next, s++) { + if (el->e_value.v_type != V_STR) + math_error("%s: options list element %d must be of type string (%s given)", + custname, s, type2str(el->e_value.v_type)); + + char *opt_str = el->e_value.v_str->s_str; + if (FALSE) + ; + else if (!strcmp(opt_str, "nohang")) opts |= WNOHANG; + else if (!strcmp(opt_str, "untraced")) opts |= WUNTRACED; + else + math_error("%s: options list element %d must be one of \"nohang\" or \"untraced\" (%s given)", + custname, s, opt_str); + } + } + + int stt = 0; + struct rusage usg; + struct rusage *usg_p = usg_assoc ? &usg : NULL; + pid_t r = pid_num ? wait4(qtoi(pid_num->v_num), &stt, opts, usg_p) + : wait(&stt); + + if (0 > r) + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + + if (WIFEXITED(stt)) { + associndex_str_int(stt_assoc->v_assoc, makenewstring("exited"), TRUE); + associndex_str_int(stt_assoc->v_assoc, makenewstring("exitstatus"), + WEXITSTATUS(stt)); + } + if (WIFSIGNALED(stt)) { + associndex_str_int(stt_assoc->v_assoc, makenewstring("signaled"), TRUE); + associndex_str_int(stt_assoc->v_assoc, makenewstring("termsig"), + WTERMSIG(stt)); + associndex_str_int(stt_assoc->v_assoc, makenewstring("coredump"), + WCOREDUMP(stt)); + } + if (WIFSTOPPED(stt)) { + associndex_str_int(stt_assoc->v_assoc, makenewstring("stopped"), TRUE); + associndex_str_int(stt_assoc->v_assoc, makenewstring("stopsig"), + WSTOPSIG(stt)); + } + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(r); + return result; } /* @@ -973,82 +1098,108 @@ u_pfe_wait4(char *UNUSED(name), int count, VALUE **vals) VALUE u_pfe_pfe(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "pfe"; - - // in, out, err arrays - int ia[2];if (pipe(ia)) math_error("%s: "__FILE__": %d: (in) pipe: %s", custname, __LINE__, strerror(errno)); - int oa[2];if (pipe(oa)) math_error("%s: "__FILE__": %d: (out) pipe: %s", custname, __LINE__, strerror(errno)); - int ea[2];if (pipe(ea)) math_error("%s: "__FILE__": %d: (err) pipe: %s", custname, __LINE__, strerror(errno)); - // in, out, err values - VALUE* iv = valv_ref_num(custname, count, vals, 0, "in"); - VALUE* ov = valv_ref_num(custname, count, vals, 1, "out"); - VALUE* ev = valv_ref_num(custname, count, vals, 2, "err"); - iv->v_num = itoq(ia[1]); - ov->v_num = itoq(oa[0]); - ev->v_num = itoq(ea[0]); - - pid_t child = fork(); - if (child) { - - // child: close (parent in, out, err) - int cci = !close(ia[0]) ? 0 : errno; - int cco = !close(oa[1]) ? 0 : errno; - int cce = !close(ea[1]) ? 0 : errno; - - if (cci) math_error("%s: "__FILE__": %d: child: (parent in) close: %s", custname, __LINE__, strerror(cci)); - if (cco) math_error("%s: "__FILE__": %d: child: (parent out) close: %s", custname, __LINE__, strerror(cco)); - if (cce) math_error("%s: "__FILE__": %d: child: (parent err) close: %s", custname, __LINE__, strerror(cce)); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(child); - return result; - - } else { - - // parent: close (child in, out, err) - int pci = !close(ia[1]) ? 0 : errno; - int pco = !close(oa[0]) ? 0 : errno; - int pce = !close(ea[0]) ? 0 : errno; - - if (pci) math_error("%s: "__FILE__": %d: parent: (child in) close: %s", custname, __LINE__, strerror(pci)); - if (pco) math_error("%s: "__FILE__": %d: parent: (child out) close: %s", custname, __LINE__, strerror(pco)); - if (pce) math_error("%s: "__FILE__": %d: parent: (child err) close: %s", custname, __LINE__, strerror(pce)); - - if (dup2(ia[0], 0)!=0) math_error("%s: "__FILE__": %d: mismatch: (in) dup2: %s", custname, __LINE__, strerror(errno)); - if (dup2(oa[1], 1)!=1) math_error("%s: "__FILE__": %d: mismatch: (out) dup2: %s", custname, __LINE__, strerror(errno)); - if (dup2(ea[1], 2)!=2) math_error("%s: "__FILE__": %d: mismatch: (err) dup2: %s", custname, __LINE__, strerror(errno)); - - VALUE* args_list = valv_get_list(custname, count, vals, 3, "args"); - - char** args; - if (!(args = malloc(sizeof(char*) * args_list->v_list->l_count))) math_error("%s: "__FILE__": %d: malloc: %s", custname, __LINE__, strerror(errno)); - - LISTELEM* el = args_list->v_list->l_first; - int s = 0; - for (; - el != NULL; - el = el->e_next, - s++ - ) { - if (el->e_value.v_type != V_STR) math_error("%s: argment 2 (args) element %d must be of type string (%s given)", custname, s, type2str(el->e_value.v_type)); - - args[s] = el->e_value.v_str->s_str; - } - - if (execvp(args[0], args)) math_error("%s: "__FILE__": %d: execvp: %s", custname, __LINE__, strerror(errno)); - - free(args); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(errno); - return result; - } + const char *custname = "pfe"; + + int ia[2]; // in array + if (pipe(ia)) + math_error("%s: "__FILE__ ": %d: (in) pipe: %s", custname, __LINE__, + strerror(errno)); + int oa[2]; // out array + if (pipe(oa)) + math_error("%s: "__FILE__ ": %d: (out) pipe: %s", custname, __LINE__, + strerror(errno)); + int ea[2]; // err array + if (pipe(ea)) + math_error("%s: "__FILE__ ": %d: (err) pipe: %s", custname, __LINE__, + strerror(errno)); + // in, out, err values + VALUE *iv = valv_ref_num(custname, count, vals, 0, "in"); + VALUE *ov = valv_ref_num(custname, count, vals, 1, "out"); + VALUE *ev = valv_ref_num(custname, count, vals, 2, "err"); + iv->v_num = itoq(ia[1]); + ov->v_num = itoq(oa[0]); + ev->v_num = itoq(ea[0]); + + pid_t child = fork(); + if (child) { + // child: close (parent in, out, err) + int cci = !close(ia[0]) ? 0 : errno; + int cco = !close(oa[1]) ? 0 : errno; + int cce = !close(ea[1]) ? 0 : errno; + + if (cci) + math_error("%s: "__FILE__ ": %d: child: (parent in) close: %s", + custname, __LINE__, strerror(cci)); + if (cco) + math_error("%s: "__FILE__ ": %d: child: (parent out) close: %s", + custname, __LINE__, strerror(cco)); + if (cce) + math_error("%s: "__FILE__ ": %d: child: (parent err) close: %s", + custname, __LINE__, strerror(cce)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(child); + return result; + + } else { + // parent: close (child in, out, err) + int pci = !close(ia[1]) ? 0 : errno; + int pco = !close(oa[0]) ? 0 : errno; + int pce = !close(ea[0]) ? 0 : errno; + + if (pci) + math_error("%s: "__FILE__ ": %d: parent: (child in) close: %s", + custname, __LINE__, strerror(pci)); + if (pco) + math_error("%s: "__FILE__ ": %d: parent: (child out) close: %s", + custname, __LINE__, strerror(pco)); + if (pce) + math_error("%s: "__FILE__ ": %d: parent: (child err) close: %s", + custname, __LINE__, strerror(pce)); + + if (dup2(ia[0], 0) != 0) + math_error("%s: "__FILE__ ": %d: mismatch: (in) dup2: %s", custname, + __LINE__, strerror(errno)); + if (dup2(oa[1], 1) != 1) + math_error("%s: "__FILE__ ": %d: mismatch: (out) dup2: %s", + custname, __LINE__, strerror(errno)); + if (dup2(ea[1], 2) != 2) + math_error("%s: "__FILE__ ": %d: mismatch: (err) dup2: %s", + custname, __LINE__, strerror(errno)); + + VALUE *args_list = valv_get_list(custname, count, vals, 3, "args"); + + char **args; + if (!(args = malloc(sizeof(char *) * args_list->v_list->l_count))) + math_error("%s: "__FILE__ ": %d: malloc: %s", custname, __LINE__, + strerror(errno)); + + LISTELEM *el = args_list->v_list->l_first; + int s = 0; + for (; el != NULL; el = el->e_next, s++) { + if (el->e_value.v_type != V_STR) + math_error("%s: argment 2 (args) element %d must be of type string (%s given)", + custname, s, type2str(el->e_value.v_type)); + + args[s] = el->e_value.v_str->s_str; + } + + if (execvp(args[0], args)) + math_error("%s: "__FILE__ ": %d: execvp: %s", custname, __LINE__, + strerror(errno)); + + free(args); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(errno); + return result; + } } /* @@ -1065,38 +1216,42 @@ u_pfe_pfe(char *UNUSED(name), int count, VALUE **vals) VALUE u_pfe_pwrite(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "pwrite"; - - VALUE* strp = valv_get_strp(custname, count, vals, 1, "string"); - - int fd = valv_get_num_long(custname, count, vals, 0, "fd"); - - ssize_t w = write(fd, - strp->v_str->s_str, - strp->v_str->s_len); - - if (w < 0) math_error("%s: "__FILE__": %d: write: %s", custname, __LINE__, strerror(errno)); - - int e = close(fd); - - if (e) math_error("%s: "__FILE__": %d: close: %s", custname, __LINE__, strerror(errno)); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(w); - return result; + const char *custname = "pwrite"; + + VALUE *strp = valv_get_strp(custname, count, vals, 1, "string"); + + int fd = valv_get_num_long(custname, count, vals, 0, "fd"); + + ssize_t w = write(fd, strp->v_str->s_str, strp->v_str->s_len); + + if (w < 0) + math_error("%s: "__FILE__ ": %d: write: %s", custname, __LINE__, + strerror(errno)); + + int e = close(fd); + + if (e) + math_error("%s: "__FILE__ ": %d: close: %s", custname, __LINE__, + strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(w); + return result; } -#define pfe_pfe_SIZE_BUFFER 4096 -#define pfe_pfe_SIZE_INIT 4096 + #define pfe_pfe_SIZE_BUFFER 4096 + #define pfe_pfe_SIZE_INIT 4096 -char* strext(char** subject, char* with) { - size_t n = strlen(*subject) + strlen(with); - if ((*subject = reallocf(*subject, n+1)) == NULL) return NULL; - strlcat(*subject, with, n+1); - return *subject; +char * +strext(char **subject, char *with) +{ + size_t n = strlen(*subject) + strlen(with); + if ((*subject = reallocf(*subject, n + 1)) == NULL) return NULL; + strlcat(*subject, with, n + 1); + return *subject; } /* @@ -1116,89 +1271,105 @@ char* strext(char** subject, char* with) { VALUE u_pfe_pread(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "pread"; - - int pid = valv_get_num_long(custname, count, vals, 0, "pid"); - int out = valv_get_num_long(custname, count, vals, 1, "out"); - int err = valv_get_num_long(custname, count, vals, 2, "err"); - - fd_set nvm; FD_ZERO(&nvm); // never mind - fd_set rbs; FD_ZERO(&rbs); // read base set - int ssz = 0; - FD_SET(out, &rbs); if (out > ssz) ssz = out; - FD_SET(err, &rbs); if (err > ssz) ssz = err; - - // Keep track of rbs - bool eoo = NULL; // end of out - bool eoe = NULL; // end of err - - char* o = malloc(pfe_pfe_SIZE_INIT*sizeof(char)); o[0] = '\0'; - char* e = malloc(pfe_pfe_SIZE_INIT*sizeof(char)); e[0] = '\0'; - - char ob[pfe_pfe_SIZE_BUFFER]; // out buffer - char eb[pfe_pfe_SIZE_BUFFER]; // err buffer - - int pco = 0; - int pce = 0; - - fd_set rcs; // read check set - while (!eoo || !eoe) { - FD_COPY(&rbs, &rcs); - - int r = select(1+ssz, &rcs, &nvm, &nvm, NULL); - if (r < 0) math_error("%s: "__FILE__": %d: select: %s", custname, __LINE__, strerror(errno)); - - if (FD_ISSET(out, &rcs)) { - r = read(out, &ob, pfe_pfe_SIZE_BUFFER); - if (r < 0) math_error("%s: "__FILE__": %d: (out, %lu) read: %s", custname, __LINE__, strlen(o), strerror(errno)); - if (r) { - ob[r] = '\0'; - strext(&o, ob); - } else { - if(close(out)) pco = errno; - FD_CLR(out, &rbs); - eoo = TRUE; - } - } - if (FD_ISSET(err, &rcs)) { - r = read(err, &eb, pfe_pfe_SIZE_BUFFER); - if (r < 0) math_error("%s: "__FILE__": %d: (err, %lu) read: %s", custname, __LINE__, strlen(e), strerror(errno)); - if (r) { - eb[r] = '\0'; - strext(&e, eb); - } else { - if(close(err)) pce = errno; - FD_CLR(err, &rbs); - eoe = TRUE; - } - } - } - - if (pco) math_error("%s: "__FILE__": %d: (out) close: %s", custname, __LINE__, strerror(pco)); - if (pce) math_error("%s: "__FILE__": %d: (err) close: %s", custname, __LINE__, strerror(pce)); - - int stt = 0; - pid_t w = wait4(pid, &stt, 0, NULL); - - if (0 > w) math_error("%s: "__FILE__": %d: wait4: %s", custname, __LINE__, strerror(errno)); - - NUMBER* r = itoq( - (!WIFEXITED(stt) ? 0 : WEXITSTATUS(stt)) + - (!WIFSTOPPED(stt) ? 0 : 128 + WSTOPSIG(stt)) + - (!WIFSIGNALED(stt) ? 0 : 128 + WTERMSIG(stt)) - ); - - LIST* list = listalloc(); - insertlistlast(list, alloc_num(r)); - insertlistlast(list, alloc_str(makestring(o))); - insertlistlast(list, alloc_str(makestring(e))); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_LIST; - - result.v_list = list; - return result; + const char *custname = "pread"; + + int pid = valv_get_num_long(custname, count, vals, 0, "pid"); + int out = valv_get_num_long(custname, count, vals, 1, "out"); + int err = valv_get_num_long(custname, count, vals, 2, "err"); + + fd_set nvm; // never mind + FD_ZERO(&nvm); + fd_set rbs; // read base set + FD_ZERO(&rbs); + int ssz = 0; + FD_SET(out, &rbs); + if (out > ssz) ssz = out; + FD_SET(err, &rbs); + if (err > ssz) ssz = err; + + // Keep track of rbs + bool eoo = NULL; // end of out + bool eoe = NULL; // end of err + + char *o = malloc(pfe_pfe_SIZE_INIT * sizeof(char)); + o[0] = '\0'; + char *e = malloc(pfe_pfe_SIZE_INIT * sizeof(char)); + e[0] = '\0'; + + char ob[pfe_pfe_SIZE_BUFFER]; // out buffer + char eb[pfe_pfe_SIZE_BUFFER]; // err buffer + + int pco = 0; + int pce = 0; + + fd_set rcs; // read check set + while (!eoo || !eoe) { + FD_COPY(&rbs, &rcs); + + int r = select(1 + ssz, &rcs, &nvm, &nvm, NULL); + if (r < 0) + math_error("%s: "__FILE__ ": %d: select: %s", custname, __LINE__, + strerror(errno)); + + if (FD_ISSET(out, &rcs)) { + r = read(out, &ob, pfe_pfe_SIZE_BUFFER); + if (r < 0) + math_error("%s: "__FILE__ ": %d: (out, %lu) read: %s", custname, + __LINE__, strlen(o), strerror(errno)); + if (r) { + ob[r] = '\0'; + strext(&o, ob); + } else { + if (close(out)) pco = errno; + FD_CLR(out, &rbs); + eoo = TRUE; + } + } + if (FD_ISSET(err, &rcs)) { + r = read(err, &eb, pfe_pfe_SIZE_BUFFER); + if (r < 0) + math_error("%s: "__FILE__ ": %d: (err, %lu) read: %s", custname, + __LINE__, strlen(e), strerror(errno)); + if (r) { + eb[r] = '\0'; + strext(&e, eb); + } else { + if (close(err)) pce = errno; + FD_CLR(err, &rbs); + eoe = TRUE; + } + } + } + + if (pco) + math_error("%s: "__FILE__ ": %d: (out) close: %s", custname, __LINE__, + strerror(pco)); + if (pce) + math_error("%s: "__FILE__ ": %d: (err) close: %s", custname, __LINE__, + strerror(pce)); + + int stt = 0; + pid_t w = wait4(pid, &stt, 0, NULL); + + if (0 > w) + math_error("%s: "__FILE__ ": %d: wait4: %s", custname, __LINE__, + strerror(errno)); + + NUMBER *r = itoq((!WIFEXITED(stt) ? 0 : WEXITSTATUS(stt)) + + (!WIFSTOPPED(stt) ? 0 : 128 + WSTOPSIG(stt)) + + (!WIFSIGNALED(stt) ? 0 : 128 + WTERMSIG(stt))); + + LIST *list = listalloc(); + insertlistlast(list, alloc_num(r)); + insertlistlast(list, alloc_str(makestring(o))); + insertlistlast(list, alloc_str(makestring(e))); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_LIST; + + result.v_list = list; + return result; } /* @@ -1211,16 +1382,16 @@ u_pfe_pread(char *UNUSED(name), int count, VALUE **vals) VALUE u_vadd_getpid(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) { - const char* UNUSED(custname) = "getpid"; - - pid_t pid = getpid(); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(pid); - return result; + const char *UNUSED(custname) = "getpid"; + + pid_t pid = getpid(); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(pid); + return result; } /* @@ -1233,16 +1404,16 @@ u_vadd_getpid(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) VALUE u_vadd_getppid(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) { - const char* UNUSED(custname) = "getppid"; - - pid_t pid = getppid(); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_NUM; - - result.v_num = itoq(pid); - return result; + const char *UNUSED(custname) = "getppid"; + + pid_t pid = getppid(); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_NUM; + + result.v_num = itoq(pid); + return result; } /* @@ -1255,17 +1426,20 @@ u_vadd_getppid(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) VALUE u_vadd_getcwd(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) { - const char* custname = "getcwd"; - - char* buf = getcwd(NULL, -1); // doing equiv(malloc) COULD use MAXPATHLEN from and s/makestring/makenewstring/ below I guess - if (!buf) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_STR; - - result.v_str = makestring(buf); - return result; + const char *custname = "getcwd"; + + char *buf = getcwd(NULL, + -1); // doing equiv(malloc) COULD use MAXPATHLEN from and s/makestring/makenewstring/ below I guess + if (!buf) + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_STR; + + result.v_str = makestring(buf); + return result; } /* @@ -1276,19 +1450,22 @@ u_vadd_getcwd(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) */ /*ARGSUSED*/ VALUE -u_vadd_inputname(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) //cspell:ignore inputname +u_vadd_inputname(char *UNUSED(name), int UNUSED(count), + VALUE **UNUSED(vals)) //cspell:ignore inputname { - const char* UNUSED(custname) = "inputname"; - - char* buf = inputname(); - if (!buf) buf = inputisterminal() ? "" : ""; //cspell:ignore inputisterminal - - VALUE result; - result.v_subtype = 0; - result.v_type = V_STR; - - result.v_str = makenewstring(buf); - return result; + const char *UNUSED(custname) = "inputname"; + + char *buf = inputname(); + if (!buf) + buf = inputisterminal() ? "" + : ""; //cspell:ignore inputisterminal + + VALUE result; + result.v_subtype = 0; + result.v_type = V_STR; + + result.v_str = makenewstring(buf); + return result; } /* @@ -1304,19 +1481,21 @@ u_vadd_inputname(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) // VALUE u_vadd_basename(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "basename"; - - VALUE* strp = valv_get_strp(custname, count, vals, 0, "path"); - - char buf[MAXPATHLEN]; - if (!basename_r(strp->v_str->s_str, buf)) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_STR; - - result.v_str = makenewstring(buf); - return result; + const char *custname = "basename"; + + VALUE *strp = valv_get_strp(custname, count, vals, 0, "path"); + + char buf[MAXPATHLEN]; + if (!basename_r(strp->v_str->s_str, buf)) + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_STR; + + result.v_str = makenewstring(buf); + return result; } /* @@ -1332,19 +1511,21 @@ u_vadd_basename(char *UNUSED(name), int count, VALUE **vals) VALUE u_vadd_dirname(char *UNUSED(name), int count, VALUE **vals) { - const char* custname = "dirname"; - - VALUE* strp = valv_get_strp(custname, count, vals, 0, "path"); - - char buf[MAXPATHLEN]; - if (!dirname_r(strp->v_str->s_str, buf)) math_error("%s: "__FILE__": %d: %s", custname, __LINE__, strerror(errno)); - - VALUE result; - result.v_subtype = 0; - result.v_type = V_STR; - - result.v_str = makenewstring(buf); - return result; + const char *custname = "dirname"; + + VALUE *strp = valv_get_strp(custname, count, vals, 0, "path"); + + char buf[MAXPATHLEN]; + if (!dirname_r(strp->v_str->s_str, buf)) + math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, + strerror(errno)); + + VALUE result; + result.v_subtype = 0; + result.v_type = V_STR; + + result.v_str = makenewstring(buf); + return result; } #endif /* CUSTOM */ From 9bc9a098225ec14c6801fe3cb6e298e3b8c02c6a Mon Sep 17 00:00:00 2001 From: vike Date: Wed, 24 Jul 2024 13:02:21 +0200 Subject: [PATCH 11/21] gitignore .clang-format & fix some sorting --- .gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 3156aeeec..1ed018651 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,9 @@ charbit.h chatbit chk_c .cache/clangd +.clang-format +compile_commands.json +compile_flags.txt conf.h const_tmp cscript/4dsphere @@ -55,8 +58,6 @@ cscript/square custom/.all custom/libcustcalc* custom/.gitignore -compile_commands.json -compile_flags.txt debug.out .dynamic endian From c294b20c0df4686752f7ceeb3b6c9d0b1ce8ecce Mon Sep 17 00:00:00 2001 From: vike Date: Thu, 8 Aug 2024 03:52:32 +0200 Subject: [PATCH 12/21] clang-format (patched) of custom/pfe.cal --- .gitignore | 1 + custom/pfe.cal | 261 +++++++++++++++++++++++++------------------------ 2 files changed, 136 insertions(+), 126 deletions(-) diff --git a/.gitignore b/.gitignore index 1ed018651..b4172a064 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ chatbit chk_c .cache/clangd .clang-format +clang-format-testee.c compile_commands.json compile_flags.txt conf.h diff --git a/custom/pfe.cal b/custom/pfe.cal index 5c8c84143..45a31d485 100644 --- a/custom/pfe.cal +++ b/custom/pfe.cal @@ -25,147 +25,156 @@ * and run with a -C arg. */ if (config("compile_custom") == 0) { - quit "calc compiled without -DCUSTOM"; + quit "calc compiled without -DCUSTOM"; } else if (config("allow_custom") == 0) { - quit "calc was run without the -C command line option"; + quit "calc was run without the -C command line option"; } define pfe_base_test() { - local file; - local fork = custom("fork"); - local fds = custom("pipe"); - if (fork) { - if (custom("write", fds[1], "test") != 4) quit "error in write"; - if (custom("close", fds[1])) quit "error in close"; - local rd = custom("read", fds[0]); - local status = assoc(); - custom("wait4", &status); - if (rd != "test") { - file = fopen("/dev/stderr", "w"); - fprintf(file, "mismatch of read: %s\n", rd); - quit; - } - if (status["exitstatus"] != 0) { - file = fopen("/dev/stderr", "w"); - fprintf(file, "mismatch of status: %d\n", status); - quit; - } - } else { - if (custom("close", fds[1])) quit "error in close"; - local args = list("sh", "-c", "{ read||:;}&&printf %s $REPLY"); - if (0 > custom("dup2", fds[0], 0)) quit "error in dup2"; - if (!custom("execvp", args[0], args)) quit "error in execvp"; - } + local file; + local fork = custom("fork"); + local fds = custom("pipe"); + if (fork) { + if (custom("write", fds[1], "test") != 4) quit "error in write"; + if (custom("close", fds[1])) quit "error in close"; + local rd = custom("read", fds[0]); + local status = assoc(); + custom("wait4", &status); + if (rd != "test") { + file = fopen("/dev/stderr", "w"); + fprintf(file, "mismatch of read: %s\n", rd); + quit; + } + if (status["exitstatus"] != 0) { + file = fopen("/dev/stderr", "w"); + fprintf(file, "mismatch of status: %d\n", status); + quit; + } + } else { + if (custom("close", fds[1])) quit "error in close"; + local args = list("sh", "-c", "{ read||:;}&&printf %s $REPLY"); + if (0 > custom("dup2", fds[0], 0)) quit "error in dup2"; + if (!custom("execvp", args[0], args)) quit "error in execvp"; + } } -define pipe() = custom("pipe"); -define fork() = custom("fork"); -define close(fd) = custom("close", fd); +define pipe() = custom("pipe"); +define fork() = custom("fork"); +define close(fd) = custom("close", fd); define fds(rdl, wtl, exl, timeout) = custom("select", rdl, wtl, exl, timeout); -define poll(in, out, timeout) = custom("poll", in, out, timeout); -define dup(src) = custom("dup", src); -define dup2(src, tgt) = custom("dup2", src, tgt); -define execvp(path, args) = custom("execvp", path, args); -define wt(fd, str) = custom("write", fd, str); -define rd(fd) = custom("read", fd); -define wait4(pid, stt, opt, usg) = custom("wait4", pid, stt, opt, usg); +define poll(in, out, timeout) = custom("poll", in, out, timeout); +define dup(src) = custom("dup", src); +define dup2(src, tgt) = custom("dup2", src, tgt); +define execvp(path, args) = custom("execvp", path, args); +define wt(fd, str) = custom("write", fd, str); +define rd(fd) = custom("read", fd); +define wait4(pid, stt, opt, usg) = custom("wait4", pid, stt, opt, usg); define pfe(in, out, err, args) = custom("pfe", in, out, err, args); -define pwrite(fd, str) = custom("pwrite", fd, str); -define pread(pid, out, err) = custom("pread", pid, out, err); - -define pfe_test() { - local r p i o e; - if (p = pfe(&i, &o, &e, list("sh", "-c", "read -rd '' || e=$?; printf %s \"$REPLY\""))) { - if (pwrite(i, "test\n") != 5) quit "bad write"; - r = pread(p, o, e); - if (r[0] != 0 ) quit "bad exit"; - if (r[1] != "test\n") quit "bad read"; - } +define pwrite(fd, str) = custom("pwrite", fd, str); +define pread(pid, out, err) = custom("pread", pid, out, err); + +define pfe_test() +{ + local r p i o e; + if (p = pfe(&i, &o, &e, + list("sh", "-c", "read -rd '' || e=$?; printf %s \"$REPLY\""))) { + if (pwrite(i, "test\n") != 5) quit "bad write"; + r = pread(p, o, e); + if (r[0] != 0) quit "bad exit"; + if (r[1] != "test\n") quit "bad read"; + } } -define pfe_cal(in, out, err, args) { - local di = pipe(); ##// dn in - local uo = pipe(); ##// up out - local ue = pipe(); ##// up err - - *in = di[1]; - *out = uo[0]; - *err = ue[0]; - - local e pid; - if (pid = fork()) { - if (close(di[0])) quit "pfe: error in parent closing reading child input"; - if (close(ue[1])) quit "pfe: error in parent closing writing child output"; - if (close(uo[1])) quit "pfe: error in parent closing writing child error"; - - return pid; - } else { - if (close(uo[0])) quit "pfe: error in child closing reading output"; - if (close(ue[0])) quit "pfe: error in child closing reading error"; - if (close(di[1])) quit "pfe: error in child closing writing input"; - - if (dup2(di[0], 0) != 0) quit "pfe: mismatch in child duplication of input"; - if (dup2(uo[1], 1) != 1) quit "pfe: mismatch in child duplication of output"; - if (dup2(ue[1], 2) != 2) quit "pfe: mismatch in child duplication of error"; - - e = execvp(args[0], args); - } -;} -define pwrite_cal(in, str) { - local w = wt(in, str); - if (w != strlen(str)) quit "pwrite: mismatch"; - if (close(in)) quit "pwrite: error closing"; - return w; +define pfe_cal(in, out, err, args) +{ + local di = pipe(); ##// dn in + local uo = pipe(); ##// up out + local ue = pipe(); ##// up err + + *in = di[1]; + *out = uo[0]; + *err = ue[0]; + + local e pid; + if (pid = fork()) { + if (close(di[0])) + quit "pfe: error in parent closing reading child input"; + if (close(ue[1])) + quit "pfe: error in parent closing writing child output"; + if (close(uo[1])) + quit "pfe: error in parent closing writing child error"; + + return pid; + } else { + if (close(uo[0])) quit "pfe: error in child closing reading output"; + if (close(ue[0])) quit "pfe: error in child closing reading error"; + if (close(di[1])) quit "pfe: error in child closing writing input"; + + if (dup2(di[0], 0) != 0) + quit "pfe: mismatch in child duplication of input"; + if (dup2(uo[1], 1) != 1) + quit "pfe: mismatch in child duplication of output"; + if (dup2(ue[1], 2) != 2) + quit "pfe: mismatch in child duplication of error"; + + e = execvp(args[0], args); + }; } -define pread_cal(pid, out, err) { - local NULL = null(); - - local rbl = list(out, err); ##// read base list - - local oud = ""; ##// out data - local erd = ""; ##// err data - - while (local rbz = size(rbl)) { - local rcl = rbl; ##// read check list - local exl = list(out, err); - - local fdc = fds(&rcl); - - if (0 < fdc) { - local rcz = size(rcl); - - for (local rcs = 0; rcz > rcs; rcs++) { - - local rcd = rd(rcl[rcs]); - if (rcl[rcs] == out) - if (rcd != NULL) oud = strcat(oud, rcd); - else delete(rbl, search(rbl, out)); - if (rcl[rcs] == err) - if (rcd != NULL) erd = strcat(erd, rcd); - else delete(rbl, search(rbl, err)); - } - } - } - local stt = assoc(); - pid = wait4(pid, &stt); - return list( - (!stt["exited"] ? 0 : stt["exitstatus"]) + - (!stt["stopped"] ? 0 : 128 + stt["stopsig"]) + - (!stt["signaled"] ? 0 : 128 + stt["termsig"]), - oud, erd - ); +define pwrite_cal(in, str) +{ + local w = wt(in, str); + if (w != strlen(str)) quit "pwrite: mismatch"; + if (close(in)) quit "pwrite: error closing"; + return w; } +define pread_cal(pid, out, err) +{ + local NULL = null(); + + local rbl = list(out, err); ##// read base list + + local oud = ""; ##// out data + local erd = ""; ##// err data + + while (local rbz = size(rbl)) { + local rcl = rbl; ##// read check list + local exl = list(out, err); -define pfe_cal_test() { - local r p i o e; - if (p = pfe_cal(&i, &o, &e, list("sh", "-c", "read -rd '' || e=$?; printf %s \"$REPLY\""))) { - if (pwrite_cal(i, "test\n") != 5) quit "bad write"; - r = pread_cal(p, o, e); - if (r[0] != 0) quit "bad exit"; - if (r[1] != "test\n") quit "bad read"; - } + local fdc = fds(&rcl); + + if (0 < fdc) { + local rcz = size(rcl); + + for (local rcs = 0; rcz > rcs; rcs++) { + local rcd = rd(rcl[rcs]); + if (rcl[rcs] == out) + if (rcd != NULL) oud = strcat(oud, rcd); + else delete(rbl, search(rbl, out)); + if (rcl[rcs] == err) + if (rcd != NULL) erd = strcat(erd, rcd); + else delete(rbl, search(rbl, err)); + } + } + } + local stt = assoc(); + pid = wait4(pid, &stt); + return list((!stt["exited"] ? 0 : stt["exitstatus"]) + + (!stt["stopped"] ? 0 : 128 + stt["stopsig"]) + + (!stt["signaled"] ? 0 : 128 + stt["termsig"]), + oud, erd); } +define pfe_cal_test() +{ + local r p i o e; + if (p = pfe_cal(&i, &o, &e, + list("sh", "-c", "read -rd '' || e=$?; printf %s \"$REPLY\""))) { + if (pwrite_cal(i, "test\n") != 5) quit "bad write"; + r = pread_cal(p, o, e); + if (r[0] != 0) quit "bad exit"; + if (r[1] != "test\n") quit "bad read"; + } +} From ff174b1f6d79e778965e4128763edaa2d11b77d7 Mon Sep 17 00:00:00 2001 From: vike Date: Fri, 9 Aug 2024 08:47:04 +0200 Subject: [PATCH 13/21] fixing execv* argv NULL pointer termination --- custom/u_pfe.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/custom/u_pfe.c b/custom/u_pfe.c index e05971365..90cf3812f 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -471,7 +471,7 @@ u_pfe_execvp(char *UNUSED(name), int count, VALUE **vals) VALUE *args_list = valv_get_list(custname, count, vals, 1, "args"); char **args; - if (!(args = malloc(sizeof(char *) * args_list->v_list->l_count))) + if (!(args = malloc(sizeof(char *) * (args_list->v_list->l_count + 1)))) math_error("%s: "__FILE__ ": %d: malloc: %s", custname, __LINE__, strerror(errno)); @@ -484,6 +484,7 @@ u_pfe_execvp(char *UNUSED(name), int count, VALUE **vals) args[s] = el->e_value.v_str->s_str; } + args[s] = NULL; if (execvp(path, args)) math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, @@ -1173,7 +1174,7 @@ u_pfe_pfe(char *UNUSED(name), int count, VALUE **vals) VALUE *args_list = valv_get_list(custname, count, vals, 3, "args"); char **args; - if (!(args = malloc(sizeof(char *) * args_list->v_list->l_count))) + if (!(args = malloc(sizeof(char *) * (args_list->v_list->l_count + 1)))) math_error("%s: "__FILE__ ": %d: malloc: %s", custname, __LINE__, strerror(errno)); @@ -1186,6 +1187,7 @@ u_pfe_pfe(char *UNUSED(name), int count, VALUE **vals) args[s] = el->e_value.v_str->s_str; } + args[s] = NULL; if (execvp(args[0], args)) math_error("%s: "__FILE__ ": %d: execvp: %s", custname, __LINE__, From b7bd76b825e430e6168bd515b36d6bed778fa03c Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Sun, 27 Apr 2025 21:10:24 -0700 Subject: [PATCH 14/21] Update u_pfe.c Fix system include file. --- custom/u_pfe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom/u_pfe.c b/custom/u_pfe.c index 90cf3812f..3ae2da839 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -35,7 +35,7 @@ int u_pfe_allowed = 0; /* CUSTOM undefined */ #if defined(CUSTOM) - #include + #include #include #include // MAXPATHLEN attow #include From 6a80a247407768b984a7724b11ef6e4cbce169bc Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Sun, 27 Apr 2025 21:23:59 -0700 Subject: [PATCH 15/21] Update u_pfe.c Try to fix more compile problems under Linux. --- custom/u_pfe.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/custom/u_pfe.c b/custom/u_pfe.c index 3ae2da839..b105453ce 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -45,6 +45,7 @@ int u_pfe_allowed = 0; /* CUSTOM undefined */ #include #include #include + #include #include "../have_const.h" #include "../value.h" @@ -1251,7 +1252,7 @@ char * strext(char **subject, char *with) { size_t n = strlen(*subject) + strlen(with); - if ((*subject = reallocf(*subject, n + 1)) == NULL) return NULL; + if ((*subject = realloc(*subject, n + 1)) == NULL) return NULL; strlcat(*subject, with, n + 1); return *subject; } @@ -1488,7 +1489,7 @@ u_vadd_basename(char *UNUSED(name), int count, VALUE **vals) VALUE *strp = valv_get_strp(custname, count, vals, 0, "path"); char buf[MAXPATHLEN]; - if (!basename_r(strp->v_str->s_str, buf)) + if (!basename(strp->v_str->s_str, buf)) math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); @@ -1518,7 +1519,7 @@ u_vadd_dirname(char *UNUSED(name), int count, VALUE **vals) VALUE *strp = valv_get_strp(custname, count, vals, 0, "path"); char buf[MAXPATHLEN]; - if (!dirname_r(strp->v_str->s_str, buf)) + if (!dirname(strp->v_str->s_str, buf)) math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); From 84f74d95877b26a8b328a5824f03b4b67c62625e Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Sun, 27 Apr 2025 21:52:41 -0700 Subject: [PATCH 16/21] undo Update u_pfe.c We undo the attempt to fix the code by the previous commit. --- custom/u_pfe.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/custom/u_pfe.c b/custom/u_pfe.c index b105453ce..3ae2da839 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -45,7 +45,6 @@ int u_pfe_allowed = 0; /* CUSTOM undefined */ #include #include #include - #include #include "../have_const.h" #include "../value.h" @@ -1252,7 +1251,7 @@ char * strext(char **subject, char *with) { size_t n = strlen(*subject) + strlen(with); - if ((*subject = realloc(*subject, n + 1)) == NULL) return NULL; + if ((*subject = reallocf(*subject, n + 1)) == NULL) return NULL; strlcat(*subject, with, n + 1); return *subject; } @@ -1489,7 +1488,7 @@ u_vadd_basename(char *UNUSED(name), int count, VALUE **vals) VALUE *strp = valv_get_strp(custname, count, vals, 0, "path"); char buf[MAXPATHLEN]; - if (!basename(strp->v_str->s_str, buf)) + if (!basename_r(strp->v_str->s_str, buf)) math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); @@ -1519,7 +1518,7 @@ u_vadd_dirname(char *UNUSED(name), int count, VALUE **vals) VALUE *strp = valv_get_strp(custname, count, vals, 0, "path"); char buf[MAXPATHLEN]; - if (!dirname(strp->v_str->s_str, buf)) + if (!dirname_r(strp->v_str->s_str, buf)) math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); From f33aa19f97adb534c902020bd25eff25f49b6153 Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Mon, 28 Apr 2025 12:23:06 -0700 Subject: [PATCH 17/21] Update u_pfe.c #include --- custom/u_pfe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/custom/u_pfe.c b/custom/u_pfe.c index 3ae2da839..562a807a7 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -45,6 +45,7 @@ int u_pfe_allowed = 0; /* CUSTOM undefined */ #include #include #include + #include #include "../have_const.h" #include "../value.h" From dbd0392a9f43de730e36ed3a886709a36d4043a6 Mon Sep 17 00:00:00 2001 From: vike Date: Sun, 14 Sep 2025 13:11:31 +0200 Subject: [PATCH 18/21] fix compat issues, re https://github.com/lcn2/calc/pull/153#pullrequestreview-2797981455 --- custom/u_pfe.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/custom/u_pfe.c b/custom/u_pfe.c index 90cf3812f..7709730c7 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -35,7 +35,7 @@ int u_pfe_allowed = 0; /* CUSTOM undefined */ #if defined(CUSTOM) - #include + #include #include #include // MAXPATHLEN attow #include @@ -1251,7 +1251,10 @@ char * strext(char **subject, char *with) { size_t n = strlen(*subject) + strlen(with); - if ((*subject = reallocf(*subject, n + 1)) == NULL) return NULL; + if ((*subject = realloc(*subject, n + 1)) == NULL) { + free(*subject); + return NULL; + } strlcat(*subject, with, n + 1); return *subject; } @@ -1306,7 +1309,7 @@ u_pfe_pread(char *UNUSED(name), int count, VALUE **vals) fd_set rcs; // read check set while (!eoo || !eoe) { - FD_COPY(&rbs, &rcs); + memmove(&rcs, &rbs, sizeof(fd_set)); int r = select(1 + ssz, &rcs, &nvm, &nvm, NULL); if (r < 0) @@ -1488,7 +1491,8 @@ u_vadd_basename(char *UNUSED(name), int count, VALUE **vals) VALUE *strp = valv_get_strp(custname, count, vals, 0, "path"); char buf[MAXPATHLEN]; - if (!basename_r(strp->v_str->s_str, buf)) + strlcpy(buf, basename(strp->v_str->s_str), sizeof(buf)); + if (!*buf) math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); @@ -1518,7 +1522,8 @@ u_vadd_dirname(char *UNUSED(name), int count, VALUE **vals) VALUE *strp = valv_get_strp(custname, count, vals, 0, "path"); char buf[MAXPATHLEN]; - if (!dirname_r(strp->v_str->s_str, buf)) + strlcpy(buf, dirname(strp->v_str->s_str), sizeof(buf)); + if (!*buf) math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); From bc2ed54fcf48dc99df2f624ffd191a01d28d6ecc Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Mon, 15 Sep 2025 00:01:40 -0700 Subject: [PATCH 19/21] update PR 153 with critical edits As mentioned in various comments in PR #153: https://github.com/lcn2/calc/pull/153 we needed to modify the PR you sent us for various reasons, including but not limited to having to satiny a number of older systems on which calc v2 needs to run. Please examine these "mods to your mods" and see if they are OK form your perspective. Feel free to update your PR if you find any issues. Once you approve or update your PR, we will complete our review. --- .gitignore | 5 +- CHANGES | 27 +- COPYING | 1 + custhelp | 1 - custom/Makefile | 33 ++ custom/custtbl.c | 86 +-- custom/pfe | 114 ++-- custom/pfe.cal | 5 +- custom/u_pfe.c | 1460 ++++++++++++++++++++++++++++++++-------------- file.h | 2 +- 10 files changed, 1168 insertions(+), 566 deletions(-) delete mode 120000 custhelp mode change 100755 => 100644 custom/pfe diff --git a/.gitignore b/.gitignore index 6fef61474..4bde7a61f 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ align32.h align32_tmp arc4random_tmp args.h +.cache/clangd cal/.all calc calc.1 @@ -37,7 +38,6 @@ cal/test082.cal charbit.h chatbit chk_c -.cache/clangd .clang-format clang-format-testee.c compile_commands.json @@ -56,7 +56,6 @@ cscript/simple cscript/square custom/.all custom/libcustcalc* -custom/.gitignore debug.out .dynamic endian @@ -186,6 +185,6 @@ uid_tmp unused_tmp ustat_tmp ver_calc -vs_tmp .vscode +vs_tmp win32/ diff --git a/CHANGES b/CHANGES index a59f34831..a2cbc937d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,21 @@ +The following are the changes from calc version 2.16.0.0 to 2.16.0.1: + + Adding support for "pipe/fork/exec and friends" via custom functions + thanks to a contribution by GitHub user @vike2000. + + We to address a bug after adding support for pipe/fork/exec (and + friends) via custom functions + + TODO: Before the calc v2 to calc v3 fork, we need to fix a critical + [bug](https://github.com/lcn2/calc/issues/103#issuecomment-3194363618) + related to heap-use-after-free memory errors. We anticipate this + will involve releasing a bug fix version of calc and then allow + for extensive testing before declaring the resulting 2.16.0.x as a + stable release. From that 2.16.0.x stable release that a new version + 2.16.1.0 stable release, with no changes other than a new version + number and git tag as the basis for the calc v2 to calc v3 fork. + + The following are the changes from calc version 2.15.1.2 to 2.16.0.0: Starting with calc version 2.16.0.0, the ability to perform arithmetic @@ -27,10 +45,6 @@ The following are the changes from calc version 2.15.1.2 to 2.16.0.0: Added E_INVALID_ADDR_OP (10611) error code to indicate an invalid arithmetic address operation. - We plan to let this most recent change settle down before performing - the calc v2 to calc v3 fork. Therefore, version 2.16.1.0 will form - the basis for the calc v2 to calc v3 fork. - The following are the changes from calc version 2.15.1.2 to 2.15.1.2: @@ -51,11 +65,6 @@ The following are the changes from calc version 2.15.1.1 to 2.15.1.1: Put full date range (1989-2025) of calc source into version.h. - Adding support for pipe/fork/exec via custom functions thanks - to a contribution by GitHub user @vike2000. - - Version 2.16.0.0 will form the basis for the calc v2 to calc v3 fork. - The following are the changes from calc version 2.15.0.7 to 2.15.1.0: diff --git a/COPYING b/COPYING index 4842db7c7..8801df956 100644 --- a/COPYING +++ b/COPYING @@ -122,6 +122,7 @@ Calc copyrights and exception files Copyright (C) year Christoph Zurnieden Copyright (C) year Landon Curt Noll and Thomas Jones-Low Copyright (C) year Klaus Alexander Seistrup and Landon Curt Noll + Copyright (C) year Viktor Bergquist These files are not covered under one of the Copyrights listed above: diff --git a/custhelp b/custhelp deleted file mode 120000 index 8f4052a5c..000000000 --- a/custhelp +++ /dev/null @@ -1 +0,0 @@ -custom \ No newline at end of file diff --git a/custom/Makefile b/custom/Makefile index 3ba6e411a..0c408188d 100644 --- a/custom/Makefile +++ b/custom/Makefile @@ -976,3 +976,36 @@ custtbl.o: ../value.h custtbl.o: ../version.h custtbl.o: ../zmath.h custtbl.o: custtbl.c +u_pfe.o: ../alloc.h +u_pfe.o: ../attribute.h +u_pfe.o: ../banned.h +u_pfe.o: ../block.h +u_pfe.o: ../bool.h +u_pfe.o: ../byteswap.h +u_pfe.o: ../calc.h +u_pfe.o: ../charbit.h +u_pfe.o: ../cmath.h +u_pfe.o: ../config.h +u_pfe.o: ../custom.h +u_pfe.o: ../decl.h +u_pfe.o: ../endian_calc.h +u_pfe.o: ../errsym.h +u_pfe.o: ../errtbl.h +u_pfe.o: ../hash.h +u_pfe.o: ../have_ban_pragma.h +u_pfe.o: ../have_const.h +u_pfe.o: ../have_limits.h +u_pfe.o: ../have_newstr.h +u_pfe.o: ../have_stdbool.h +u_pfe.o: ../have_stdlib.h +u_pfe.o: ../have_string.h +u_pfe.o: ../have_unused.h +u_pfe.o: ../longbits.h +u_pfe.o: ../nametype.h +u_pfe.o: ../qmath.h +u_pfe.o: ../sha1.h +u_pfe.o: ../str.h +u_pfe.o: ../value.h +u_pfe.o: ../version.h +u_pfe.o: ../zmath.h +u_pfe.o: u_pfe.c diff --git a/custom/custtbl.c b/custom/custtbl.c index e13aed739..e6b9256c1 100644 --- a/custom/custtbl.c +++ b/custom/custtbl.c @@ -163,49 +163,49 @@ CONST struct custom cust[] = { { "register", "get or set customer registers", 1, 2, c_register }, - { "fork", "create process", - 0, 0, u_pfe_fork }, - { "pipe", "create descriptor pair for interprocess communication", - 0, 0, u_pfe_pipe }, - { "dup", "duplicate a file descriptor", - 1, 1, u_pfe_dup }, - { "dup2", "duplicate a file descriptor", - 2, 2, u_pfe_dup2 }, - { "close", "remove a file descriptor", - 1, 1, u_pfe_close }, - { "execvp", "execute a file", - 2, 2, u_pfe_execvp }, - { "write", "write output", - 2, 2, u_pfe_write }, - { "read", "read input", - 1, 2, u_pfe_read }, - { "select", "examine file descriptors", - 3, 4, u_pfe_select }, - { "poll", "synchronous I/O multiplexing", - 2, 3, u_pfe_poll }, - - { "wait4", "wait for process", - 1, 4, u_pfe_wait4 }, - - { "pfe", "pipe/fork/exec", - 4, 4, u_pfe_pfe }, - { "pwrite", "write and close", - 2, 2, u_pfe_pwrite }, - { "pread", "read until eof, close and wait for exit status", - 3, 3, u_pfe_pread }, - - { "getpid", "get calling process identification", - 0, 0, u_vadd_getpid }, - { "getppid", "get parent process identification", - 0, 0, u_vadd_getppid }, - { "getcwd", "get working directory pathname", - 0, 0, u_vadd_getcwd }, - { "inputname", "get name of input", - 0, 0, u_vadd_inputname }, - { "basename", "extract the base portion of a pathname", - 1, 1, u_vadd_basename }, - { "dirname", "extract the directory part of a pathname", - 1, 1, u_vadd_dirname }, + { "fork", "create process", + 0, 0, u_pfe_fork }, + { "pipe", "create descriptor pair for interprocess communication", + 0, 0, u_pfe_pipe }, + { "dup", "duplicate a file descriptor", + 1, 1, u_pfe_dup }, + { "dup2", "duplicate a file descriptor", + 2, 2, u_pfe_dup2 }, + { "close", "remove a file descriptor", + 1, 1, u_pfe_close }, + { "execvp", "execute a file", + 2, 2, u_pfe_execvp }, + { "write", "write output", + 2, 2, u_pfe_write }, + { "read", "read input", + 1, 2, u_pfe_read }, + { "select", "examine file descriptors", + 3, 4, u_pfe_select }, + { "poll", "synchronous I/O multiplexing", + 2, 3, u_pfe_poll }, + + { "wait4", "wait for process", + 1, 4, u_pfe_wait4 }, + + { "pfe", "pipe/fork/exec", + 4, 4, u_pfe_pfe }, + { "pwrite", "write and close", + 2, 2, u_pfe_pwrite }, + { "pread", "read until eof, close and wait for exit status", + 3, 3, u_pfe_pread }, + + { "getpid", "get calling process identification", + 0, 0, u_vadd_getpid }, + { "getppid", "get parent process identification", + 0, 0, u_vadd_getppid }, + { "getcwd", "get working directory pathname", + 0, 0, u_vadd_getcwd }, + { "inputname", "get name of input", + 0, 0, u_vadd_inputname }, + { "basename", "extract the base portion of a pathname", + 1, 1, u_vadd_basename }, + { "dirname", "extract the directory part of a pathname", + 1, 1, u_vadd_dirname }, #endif /* CUSTOM */ diff --git a/custom/pfe b/custom/pfe old mode 100755 new mode 100644 index fe4d85071..01d6367e9 --- a/custom/pfe +++ b/custom/pfe @@ -1,72 +1,72 @@ NAME - pfe - pipe/fork/exec and friends + pfe - pipe/fork/exec and friends SYNOPSIS - pipe = custom("pipe") ## create descriptor pair for interprocess communication - pid = custom("fork") ## create process - tgt = custom("dup", src) ## duplicate a file descriptor - tgt = custom("dup2", src, tgt) ## duplicate a file descriptor - e = custom("close", fd) ## remove a file descriptor - e = custom("execvp", arg0, args) ## execute a file - count = custom("write", fd, str) ## write output - str = custom("read", fd) ## read input - count = custom("select", rd, wt, exc[, timeout]) ## examine file descriptors - count = custom("poll", chk, &ret[, msecs]) ## synchronous I/O multiplexing - pid = custom("wait", [pid, ]&stt[, opts][, &usg]) ## wait for process - - pid = custom("pfe", &in, &out, &err, args) ## pipe/fork/exec - count = custom("pwrite", fd, str) ## write and close - e = custom("pread", pid, out, err) ## read until eof, close and wait for exit status - - str = custom("inputname") ## get name of input - path = custom("getcwd") ## get working directory pathname - - path = custom("basename", path) ## extract the base portion of a pathname - path = custom("dirname", path) ## extract the directory part of a pathname - - pid = custom("getpid") ## get calling process identification - pid = custom("getppid") ## get parent process identification + pipe = custom("pipe") ## create descriptor pair for interprocess communication + pid = custom("fork") ## create process + tgt = custom("dup", src) ## duplicate a file descriptor + tgt = custom("dup2", src, tgt) ## duplicate a file descriptor + e = custom("close", fd) ## remove a file descriptor + e = custom("execvp", arg0, args) ## execute a file + count = custom("write", fd, str) ## write output + str = custom("read", fd) ## read input + count = custom("select", rd, wt, exc[, timeout]) ## examine file descriptors + count = custom("poll", chk, &ret[, msecs]) ## synchronous I/O multiplexing + pid = custom("wait", [pid, ]&stt[, opts][, &usg]) ## wait for process + + pid = custom("pfe", &in, &out, &err, args) ## pipe/fork/exec + count = custom("pwrite", fd, str) ## write and close + e = custom("pread", pid, out, err) ## read until eof, close and wait for exit status + + str = custom("inputname") ## get name of input + path = custom("getcwd") ## get working directory pathname + + path = custom("basename", path) ## extract the base portion of a pathname + path = custom("dirname", path) ## extract the directory part of a pathname + + pid = custom("getpid") ## get calling process identification + pid = custom("getppid") ## get parent process identification TYPES - fd int num - pipe list of fd - pid int num - src tgt fd - arg0 str - args list of str - e int num - count int num - rd wt exc list of fd - in out err list of fd - timeout num - - arg1 str - ...argN str - chk list of list(fd[, arg1[, ...argN]]) - ret list of list(fd[, arg1[, ...argN]]) - msec int num - - stt assoc str => int num - opts list of str - usg assoc str => int num - - path str + fd int num + pipe list of fd + pid int num + src tgt fd + arg0 str + args list of str + e int num + count int num + rd wt exc list of fd + in out err list of fd + timeout num + + arg1 str + ...argN str + chk list of list(fd[, arg1[, ...argN]]) + ret list of list(fd[, arg1[, ...argN]]) + msec int num + + stt assoc str => int num + opts list of str + usg assoc str => int num + + path str EXAMPLE - global i, o, e - if(pid = pfe(&i, &o, &e,list("sh","-c","read||:;echo $REPLY"))){ - pwrite(i,"test") - pread(pid,o,e)} + global i, o, e + if(pid = pfe(&i, &o, &e,list("sh","-c","read||:;echo $REPLY"))){ + pwrite(i,"test") + pread(pid,o,e)} LIMITS - calc must be built with ALLOW_CUSTOM= -DCUSTOM - calc must be executed with a -C arg. + calc must be built with ALLOW_CUSTOM= -DCUSTOM + calc must be executed with a -C arg. LIBRARY - none + none SEE ALSO - custom + custom ## Copyright (C) 2024 Viktor Bergquist ## @@ -76,7 +76,7 @@ SEE ALSO ## ## Calc is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General ## Public License for more details. ## ## A copy of version 2.1 of the GNU Lesser General Public License is diff --git a/custom/pfe.cal b/custom/pfe.cal index 45a31d485..17f4c8427 100644 --- a/custom/pfe.cal +++ b/custom/pfe.cal @@ -9,7 +9,7 @@ * * Calc is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General * Public License for more details. * * A copy of version 2.1 of the GNU Lesser General Public License is @@ -22,7 +22,7 @@ * This file is part of the custom sample calc files. * * NOTE: You must use a calc that was compiled with ALLOW_CUSTOM= -DCUSTOM - * and run with a -C arg. + * and run with a -C arg. */ if (config("compile_custom") == 0) { quit "calc compiled without -DCUSTOM"; @@ -130,6 +130,7 @@ define pwrite_cal(in, str) if (close(in)) quit "pwrite: error closing"; return w; } + define pread_cal(pid, out, err) { local NULL = null(); diff --git a/custom/u_pfe.c b/custom/u_pfe.c index 54dadd706..4fcdc28f2 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -9,7 +9,7 @@ * * Calc is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General * Public License for more details. * * A copy of version 2.1 of the GNU Lesser General Public License is @@ -18,14 +18,33 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -//cspell:ignore qtoi itoq -//cspell:ignore ARGSUSED + +/* cspell:ignore qtoi itoq */ +/* cspell:ignore ARGSUSED */ +/* cspell:ignore custname */ +/* cspell:ignore makenewstring */ +/* cspell:ignore makestring */ +/* makenewstring("0"); */ +/* cspell:ignore associndex */ +/* cspell:ignore assocalloc */ +/* cspell:ignore strp */ +/* cspell:ignore listalloc copyvalue insertlistlast */ +/* cspell:ignore qisneg qisint ztoi qscale qfree */ +/* cspell:ignore pollfds */ +/* cspell:ignore nval */ +/* cspell:ignore rdband */ +/* cspell:ignore wrband */ +/* cspell:ignore wrband */ +/* cspell:ignore wrnorm */ +/* cspell:ignore inputname */ +/* cspell:ignore inputisterminal */ + /* * ISO C requires a translation unit to contain at least one declaration, * so we declare a global variable whose value is based on if CUSTOM is defined. */ -#include + #if defined(CUSTOM) int u_pfe_allowed = 1; /* CUSTOM defined */ #else /* CUSTOM */ @@ -35,79 +54,268 @@ int u_pfe_allowed = 0; /* CUSTOM undefined */ #if defined(CUSTOM) - #include - #include - #include // MAXPATHLEN attow - #include - #include - #include - #include - #include - #include - #include - #include +#include +#include +#include +#include /* MAXPATHLEN attow */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../have_const.h" +#include "../value.h" +#include "../custom.h" + +#include "../config.h" +#include "../calc.h" + +#include "../have_unused.h" + +#include "../banned.h" /* include after system header <> includes */ + + +#define u_pfe_read_STRL_DFLT 1024 +#define pfe_pfe_SIZE_BUFFER 4096 +#define pfe_pfe_SIZE_INIT 4096 + + +typedef enum { + VALV_OPT_OOB, + VALV_OPT_NULL, + VALV_OPT_GOOD, + VALV_OPT_BAD, + VALV_OPT_REF_NULL, +} valv_opt; + + +/* + * static declations + */ +static VALUE *pfe_select_TIMEOUT_DFLT = NULL; +static VALUE *u_pfe_poll_TIMEOUT_DFLT = NULL; + + +/* + * forward declarations + */ +static size_t strlcat(char *dst, const char *src, size_t dsize); +static size_t strlcpy(char *dst, const char *src, size_t dsize); +static const char * type2str(short type); +static VALUE * associndex_int(ASSOC *assoc, long index); +static VALUE * associndex_str(ASSOC *assoc, STRING *index); +static void associndex_int_int(ASSOC *assoc, long index, long value); +static void associndex_str_int(ASSOC *assoc, STRING *index, long value); +static valv_opt valv_optional_type_check(int count, VALUE **vals, int idx, + const char *UNUSED(name), short wanted); +static valv_opt valv_optional_ref_type_check(int count, VALUE **vals, int idx, + const char *UNUSED(name), short wanted); +static bool valv_type_check(int UNUSED(count), VALUE **vals, int idx, + const char *UNUSED(name), short wanted); +static void valv_type_require(const char *custname, int count, VALUE **vals, int idx, + const char *name, short wanted); +static bool valv_ref_type_check(int UNUSED(count), VALUE **vals, int idx, + const char *UNUSED(name), short wanted); +static void valv_ref_type_require(const char *custname, int count, VALUE **vals, int idx, + const char *name, short wanted); +static long valv_get_num_long(const char *custname, int count, VALUE **vals, int idx, + const char *name); +static VALUE * valv_optional_get_num(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt); +#if 0 /* function defined but not used */ +static VALUE * valv_optional_ref_num(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt); +#endif /* function defined but not used */ +static VALUE * valv_ref_num(const char *custname, int count, VALUE **vals, int idx, + const char *name); +#if 0 /* function defined but not used */ +static VALUE * valv_get_num(const char *custname, int count, VALUE **vals, int idx, + const char *name); +#endif /* function defined but not used */ +static char * valv_get_str(const char *custname, int count, VALUE **vals, int idx, + const char *name); +static VALUE * valv_get_strp(const char *custname, int count, VALUE **vals, int idx, + const char *name); +#if 0 /* function defined but not used */ +static VALUE * valv_optional_ref_list(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt); +#endif /* function defined but not used */ +static VALUE * valv_optional_get_list(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt); +static VALUE * valv_get_list(const char *custname, int count, VALUE **vals, int idx, + const char *name); +static VALUE * valv_ref_list(const char *custname, int count, VALUE **vals, int idx, + const char *name); +#if 0 /* function defined but not used */ +static VALUE * valv_optional_get_assoc(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt); +#endif /* function defined but not used */ +static VALUE * valv_optional_ref_assoc(int count, VALUE **vals, int *idx, const char *name, + VALUE *dflt); +#if 0 /* function defined but not used */ +static VALUE * valv_get_assoc(const char *custname, int count, VALUE **vals, int idx, + const char *name); +#endif /* function defined but not used */ +static VALUE * valv_ref_assoc(const char *custname, int count, VALUE **vals, int idx, + const char *name); +static VALUE * optional_valv_ref_list2fd_set(const char *custname, int count, VALUE **vals, + int *idx, const char *name, fd_set *fds, int *setsize); +static VALUE * alloc_list(LIST *list); +static VALUE * alloc_assoc(ASSOC *assoc); +static VALUE * list_fd_get(LIST *in, fd_set *fds); +static VALUE * alloc_num(NUMBER *num); +static VALUE * alloc_str(STRING *str); +static char * strext(char **subject, char *with); + + +/* + * strlcat - size-bounded string concatenation + * + * Sadly, strlcat(3) is not portable enough for a number of supported calc v2 enviroments. + * So we will include as a static function below, strlcat.c from: + * + * https://github.com/libressl/openbsd/blob/master/src/lib/libc/string/strlcat.c + * + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +static size_t +strlcat(char *dst, const char *src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + size_t ret; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') { + dst++; + } + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) { + return(dlen + strlen(src)); + } + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + /* count does not include NUL */ + ret = dlen + (src - osrc); + + return ret; +} + - #include "../have_const.h" - #include "../value.h" - #include "../custom.h" +/* + * strlcpy - size-bounded string copying + * + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + * + * Sadly, strlcpy(3) is not portable enough for a number of supported calc v2 enviroments. + * So we will include as a static function below, strlcpy.c from: + * + * https://github.com/libressl/openbsd/blob/master/src/lib/libc/string/strlcpy.c + */ +static size_t +strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + size_t ret; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') { + break; + } + } + } - #include "../config.h" - #include "../calc.h" + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) { + *dst = '\0'; /* NUL-terminate dst */ + } + while (*src++) { + ; + } + } - #include "../have_unused.h" + /* count does not include NUL */ + ret = src - osrc - 1; + return ret; +} - #include "../banned.h" /* include after system header <> includes */ -const char * +static const char * type2str(short type) { - // originally from c_argv.c + /* originally from c_argv.c */ switch (type) { case V_NULL: - return "null"; // null value + return "null"; /* null value */ case V_INT: - return "int"; // normal integer + return "int"; /* normal integer */ case V_NUM: - return "rational_value"; // number + return "rational_value"; /* number */ case V_COM: - return "complex_value"; // complex number + return "complex_value"; /* complex number */ case V_ADDR: - return "address"; // address of variable value + return "address"; /* address of variable value */ case V_STR: - return "string"; // address of string + return "string"; /* address of string */ case V_MAT: - return "matrix"; // address of matrix structure + return "matrix"; /* address of matrix structure */ case V_LIST: - return "list"; // address of list structure + return "list"; /* address of list structure */ case V_ASSOC: - return "assoc"; // address of association structure + return "assoc"; /* address of association structure */ case V_OBJ: - return "object"; // address of object structure + return "object"; /* address of object structure */ case V_FILE: - return "file"; // opened file id + return "file"; /* opened file id */ case V_RAND: - return "rand_state"; // subtractive 100 random state + return "rand_state"; /* subtractive 100 random state */ case V_RANDOM: - return "random_state"; // address of Blum random state + return "random_state"; /* address of Blum random state */ case V_CONFIG: - return "config_state"; // configuration state + return "config_state"; /* configuration state */ case V_HASH: - return "hash_state"; // hash state + return "hash_state"; /* hash state */ case V_BLOCK: - return "octet_block"; // memory block + return "octet_block"; /* memory block */ case V_OCTET: - return "octet"; // octet (unsigned char) + return "octet"; /* octet (unsigned char) */ default: return "unknown"; } } + /* * u_pfe_fork - create process * * returns: - * pid + * pid */ /*ARGSUSED*/ VALUE @@ -121,229 +329,320 @@ u_pfe_fork(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(pid); + return result; } -//cspell:ignore makenewstring -//cspell:ignore makestring -//makenewstring("0"); - -//cspell:ignore associndex -//cspell:ignore assocalloc -VALUE * +static VALUE * associndex_int(ASSOC *assoc, long index) { VALUE i; VALUE indices[1]; + VALUE *ret; i.v_type = V_NUM; i.v_num = itoq(index); indices[0] = i; - return associndex(assoc, TRUE, 1, indices); + + ret = associndex(assoc, TRUE, 1, indices); + + return ret; } -VALUE * + +static VALUE * associndex_str(ASSOC *assoc, STRING *index) { VALUE i; VALUE indices[1]; + VALUE *ret; i.v_type = V_STR; i.v_str = index; indices[0] = i; - return associndex(assoc, TRUE, 1, indices); + + ret = associndex(assoc, TRUE, 1, indices); + + return ret; } -void + +static void associndex_int_int(ASSOC *assoc, long index, long value) { - VALUE *i = associndex_int(assoc, index); + VALUE *i; + + i = associndex_int(assoc, index); i->v_type = V_NUM; i->v_num = itoq(value); + + return; } -void + +static void associndex_str_int(ASSOC *assoc, STRING *index, long value) { - VALUE *i = associndex_str(assoc, index); + VALUE *i; + + i = associndex_str(assoc, index); i->v_type = V_NUM; i->v_num = itoq(value); + + return; } + /* * u_pfe_pipe - create descriptor pair for interprocess communication * * returns: - * assoc { [0] = reading, [1] = writing } + * assoc { [0] = reading, [1] = writing } */ /*ARGSUSED*/ VALUE u_pfe_pipe(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) { + VALUE result; const char *custname = "pipe"; - + ASSOC *assoc; int fds[2]; - if (pipe(fds)) + + if (pipe(fds)) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); + } - ASSOC *assoc = assocalloc(2); + assoc = assocalloc(2); associndex_int_int(assoc, 0, fds[0]); associndex_int_int(assoc, 1, fds[1]); - VALUE result; result.v_subtype = 0; result.v_type = V_ASSOC; result.v_assoc = assoc; + return result; } -//cspell:ignore custname -typedef enum { - VALV_OPT_OOB, - VALV_OPT_NULL, - VALV_OPT_GOOD, - VALV_OPT_BAD, - VALV_OPT_REF_NULL, -} valv_opt; -valv_opt +static valv_opt valv_optional_type_check(int count, VALUE **vals, int idx, const char *UNUSED(name), short wanted) { - if (idx > count) return VALV_OPT_OOB; - if (vals[idx]->v_type == V_NULL) return VALV_OPT_NULL; - if (vals[idx]->v_type == wanted) return VALV_OPT_GOOD; + if (idx > count) { + return VALV_OPT_OOB; + } + if (vals[idx]->v_type == V_NULL) { + return VALV_OPT_NULL; + } + if (vals[idx]->v_type == wanted) { + return VALV_OPT_GOOD; + } + return VALV_OPT_BAD; } -valv_opt + + +static valv_opt valv_optional_ref_type_check(int count, VALUE **vals, int idx, const char *UNUSED(name), short wanted) { - if (idx > count) return VALV_OPT_OOB; - if (vals[idx]->v_type == V_NULL) return VALV_OPT_NULL; - if (vals[idx]->v_type != V_VPTR) return VALV_OPT_BAD; - if (vals[idx]->v_addr->v_type == V_NULL) return VALV_OPT_REF_NULL; - if (vals[idx]->v_addr->v_type == wanted) return VALV_OPT_GOOD; + if (idx > count) { + return VALV_OPT_OOB; + } + if (vals[idx]->v_type == V_NULL) { + return VALV_OPT_NULL; + } + if (vals[idx]->v_type != V_VPTR) { + return VALV_OPT_BAD; + } + if (vals[idx]->v_addr->v_type == V_NULL) { + return VALV_OPT_REF_NULL; + } + if (vals[idx]->v_addr->v_type == wanted) { + return VALV_OPT_GOOD; + } + return VALV_OPT_BAD; } -bool + + +static bool valv_type_check(int UNUSED(count), VALUE **vals, int idx, const char *UNUSED(name), short wanted) { - return vals[idx]->v_type == wanted; + bool ret; + + ret = (vals[idx]->v_type == wanted); + + return ret; } -void + + +static void valv_type_require(const char *custname, int count, VALUE **vals, int idx, const char *name, short wanted) { - if (!valv_type_check(count, vals, idx, name, wanted)) + if (!valv_type_check(count, vals, idx, name, wanted)) { math_error("%s: argment %d (%s) must be of type %s (%s given)", custname, idx + 1, name, type2str(wanted), type2str(vals[idx]->v_type)); + } + + return; } -bool + + +static bool valv_ref_type_check(int UNUSED(count), VALUE **vals, int idx, const char *UNUSED(name), short wanted) { - return vals[idx]->v_addr->v_type == wanted; + bool ret; + + ret = (vals[idx]->v_addr->v_type == wanted); + + return ret; } -void + + +static void valv_ref_type_require(const char *custname, int count, VALUE **vals, int idx, const char *name, short wanted) { - if (!valv_type_check(count, vals, idx, name, V_VPTR)) + if (!valv_type_check(count, vals, idx, name, V_VPTR)) { math_error("%s: argment %d (%s) must be address (%s given) of type %s", custname, idx + 1, name, type2str(vals[idx]->v_type), type2str(wanted)); - if (!valv_ref_type_check(count, vals, idx, name, wanted)) + } + if (!valv_ref_type_check(count, vals, idx, name, wanted)) { math_error("%s: argment %d (%s) must be address of type %s (%s given)", custname, idx + 1, name, type2str(wanted), type2str(vals[idx]->v_addr->v_type)); + } + + return; } -long + +static long valv_get_num_long(const char *custname, int count, VALUE **vals, int idx, const char *name) { valv_type_require(custname, count, vals, idx, name, V_NUM); + return qtoi(vals[idx]->v_num); } -VALUE * + + +static VALUE * valv_optional_get_num(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { - valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_NUM); + valv_opt chk; + VALUE *num; + + chk = valv_optional_type_check(count, vals, *idx, name, V_NUM); switch (chk) { case VALV_OPT_BAD: return dflt; case VALV_OPT_NULL: - *idx += 1; // fall-thru + *idx += 1; + /*FALLTHRU*/ case VALV_OPT_OOB: return dflt; case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD:; // fall-thru + case VALV_OPT_GOOD: + ; + /*FALLTHRU*/ } - VALUE *num = vals[*idx]; + num = vals[*idx]; *idx += 1; + return num; } -VALUE * + + +#if 0 /* function defined but not used */ +static VALUE * valv_optional_ref_num(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { - valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_NUM); + valv_opt chk; + VALUE *num; + + chk = valv_optional_ref_type_check(count, vals, *idx, name, V_NUM); switch (chk) { case VALV_OPT_BAD: return dflt; case VALV_OPT_NULL: - *idx += 1; // fall-thru + *idx += 1; + /*FALLTHRU*/ case VALV_OPT_OOB: return dflt; case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD:; // fall-thru + case VALV_OPT_GOOD: + ; + /*FALLTHRU*/ } - VALUE *num = vals[*idx]->v_addr; + num = vals[*idx]->v_addr; if (chk == VALV_OPT_REF_NULL) { num->v_type = V_NUM; num->v_num = dflt->v_num; } *idx += 1; + return num; } -VALUE * +#endif /* function defined but not used */ + + +static VALUE * valv_ref_num(const char *custname, int count, VALUE **vals, int idx, const char *name) { valv_ref_type_require(custname, count, vals, idx, name, V_NUM); + return vals[idx]->v_addr; } -VALUE * + + +#if 0 /* function defined but not used */ +static VALUE * valv_get_num(const char *custname, int count, VALUE **vals, int idx, const char *name) { valv_type_require(custname, count, vals, idx, name, V_NUM); + return vals[idx]; } -char * +#endif /* function defined but not used */ + + +static char * valv_get_str(const char *custname, int count, VALUE **vals, int idx, const char *name) { valv_type_require(custname, count, vals, idx, name, V_STR); + return vals[idx]->v_str->s_str; } -//cspell:ignore strp -VALUE * + + +static VALUE * valv_get_strp(const char *custname, int count, VALUE **vals, int idx, const char *name) { valv_type_require(custname, count, vals, idx, name, V_STR); + return vals[idx]; } -VALUE * + + +#if 0 /* function defined but not used */ +static VALUE * valv_optional_ref_list(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { @@ -352,11 +651,14 @@ valv_optional_ref_list(int count, VALUE **vals, int *idx, const char *name, case VALV_OPT_BAD: return dflt; case VALV_OPT_NULL: - *idx += 1; // fall-thru + *idx += 1; + /*FALLTHRU*/ case VALV_OPT_OOB: return dflt; case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD:; // fall-thru + case VALV_OPT_GOOD: + ; + /*FALLTHRU*/ } VALUE *list = vals[*idx]->v_addr; if (chk == VALV_OPT_REF_NULL) { @@ -364,136 +666,186 @@ valv_optional_ref_list(int count, VALUE **vals, int *idx, const char *name, list->v_list = dflt->v_list; } *idx += 1; + return list; } -VALUE * +#endif /* function defined but not used */ + + +static VALUE * valv_optional_get_list(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { - valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_LIST); + valv_opt chk; + VALUE *list; + + chk = valv_optional_type_check(count, vals, *idx, name, V_LIST); switch (chk) { case VALV_OPT_BAD: return dflt; case VALV_OPT_NULL: - *idx += 1; // fall-thru + *idx += 1; + /*FALLTHRU*/ case VALV_OPT_OOB: return dflt; case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD:; // fall-thru + case VALV_OPT_GOOD: + ; + /*FALLTHRU*/ } - VALUE *list = vals[*idx]; + list = vals[*idx]; *idx += 1; + return list; } -VALUE * + + +static VALUE * valv_get_list(const char *custname, int count, VALUE **vals, int idx, const char *name) { valv_type_require(custname, count, vals, idx, name, V_LIST); + return vals[idx]; } -VALUE * + + +static VALUE * valv_ref_list(const char *custname, int count, VALUE **vals, int idx, const char *name) { valv_ref_type_require(custname, count, vals, idx, name, V_LIST); + return vals[idx]->v_addr; } -VALUE * + + +#if 0 /* function defined but not used */ +static VALUE * valv_optional_get_assoc(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { - valv_opt chk = valv_optional_type_check(count, vals, *idx, name, V_ASSOC); + valv_opt chk; + VALUE *assoc; + + chk = valv_optional_type_check(count, vals, *idx, name, V_ASSOC); switch (chk) { case VALV_OPT_BAD: return dflt; case VALV_OPT_NULL: - *idx += 1; // fall-thru + *idx += 1; + /*FALLTHRU*/ case VALV_OPT_OOB: return dflt; case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD:; // fall-thru + case VALV_OPT_GOOD: + ; + /*FALLTHRU*/ } - VALUE *assoc = vals[*idx]; + assoc = vals[*idx]; *idx += 1; + return assoc; } -VALUE * +#endif /* function defined but not used */ + + +static VALUE * valv_optional_ref_assoc(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { - valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_ASSOC); + valv_opt chk; + VALUE *assoc; + + chk = valv_optional_ref_type_check(count, vals, *idx, name, V_ASSOC); switch (chk) { case VALV_OPT_BAD: return dflt; case VALV_OPT_NULL: - *idx += 1; // fall-thru + *idx += 1; + /*FALLTHRU*/ case VALV_OPT_OOB: return dflt; case VALV_OPT_REF_NULL: - case VALV_OPT_GOOD:; // fall-thru + case VALV_OPT_GOOD: + ; + /*FALLTHRU*/ } - VALUE *assoc = vals[*idx]->v_addr; + assoc = vals[*idx]->v_addr; *idx += 1; return assoc; } -VALUE * + + +#if 0 /* function defined but not used */ +static VALUE * valv_get_assoc(const char *custname, int count, VALUE **vals, int idx, const char *name) { valv_type_require(custname, count, vals, idx, name, V_ASSOC); return vals[idx]; } -VALUE * +#endif /* function defined but not used */ + + +static VALUE * valv_ref_assoc(const char *custname, int count, VALUE **vals, int idx, const char *name) { valv_ref_type_require(custname, count, vals, idx, name, V_ASSOC); + return vals[idx]->v_addr; } + /* * u_pfe_execvp - execute a file, possibly looking in paths from environment or system * * given: - * vals[0] file - * vals[1] list(arg0,...) + * vals[0] file + * vals[1] list(arg0,...) * * returns: - * 0 on success + * 0 on success */ /*ARGSUSED*/ VALUE u_pfe_execvp(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "execvp"; + char *path; + VALUE *args_list; + char **args; + LISTELEM *el; + int s = 0; - char *path = valv_get_str(custname, count, vals, 0, "file"); - VALUE *args_list = valv_get_list(custname, count, vals, 1, "args"); + path = valv_get_str(custname, count, vals, 0, "file"); + args_list = valv_get_list(custname, count, vals, 1, "args"); - char **args; - if (!(args = malloc(sizeof(char *) * (args_list->v_list->l_count + 1)))) + if (!(args = malloc(sizeof(char *) * (args_list->v_list->l_count + 1)))) { math_error("%s: "__FILE__ ": %d: malloc: %s", custname, __LINE__, strerror(errno)); + } - LISTELEM *el = args_list->v_list->l_first; - int s = 0; + el = args_list->v_list->l_first; for (; el != NULL; el = el->e_next, s++) { - if (el->e_value.v_type != V_STR) + if (el->e_value.v_type != V_STR) { math_error("%s: argment 2 (args) element %d must be of type string (%s given)", custname, s, type2str(el->e_value.v_type)); + } args[s] = el->e_value.v_str->s_str; } args[s] = NULL; - if (execvp(path, args)) + if (execvp(path, args)) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); + } free(args); - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; @@ -501,153 +853,170 @@ u_pfe_execvp(char *UNUSED(name), int count, VALUE **vals) return result; } + /* * u_pfe_dup - duplicate a file descriptor * * given: - * vals[0] source fd + * vals[0] source fd * * returns: - * target fd + * target fd */ /*ARGSUSED*/ VALUE u_pfe_dup(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "dup"; + int fd; - int fd = dup(valv_get_num_long(custname, count, vals, 0, "source")); + fd = dup(valv_get_num_long(custname, count, vals, 0, "source")); - if (fd < 0) + if (fd < 0) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); + } - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(fd); + return result; } + /* * u_pfe_dup2 - duplicate a file descriptor * * given: - * vals[0] source fd - * vals[1] target fd + * vals[0] source fd + * vals[1] target fd * * returns: - * target fd + * target fd */ /*ARGSUSED*/ VALUE u_pfe_dup2(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "dup2"; + int fd; - int fd = dup2(valv_get_num_long(custname, count, vals, 0, "source"), + fd = dup2(valv_get_num_long(custname, count, vals, 0, "source"), valv_get_num_long(custname, count, vals, 1, "target")); - if (fd < 0) + if (fd < 0) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); + } - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(fd); + return result; } + /* * u_pfe_close - delete a file descriptor * * given: - * vals[0] fd + * vals[0] fd * * returns: - * 0 on success + * 0 on success */ /*ARGSUSED*/ VALUE u_pfe_close(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "close"; + int e; - int e = close(valv_get_num_long(custname, count, vals, 0, "fd")); + e = close(valv_get_num_long(custname, count, vals, 0, "fd")); - if (e) + if (e) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); + } - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(e); + return result; } + /* * u_pfe_write - write output * * given: - * vals[0] fd - * vals[1] string + * vals[0] fd + * vals[1] string * * returns: - * count of bytes written + * count of bytes written */ /*ARGSUSED*/ VALUE u_pfe_write(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "write"; + VALUE *strp; + ssize_t written; - VALUE *strp = valv_get_strp(custname, count, vals, 1, "string"); + strp = valv_get_strp(custname, count, vals, 1, "string"); - ssize_t written = write(valv_get_num_long(custname, count, vals, 0, "fd"), - strp->v_str->s_str, strp->v_str->s_len); + written = write(valv_get_num_long(custname, count, vals, 0, "fd"), strp->v_str->s_str, strp->v_str->s_len); - if (written < 0) + if (written < 0) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); + } - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(written); + return result; } - #define u_pfe_read_STRL_DFLT 1024 /* * u_pfe_read - write output * * given: - * vals[0] fd - * vals[1] count defaulting to 1024 + * vals[0] fd + * vals[1] count defaulting to 1024 * * returns: - * count of bytes read + * count of bytes read */ /*ARGSUSED*/ VALUE u_pfe_read(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "read"; + int strl; + char *str; + ssize_t r; - int strl = count < 2 ? u_pfe_read_STRL_DFLT - : valv_get_num_long(custname, count, vals, 1, "count"); + strl = count < 2 ? u_pfe_read_STRL_DFLT : valv_get_num_long(custname, count, vals, 1, "count"); - char *str = malloc((strl + 1) * sizeof(char)); + str = malloc((strl + 1) * sizeof(char)); - ssize_t r = read(valv_get_num_long(custname, count, vals, 0, "fd"), str, - strl); + r = read(valv_get_num_long(custname, count, vals, 0, "fd"), str, strl); str[r] = '\0'; if (r < 0) { @@ -656,161 +1025,203 @@ u_pfe_read(char *UNUSED(name), int count, VALUE **vals) strerror(errno)); } - VALUE result; result.v_subtype = 0; result.v_type = !r ? V_NULL : V_STR; - if (r) result.v_str = makestring(str); + if (r) { + result.v_str = makestring(str); + } + return result; } -VALUE * +static VALUE * optional_valv_ref_list2fd_set(const char *custname, int count, VALUE **vals, int *idx, const char *name, fd_set *fds, int *setsize) { - valv_opt chk = valv_optional_ref_type_check(count, vals, *idx, name, V_LIST); + valv_opt chk; + VALUE *list; + LISTELEM *el; + int s = 0; + int i; + + chk = valv_optional_ref_type_check(count, vals, *idx, name, V_LIST); switch (chk) { case VALV_OPT_BAD: return NULL; case VALV_OPT_NULL: - *idx += 1; // fall-thru + *idx += 1; + /*FALLTHRU*/ case VALV_OPT_OOB: return NULL; case VALV_OPT_REF_NULL: math_error("%s: argument %d (%s) address of type null is not allowed", custname, *idx, name); - case VALV_OPT_GOOD:; // fall-thru + case VALV_OPT_GOOD: + ; + /*FALLTHRU*/ } - VALUE *list = vals[*idx]->v_addr; - *idx += 1; - LISTELEM *el = list->v_list->l_first; - int s = 0; + list = vals[*idx]->v_addr; + *idx += 1; + el = list->v_list->l_first; for (; el != NULL; el = el->e_next, s++) { - if (el->e_value.v_type != V_NUM) + if (el->e_value.v_type != V_NUM) { math_error("%s: argument %d (%s) element %d must be of type number (%s given)", custname, *idx, name, s, type2str(el->e_value.v_type)); + } - int i = qtoi(el->e_value.v_num); - if (*setsize < i + 1) *setsize = i + 1; + i = qtoi(el->e_value.v_num); + if (*setsize < i + 1) { + *setsize = i + 1; + } FD_SET(i, fds); } + return list; } -VALUE * + +static VALUE * alloc_list(LIST *list) { - VALUE *result = malloc(sizeof(VALUE)); + VALUE *result; + + result = malloc(sizeof(VALUE)); result->v_type = V_LIST; result->v_list = list; + return result; } -VALUE * + +static VALUE * alloc_assoc(ASSOC *assoc) { - VALUE *result = malloc(sizeof(VALUE)); + VALUE *result; + + result = malloc(sizeof(VALUE)); result->v_type = V_ASSOC; result->v_assoc = assoc; + return result; } -//cspell:ignore listalloc copyvalue insertlistlast -VALUE * +static VALUE * list_fd_get(LIST *in, fd_set *fds) { - VALUE *out = alloc_list(listalloc()); - LISTELEM *el = in->l_first; + VALUE *out; + LISTELEM *el; int s = 0; + int i; + VALUE o; + + out = alloc_list(listalloc()); + el = in->l_first; + for (; el != NULL; el = el->e_next, s++) { - int i = qtoi(el->e_value.v_num); + i = qtoi(el->e_value.v_num); if (FD_ISSET(i, fds)) { - VALUE o; copyvalue(&el->e_value, &o); insertlistlast(out->v_list, &o); } } + return out; } -VALUE * + +static VALUE * alloc_num(NUMBER *num) { - VALUE *result = malloc(sizeof(VALUE)); + VALUE *result; + + result = malloc(sizeof(VALUE)); result->v_type = V_NUM; result->v_num = num; + return result; } -VALUE * + +static VALUE * alloc_str(STRING *str) { - VALUE *result = malloc(sizeof(VALUE)); + VALUE *result; + + result = malloc(sizeof(VALUE)); result->v_type = V_STR; result->v_str = str; + return result; } -VALUE *pfe_select_TIMEOUT_DFLT = NULL; - -//cspell:ignore qisneg qisint ztoi qscale qfree /* * u_pfe_select - examine file descriptors * * given: - * vals[l1+0] null or address of list (inout\ref) of fds for reading, wh/ l1 is zero-index of 1st list - * vals[l1+1] null or address of list (inout\ref) of fds for writing, wh/ l1 is zero-index of 1st list - * vals[l1+2] null or address of list (inout\ref) of fds for exceptional, wh/ l1 is zero-index of 1st list - * vals[lZ+1] null or timeout defaulting to -1, wh/ lZ is zero-index of last list + * vals[l1+0] null or address of list (inout\ref) of fds for reading, + * wh/ l1 is zero-index of 1st list + * vals[l1+1] null or address of list (inout\ref) of fds for writing, + * wh/ l1 is zero-index of 1st list + * vals[l1+2] null or address of list (inout\ref) of fds for exceptional, + * wh/ l1 is zero-index of 1st list + * vals[lZ+1] null or timeout defaulting to -1, + * wh/ lZ is zero-index of last list * * returns: - * count of fds w/ status + * count of fds w/ status */ /*ARGSUSED*/ VALUE u_pfe_select(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "select"; int v = 0; - - int ssz = 0; + VALUE *rdl; + VALUE *wtl; fd_set rds; - FD_ZERO(&rds); - VALUE *rdl = optional_valv_ref_list2fd_set(custname, count, vals, &v, - "reading", &rds, &ssz); fd_set wts; - FD_ZERO(&wts); - VALUE *wtl = optional_valv_ref_list2fd_set(custname, count, vals, &v, - "writing", &wts, &ssz); fd_set ers; + VALUE *erl; + VALUE *tv; + NUMBER *tn; + struct timeval t; + struct timeval *tp; + int ssz = 0; + + FD_ZERO(&rds); + rdl = optional_valv_ref_list2fd_set(custname, count, vals, &v, "reading", &rds, &ssz); + FD_ZERO(&wts); + wtl = optional_valv_ref_list2fd_set(custname, count, vals, &v, "writing", &wts, &ssz); FD_ZERO(&ers); - VALUE *erl = optional_valv_ref_list2fd_set(custname, count, vals, &v, - "exceptional", &ers, &ssz); + erl = optional_valv_ref_list2fd_set(custname, count, vals, &v, "exceptional", &ers, &ssz); - if (!pfe_select_TIMEOUT_DFLT) pfe_select_TIMEOUT_DFLT = alloc_num(itoq(-1)); + if (!pfe_select_TIMEOUT_DFLT) { + pfe_select_TIMEOUT_DFLT = alloc_num(itoq(-1)); + } - VALUE *tv = valv_optional_get_num(count, vals, &v, "timeout", - pfe_select_TIMEOUT_DFLT); + tv = valv_optional_get_num(count, vals, &v, "timeout", pfe_select_TIMEOUT_DFLT); - NUMBER *tn = tv->v_num; - struct timeval t; - struct timeval *tp; - // originally from f_sleep() in ../func.c + tn = tv->v_num; + /* originally from f_sleep() in ../func.c */ if (qisneg(tn)) { tp = NULL; } else if (qisint(tn)) { - if (zge31b(tn->num)) math_error("sizeof(timeout) > 31 bytes"); + if (zge31b(tn->num)) { + math_error("sizeof(timeout) > 31 bytes"); + } t.tv_sec = ztoi(tn->num); t.tv_usec = 0; tp = &t; } else { NUMBER *q1, *q2; - q1 = qscale(tn, 20); // 2^20 = 1 Mi + q1 = qscale(tn, 20); /* 2^20 = 1 Mi */ q2 = qint(q1); qfree(q1); if (zge31b(q2->num)) { @@ -826,38 +1237,42 @@ u_pfe_select(char *UNUSED(name), int count, VALUE **vals) int r = select(ssz, &rds, &wts, &ers, tp); - if (r < 0) + if (r < 0) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); + } - if (rdl) *rdl = *list_fd_get(rdl->v_list, &rds); - if (wtl) *wtl = *list_fd_get(wtl->v_list, &wts); - if (erl) *erl = *list_fd_get(erl->v_list, &ers); + if (rdl) { + *rdl = *list_fd_get(rdl->v_list, &rds); + } + if (wtl) { + *wtl = *list_fd_get(wtl->v_list, &wts); + } + if (erl) { + *erl = *list_fd_get(erl->v_list, &ers); + } - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(r); + return result; } -VALUE *u_pfe_poll_TIMEOUT_DFLT = NULL; /* * u_pfe_poll - synchronous I/O multiplexing * * tested manually only slightly (as it turned out it wasn't suitable for why it was written) * - * TODO unit/feature test - * * given: - * vals[0] list of list(fd[, event1[, ...eventN]]) - * vals[1] address of list, appended with list(fd[, event1[, ...eventN]]) - * vals[2] null or integer millisecond timeout defaulting to -1 + * vals[0] list of list(fd[, event1[, ...eventN]]) + * vals[1] address of list, appended with list(fd[, event1[, ...eventN]]) + * vals[2] null or integer millisecond timeout defaulting to -1 * * returns: - * count of fds w/ status + * count of fds w/ status */ /*ARGSUSED*/ VALUE @@ -865,25 +1280,42 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) { const char *custname = "poll"; const char *i_name = "list of list(fd[, event1[, ...eventN]])"; - - VALUE *iv = valv_get_list(custname, count, vals, 0, i_name); - VALUE *ov = valv_ref_list(custname, count, vals, 1, "list"); - - if (!u_pfe_poll_TIMEOUT_DFLT) u_pfe_poll_TIMEOUT_DFLT = alloc_num(itoq(-1)); - int v = 2; - VALUE *tv = valv_optional_get_num(count, vals, &v, "timeout", - u_pfe_poll_TIMEOUT_DFLT); - NUMBER *tn = tv->v_num; - if (!qisint(tn)) + VALUE result; + int v = 2; + VALUE *tv; + NUMBER *tn; + int t; + LIST *il; + struct pollfd *pollfds; + LISTELEM *el; + int s = 0; + LIST *el_list; + LISTELEM *el_el; + int el_el_s; + char *el_el_str; + int r; + LIST *ol; + VALUE *o; + VALUE *iv; + VALUE *ov; + + iv = valv_get_list(custname, count, vals, 0, i_name); + ov = valv_ref_list(custname, count, vals, 1, "list"); + + if (!u_pfe_poll_TIMEOUT_DFLT) { + u_pfe_poll_TIMEOUT_DFLT = alloc_num(itoq(-1)); + } + tv = valv_optional_get_num(count, vals, &v, "timeout", u_pfe_poll_TIMEOUT_DFLT); + tn = tv->v_num; + if (!qisint(tn)) { math_error("%s: argument 2 (timeout) must be integer", custname); - int t = qtoi(tn); + } + t = qtoi(tn); - LIST *il = iv->v_list; - struct pollfd *pollfds = malloc(il->l_count - * sizeof(struct pollfd)); //cspell:ignore pollfds + il = iv->v_list; + pollfds = malloc(il->l_count * sizeof(struct pollfd)); - LISTELEM *el = il->l_first; - int s = 0; + el = il->l_first; for (; el != NULL; el = el->e_next, s++) { if (el->e_value.v_type != V_LIST) { free(pollfds); @@ -891,8 +1323,7 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) custname, 1, i_name, s, type2str(el->e_value.v_type)); } - LIST *el_list = el->e_value.v_list; - LISTELEM *el_el; + el_list = el->e_value.v_list; el_el = el_list->l_first; @@ -912,7 +1343,7 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) el_el = el_el->e_next; - int el_el_s = 1; + el_el_s = 1; for (; el_el != NULL; el_el = el_el->e_next, el_el_s++) { if (el_el->e_value.v_type != V_STR) { free(pollfds); @@ -921,27 +1352,33 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) type2str(el_el->e_value.v_type)); } - char *el_el_str = el_el->e_value.v_str->s_str; - if (FALSE) - ; // man poll|gawk 'match($0,"^\\s*POLL([A-Z]+)",m){print(tolower(m[1]))}' - else if (!strcmp(el_el_str, "err")) pollfds[s].events |= POLLERR; - else if (!strcmp(el_el_str, "hup")) pollfds[s].events |= POLLHUP; - else if (!strcmp(el_el_str, "in")) pollfds[s].events |= POLLIN; - else if (!strcmp(el_el_str, "nval")) - pollfds[s].events |= POLLNVAL; //cspell:ignore nval - else if (!strcmp(el_el_str, "out")) pollfds[s].events |= POLLOUT; - else if (!strcmp(el_el_str, "pri")) pollfds[s].events |= POLLPRI; - else if (!strcmp(el_el_str, "rdband")) - pollfds[s].events |= POLLRDBAND; //cspell:ignore rdband - else if (!strcmp(el_el_str, "rdnorm")) - pollfds[s].events |= POLLRDNORM; //cspell:ignore rdnorm - else if (!strcmp(el_el_str, "wrband")) - pollfds[s].events |= POLLWRBAND; //cspell:ignore wrband - else if (!strcmp(el_el_str, "wrnorm")) - pollfds[s].events |= POLLWRNORM; //cspell:ignore wrnorm - else { + el_el_str = el_el->e_value.v_str->s_str; + if (FALSE) { + ; /* man poll|gawk 'match($0,"^\\s*POLL([A-Z]+)",m){print(tolower(m[1]))}' */ + } else if (!strcmp(el_el_str, "err")) { + pollfds[s].events |= POLLERR; + } else if (!strcmp(el_el_str, "hup")) { + pollfds[s].events |= POLLHUP; + } else if (!strcmp(el_el_str, "in")) { + pollfds[s].events |= POLLIN; + } else if (!strcmp(el_el_str, "nval")) { + pollfds[s].events |= POLLNVAL; + } else if (!strcmp(el_el_str, "out")) { + pollfds[s].events |= POLLOUT; + } else if (!strcmp(el_el_str, "pri")) { + pollfds[s].events |= POLLPRI; + } else if (!strcmp(el_el_str, "rdband")) { + pollfds[s].events |= POLLRDBAND; + } else if (!strcmp(el_el_str, "rdnorm")) { + pollfds[s].events |= POLLRDNORM; + } else if (!strcmp(el_el_str, "wrband")) { + pollfds[s].events |= POLLWRBAND; + } else if (!strcmp(el_el_str, "wrnorm")) { + pollfds[s].events |= POLLWRNORM; + } else { free(pollfds); - math_error("%s: argument %d (%s) element %d element %d must be a string containing one of the event names from POSIX poll.h or the manual for poll, lowercase without poll prefix (%s given)", + math_error("%s: argument %d (%s) element %d element %d must be a string containing one of the " + "event names from POSIX poll.h or the manual for poll, lowercase without poll prefix (%s given)", custname, 1, i_name, s, el_el_s, el_el->e_value.v_str->s_str); } } @@ -949,7 +1386,7 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) pollfds[s].revents = 0; } - int r = poll(pollfds, il->l_count, t); + r = poll(pollfds, il->l_count, t); if (r < 0) { free(pollfds); @@ -957,106 +1394,137 @@ u_pfe_poll(char *UNUSED(name), int count, VALUE **vals) strerror(errno)); } - LIST *ol = listalloc(); + ol = listalloc(); for (s = 0; s < il->l_count; s++) { - VALUE *o = alloc_assoc(assocalloc(0)); + o = alloc_assoc(assocalloc(0)); - if ((pollfds[s].revents & POLLERR) == POLLERR) + if ((pollfds[s].revents & POLLERR) == POLLERR) { associndex_str_int(o->v_assoc, makenewstring("err"), POLLERR); - if ((pollfds[s].revents & POLLHUP) == POLLHUP) + } + if ((pollfds[s].revents & POLLHUP) == POLLHUP) { associndex_str_int(o->v_assoc, makenewstring("hup"), POLLHUP); - if ((pollfds[s].revents & POLLIN) == POLLIN) + } + if ((pollfds[s].revents & POLLIN) == POLLIN) { associndex_str_int(o->v_assoc, makenewstring("in"), POLLIN); - if ((pollfds[s].revents & POLLNVAL) == POLLNVAL) + } + if ((pollfds[s].revents & POLLNVAL) == POLLNVAL) { associndex_str_int(o->v_assoc, makenewstring("nval"), POLLNVAL); - if ((pollfds[s].revents & POLLOUT) == POLLOUT) + } + if ((pollfds[s].revents & POLLOUT) == POLLOUT) { associndex_str_int(o->v_assoc, makenewstring("out"), POLLOUT); - if ((pollfds[s].revents & POLLPRI) == POLLPRI) + } + if ((pollfds[s].revents & POLLPRI) == POLLPRI) { associndex_str_int(o->v_assoc, makenewstring("pri"), POLLPRI); - if ((pollfds[s].revents & POLLRDBAND) == POLLRDBAND) + } + if ((pollfds[s].revents & POLLRDBAND) == POLLRDBAND) { associndex_str_int(o->v_assoc, makenewstring("rdband"), POLLRDBAND); - if ((pollfds[s].revents & POLLRDNORM) == POLLRDNORM) + } + if ((pollfds[s].revents & POLLRDNORM) == POLLRDNORM) { associndex_str_int(o->v_assoc, makenewstring("rdnorm"), POLLRDNORM); - if ((pollfds[s].revents & POLLWRBAND) == POLLWRBAND) + } + if ((pollfds[s].revents & POLLWRBAND) == POLLWRBAND) { associndex_str_int(o->v_assoc, makenewstring("wrband"), POLLWRBAND); - if ((pollfds[s].revents & POLLWRNORM) == POLLWRNORM) + } + if ((pollfds[s].revents & POLLWRNORM) == POLLWRNORM) { associndex_str_int(o->v_assoc, makenewstring("wrnorm"), POLLWRNORM); + } insertlistlast(ol, o); } ov->v_list = ol; - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(r); + return result; } + /* * u_pfe_wait4 - wait for process termination * * wh/ n1 is zero-index of 1st number, * given: - * vals[n1+0] pid wh/ null() means any children à la man 2 wait # aka wait(2) and only vals[n1+1] allowed - * vals[n1+1] address of assoc of status w/ one pair of key with companion(s): "exited" &then "exitstatus", "signaled" &then "termsig" & "coredump", "stopped" &then "stopsig" acc2 man 2 wait # aka wait(2) - * vals[n1+2] null or list of options "nohang" or "untraced" acc2 man TODO test - * vals[n1+3] null or address of assoc of usage TODO handle + * vals[n1+0] pid wh/ null() means any children a la man 2 wait + * # aka wait(2) and only vals[n1+1] allowed + * vals[n1+1] address of assoc of status w/ one pair of key with companion(s): "exited" and then + * "exitstatus","signaled" and then + * "termsig" and "coredump", "stopped" and then + * "stopsig" acc2 man 2 wait + * # aka wait(2) + * vals[n1+2] null or list of options "nohang" or "untraced" acc2 man TODO test + * vals[n1+3] null or address of assoc of usage TODO handle * * returns: - * pid or 0 w/ "nohang" + * pid or 0 w/ "nohang" */ /*ARGSUSED*/ VALUE u_pfe_wait4(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "wait4"; - int v = 0; - VALUE *pid_num = valv_optional_get_num(count, vals, &v, "pid", NULL); - VALUE *stt_assoc = valv_ref_assoc(custname, count, vals, v++, - "status"); // stat in - VALUE *opt_list = valv_optional_get_list(count, vals, &v, "options", NULL); - VALUE *usg_assoc = valv_optional_ref_assoc(count, vals, &v, "usage", NULL); - - if (!pid_num && opt_list) + int v = 0; + int stt = 0; + struct rusage usg; + struct rusage *usg_p; + pid_t r; + int opts = 0; + VALUE *pid_num; + VALUE *stt_assoc; + VALUE *opt_list; + VALUE *usg_assoc; + LISTELEM *el; + int s = 0; + char *opt_str; + + pid_num = valv_optional_get_num(count, vals, &v, "pid", NULL); + stt_assoc = valv_ref_assoc(custname, count, vals, v++, "status"); /* stat in */ + opt_list = valv_optional_get_list(count, vals, &v, "options", NULL); + usg_assoc = valv_optional_ref_assoc(count, vals, &v, "usage", NULL); + + if (!pid_num && opt_list) { math_error("%s: argument 1 (pid) being null doesn't support options list", custname); - if (!pid_num && usg_assoc) + } + if (!pid_num && usg_assoc) { math_error("%s: argument 1 (pid) being null doesn't support usage assoc", custname); + } - int opts = 0; if (opt_list) { - LISTELEM *el = opt_list->v_list->l_first; - int s = 0; + el = opt_list->v_list->l_first; for (; el != NULL; el = el->e_next, s++) { - if (el->e_value.v_type != V_STR) + if (el->e_value.v_type != V_STR) { math_error("%s: options list element %d must be of type string (%s given)", custname, s, type2str(el->e_value.v_type)); + } - char *opt_str = el->e_value.v_str->s_str; - if (FALSE) + opt_str = el->e_value.v_str->s_str; + if (FALSE) { ; - else if (!strcmp(opt_str, "nohang")) opts |= WNOHANG; - else if (!strcmp(opt_str, "untraced")) opts |= WUNTRACED; - else + } else if (!strcmp(opt_str, "nohang")) { + opts |= WNOHANG; + } else if (!strcmp(opt_str, "untraced")) { + opts |= WUNTRACED; + } else { math_error("%s: options list element %d must be one of \"nohang\" or \"untraced\" (%s given)", custname, s, opt_str); + } } } - int stt = 0; - struct rusage usg; - struct rusage *usg_p = usg_assoc ? &usg : NULL; - pid_t r = pid_num ? wait4(qtoi(pid_num->v_num), &stt, opts, usg_p) - : wait(&stt); + usg_p = usg_assoc ? &usg : NULL; + r = pid_num ? wait4(qtoi(pid_num->v_num), &stt, opts, usg_p) : wait(&stt); - if (0 > r) + if (0 > r) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); + } if (WIFEXITED(stt)) { associndex_str_int(stt_assoc->v_assoc, makenewstring("exited"), TRUE); @@ -1076,464 +1544,556 @@ u_pfe_wait4(char *UNUSED(name), int count, VALUE **vals) WSTOPSIG(stt)); } - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(r); + return result; } + /* * u_pfe_pfe - pipe/fork/exec * * given: - * vals[0] address of fd for in - * vals[1] address of fd for out - * vals[2] address of fd for err - * vals[3] list of args + * vals[0] address of fd for in + * vals[1] address of fd for out + * vals[2] address of fd for err + * vals[3] list of args * * returns: - * forked pid + * forked pid */ /*ARGSUSED*/ VALUE u_pfe_pfe(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "pfe"; - - int ia[2]; // in array - if (pipe(ia)) + LISTELEM *el; + int s; + char **args; + VALUE *args_list; + VALUE *iv; + VALUE *ov; + VALUE *ev; + int cci; + int cco; + int cce; + int pci; + int pco; + int pce; + int ia[2]; /* in array */ + int oa[2]; /* out array */ + int ea[2]; /* err array */ + pid_t child; + + if (pipe(ia)) { math_error("%s: "__FILE__ ": %d: (in) pipe: %s", custname, __LINE__, strerror(errno)); - int oa[2]; // out array - if (pipe(oa)) + } + if (pipe(oa)) { math_error("%s: "__FILE__ ": %d: (out) pipe: %s", custname, __LINE__, strerror(errno)); - int ea[2]; // err array - if (pipe(ea)) + } + if (pipe(ea)) { math_error("%s: "__FILE__ ": %d: (err) pipe: %s", custname, __LINE__, strerror(errno)); - // in, out, err values - VALUE *iv = valv_ref_num(custname, count, vals, 0, "in"); - VALUE *ov = valv_ref_num(custname, count, vals, 1, "out"); - VALUE *ev = valv_ref_num(custname, count, vals, 2, "err"); + } + /* in, out, err values */ + iv = valv_ref_num(custname, count, vals, 0, "in"); + ov = valv_ref_num(custname, count, vals, 1, "out"); + ev = valv_ref_num(custname, count, vals, 2, "err"); iv->v_num = itoq(ia[1]); ov->v_num = itoq(oa[0]); ev->v_num = itoq(ea[0]); - pid_t child = fork(); + child = fork(); if (child) { - // child: close (parent in, out, err) - int cci = !close(ia[0]) ? 0 : errno; - int cco = !close(oa[1]) ? 0 : errno; - int cce = !close(ea[1]) ? 0 : errno; + /* child: close (parent in, out, err) */ + cci = !close(ia[0]) ? 0 : errno; + cco = !close(oa[1]) ? 0 : errno; + cce = !close(ea[1]) ? 0 : errno; - if (cci) + if (cci) { math_error("%s: "__FILE__ ": %d: child: (parent in) close: %s", custname, __LINE__, strerror(cci)); - if (cco) + } + if (cco) { math_error("%s: "__FILE__ ": %d: child: (parent out) close: %s", custname, __LINE__, strerror(cco)); - if (cce) + } + if (cce) { math_error("%s: "__FILE__ ": %d: child: (parent err) close: %s", custname, __LINE__, strerror(cce)); + } - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(child); + return result; } else { - // parent: close (child in, out, err) - int pci = !close(ia[1]) ? 0 : errno; - int pco = !close(oa[0]) ? 0 : errno; - int pce = !close(ea[0]) ? 0 : errno; + /* parent: close (child in, out, err) */ + pci = !close(ia[1]) ? 0 : errno; + pco = !close(oa[0]) ? 0 : errno; + pce = !close(ea[0]) ? 0 : errno; - if (pci) + if (pci) { math_error("%s: "__FILE__ ": %d: parent: (child in) close: %s", custname, __LINE__, strerror(pci)); - if (pco) + } + if (pco) { math_error("%s: "__FILE__ ": %d: parent: (child out) close: %s", custname, __LINE__, strerror(pco)); - if (pce) + } + if (pce) { math_error("%s: "__FILE__ ": %d: parent: (child err) close: %s", custname, __LINE__, strerror(pce)); + } - if (dup2(ia[0], 0) != 0) + if (dup2(ia[0], 0) != 0) { math_error("%s: "__FILE__ ": %d: mismatch: (in) dup2: %s", custname, __LINE__, strerror(errno)); - if (dup2(oa[1], 1) != 1) + } + if (dup2(oa[1], 1) != 1) { math_error("%s: "__FILE__ ": %d: mismatch: (out) dup2: %s", custname, __LINE__, strerror(errno)); - if (dup2(ea[1], 2) != 2) + } + if (dup2(ea[1], 2) != 2) { math_error("%s: "__FILE__ ": %d: mismatch: (err) dup2: %s", custname, __LINE__, strerror(errno)); + } - VALUE *args_list = valv_get_list(custname, count, vals, 3, "args"); + args_list = valv_get_list(custname, count, vals, 3, "args"); - char **args; - if (!(args = malloc(sizeof(char *) * (args_list->v_list->l_count + 1)))) + if (!(args = malloc(sizeof(char *) * (args_list->v_list->l_count + 1)))) { math_error("%s: "__FILE__ ": %d: malloc: %s", custname, __LINE__, strerror(errno)); + } - LISTELEM *el = args_list->v_list->l_first; - int s = 0; + el = args_list->v_list->l_first; + s = 0; for (; el != NULL; el = el->e_next, s++) { - if (el->e_value.v_type != V_STR) + if (el->e_value.v_type != V_STR) { math_error("%s: argment 2 (args) element %d must be of type string (%s given)", custname, s, type2str(el->e_value.v_type)); + } args[s] = el->e_value.v_str->s_str; } args[s] = NULL; - if (execvp(args[0], args)) + if (execvp(args[0], args)) { math_error("%s: "__FILE__ ": %d: execvp: %s", custname, __LINE__, strerror(errno)); + } free(args); - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(errno); + return result; } } + /* * u_pfe_pwrite - write and close * * given: - * vals[0] fd - * vals[1] string + * vals[0] fd + * vals[1] string * * returns: - * count of bytes written + * count of bytes written */ /*ARGSUSED*/ VALUE u_pfe_pwrite(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "pwrite"; + VALUE *strp; + int fd; + ssize_t w; + int e; - VALUE *strp = valv_get_strp(custname, count, vals, 1, "string"); + strp = valv_get_strp(custname, count, vals, 1, "string"); - int fd = valv_get_num_long(custname, count, vals, 0, "fd"); + fd = valv_get_num_long(custname, count, vals, 0, "fd"); - ssize_t w = write(fd, strp->v_str->s_str, strp->v_str->s_len); + w = write(fd, strp->v_str->s_str, strp->v_str->s_len); - if (w < 0) + if (w < 0) { math_error("%s: "__FILE__ ": %d: write: %s", custname, __LINE__, strerror(errno)); + } - int e = close(fd); + e = close(fd); - if (e) + if (e) { math_error("%s: "__FILE__ ": %d: close: %s", custname, __LINE__, strerror(errno)); + } - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(w); + return result; } - #define pfe_pfe_SIZE_BUFFER 4096 - #define pfe_pfe_SIZE_INIT 4096 -char * +static char * strext(char **subject, char *with) { - size_t n = strlen(*subject) + strlen(with); + size_t n; + + n = strlen(*subject) + strlen(with); if ((*subject = realloc(*subject, n + 1)) == NULL) { free(*subject); return NULL; } strlcat(*subject, with, n + 1); + return *subject; } + /* * u_pfe_pread - read until eof, close and wait for exit status * - * if wait4() encounters a signalled process, this function returns the signal + 128, like bash(1). + * if wait4() encounters a signalled process,this function returns the signal + 128, like bash(1). * * given: - * vals[0] pid - * vals[1] out - * vals[1] err + * vals[0] pid + * vals[1] out + * vals[1] err * * returns: - * list(status, stdout_string, stderr_string) + * list(status, stdout_string, stderr_string) */ /*ARGSUSED*/ VALUE u_pfe_pread(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "pread"; + int pid; + int out; + int err; + int ssz = 0; + fd_set nvm; /* never mind */ + fd_set nvm2; /* never mind II */ + fd_set rbs; /* read base set */ + /* Keep track of rbs */ + bool eoo = NULL; + bool eoe = NULL; + char *o; + char *e; + char ob[pfe_pfe_SIZE_BUFFER]; /* out buffer */ + char eb[pfe_pfe_SIZE_BUFFER]; /* err buffer */ + int pco = 0; + int pce = 0; + fd_set rcs; /* read check set */ + int stt = 0; + pid_t w; + NUMBER *r; + LIST *list; - int pid = valv_get_num_long(custname, count, vals, 0, "pid"); - int out = valv_get_num_long(custname, count, vals, 1, "out"); - int err = valv_get_num_long(custname, count, vals, 2, "err"); + pid = valv_get_num_long(custname, count, vals, 0, "pid"); + out = valv_get_num_long(custname, count, vals, 1, "out"); + err = valv_get_num_long(custname, count, vals, 2, "err"); - fd_set nvm; // never mind FD_ZERO(&nvm); - fd_set rbs; // read base set + FD_ZERO(&nvm2); + FD_ZERO(&rbs); - int ssz = 0; FD_SET(out, &rbs); - if (out > ssz) ssz = out; + if (out > ssz) { + ssz = out; + } FD_SET(err, &rbs); - if (err > ssz) ssz = err; - - // Keep track of rbs - bool eoo = NULL; // end of out - bool eoe = NULL; // end of err + if (err > ssz) { + ssz = err; + } - char *o = malloc(pfe_pfe_SIZE_INIT * sizeof(char)); + o = malloc(pfe_pfe_SIZE_INIT * sizeof(char)); o[0] = '\0'; - char *e = malloc(pfe_pfe_SIZE_INIT * sizeof(char)); + e = malloc(pfe_pfe_SIZE_INIT * sizeof(char)); e[0] = '\0'; - char ob[pfe_pfe_SIZE_BUFFER]; // out buffer - char eb[pfe_pfe_SIZE_BUFFER]; // err buffer - - int pco = 0; - int pce = 0; - - fd_set rcs; // read check set while (!eoo || !eoe) { memmove(&rcs, &rbs, sizeof(fd_set)); - int r = select(1 + ssz, &rcs, &nvm, &nvm, NULL); - if (r < 0) + int r = select(1 + ssz, &rcs, &nvm, &nvm2, NULL); + if (r < 0) { math_error("%s: "__FILE__ ": %d: select: %s", custname, __LINE__, strerror(errno)); + } if (FD_ISSET(out, &rcs)) { r = read(out, &ob, pfe_pfe_SIZE_BUFFER); - if (r < 0) + if (r < 0) { math_error("%s: "__FILE__ ": %d: (out, %lu) read: %s", custname, __LINE__, strlen(o), strerror(errno)); + } if (r) { ob[r] = '\0'; strext(&o, ob); } else { - if (close(out)) pco = errno; + if (close(out)) { + pco = errno; + } FD_CLR(out, &rbs); eoo = TRUE; } } if (FD_ISSET(err, &rcs)) { r = read(err, &eb, pfe_pfe_SIZE_BUFFER); - if (r < 0) + if (r < 0) { math_error("%s: "__FILE__ ": %d: (err, %lu) read: %s", custname, __LINE__, strlen(e), strerror(errno)); + } if (r) { eb[r] = '\0'; strext(&e, eb); } else { - if (close(err)) pce = errno; + if (close(err)) { + pce = errno; + } FD_CLR(err, &rbs); eoe = TRUE; } } } - if (pco) + if (pco) { math_error("%s: "__FILE__ ": %d: (out) close: %s", custname, __LINE__, strerror(pco)); - if (pce) + } + if (pce) { math_error("%s: "__FILE__ ": %d: (err) close: %s", custname, __LINE__, strerror(pce)); + } - int stt = 0; - pid_t w = wait4(pid, &stt, 0, NULL); + w = wait4(pid, &stt, 0, NULL); - if (0 > w) + if (0 > w) { math_error("%s: "__FILE__ ": %d: wait4: %s", custname, __LINE__, strerror(errno)); + } - NUMBER *r = itoq((!WIFEXITED(stt) ? 0 : WEXITSTATUS(stt)) - + (!WIFSTOPPED(stt) ? 0 : 128 + WSTOPSIG(stt)) - + (!WIFSIGNALED(stt) ? 0 : 128 + WTERMSIG(stt))); + r = itoq((!WIFEXITED(stt) ? 0 : WEXITSTATUS(stt)) + + (!WIFSTOPPED(stt) ? 0 : 128 + WSTOPSIG(stt)) + + (!WIFSIGNALED(stt) ? 0 : 128 + WTERMSIG(stt))); - LIST *list = listalloc(); + list = listalloc(); insertlistlast(list, alloc_num(r)); insertlistlast(list, alloc_str(makestring(o))); insertlistlast(list, alloc_str(makestring(e))); - VALUE result; result.v_subtype = 0; result.v_type = V_LIST; result.v_list = list; + return result; } + /* * u_vadd_getpid - get calling process identification * * returns: - * pid + * pid */ /*ARGSUSED*/ VALUE u_vadd_getpid(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) { + VALUE result; const char *UNUSED(custname) = "getpid"; + pid_t pid; - pid_t pid = getpid(); + pid = getpid(); - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(pid); + return result; } + /* * u_vadd_getppid - get parent process identification * * returns: - * pid + * pid */ /*ARGSUSED*/ VALUE u_vadd_getppid(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) { + VALUE result; const char *UNUSED(custname) = "getppid"; + pid_t pid; - pid_t pid = getppid(); + pid = getppid(); - VALUE result; result.v_subtype = 0; result.v_type = V_NUM; result.v_num = itoq(pid); + return result; } + /* * u_vadd_getcwd - get working directory pathname * * returns: - * path + * path */ /*ARGSUSED*/ VALUE u_vadd_getcwd(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) { + VALUE result; const char *custname = "getcwd"; - - char *buf = getcwd(NULL, - -1); // doing equiv(malloc) COULD use MAXPATHLEN from and s/makestring/makenewstring/ below I guess - if (!buf) + char *buf; + + /* + * doing equiv(malloc) COULD use MAXPATHLEN from + * and s/makestring/makenewstring/ below I guess + */ + buf = getcwd(NULL, -1); + if (!buf) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); + } - VALUE result; result.v_subtype = 0; result.v_type = V_STR; result.v_str = makestring(buf); + return result; } + /* * u_vadd_inputname - get working directory pathname * * returns: - * name + * name */ /*ARGSUSED*/ VALUE u_vadd_inputname(char *UNUSED(name), int UNUSED(count), - VALUE **UNUSED(vals)) //cspell:ignore inputname + VALUE **UNUSED(vals)) { + VALUE result; const char *UNUSED(custname) = "inputname"; + char *buf; - char *buf = inputname(); - if (!buf) + buf = inputname(); + if (!buf) { buf = inputisterminal() ? "" - : ""; //cspell:ignore inputisterminal + : ""; + } - VALUE result; result.v_subtype = 0; result.v_type = V_STR; result.v_str = makenewstring(buf); + return result; } + /* * u_vadd_basename - extract the base portion of a pathname * * given: - * vals[0] path + * vals[0] path * * returns: - * path + * path */ /*ARGSUSED*/ VALUE u_vadd_basename(char *UNUSED(name), int count, VALUE **vals) { + VALUE result; const char *custname = "basename"; + char buf[MAXPATHLEN]; + VALUE *strp; - VALUE *strp = valv_get_strp(custname, count, vals, 0, "path"); + strp = valv_get_strp(custname, count, vals, 0, "path"); - char buf[MAXPATHLEN]; strlcpy(buf, basename(strp->v_str->s_str), sizeof(buf)); - if (!*buf) + if (!*buf) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); + } - VALUE result; result.v_subtype = 0; result.v_type = V_STR; result.v_str = makenewstring(buf); + return result; } + /* * u_vadd_dirname - extract the base portion of a pathname * * given: - * vals[0] path + * vals[0] path * * returns: - * path + * path */ /*ARGSUSED*/ VALUE u_vadd_dirname(char *UNUSED(name), int count, VALUE **vals) { - const char *custname = "dirname"; + VALUE result; + const char *custname = "dirname"; + VALUE *strp; + char buf[MAXPATHLEN]; - VALUE *strp = valv_get_strp(custname, count, vals, 0, "path"); + fd_set nvm; /* never mind */ + FD_ZERO(&nvm); + + strp = valv_get_strp(custname, count, vals, 0, "path"); - char buf[MAXPATHLEN]; strlcpy(buf, dirname(strp->v_str->s_str), sizeof(buf)); - if (!*buf) + if (!*buf) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); + } - VALUE result; result.v_subtype = 0; result.v_type = V_STR; result.v_str = makenewstring(buf); + return result; } + #endif /* CUSTOM */ diff --git a/file.h b/file.h index a3b1d3e1d..c3c797a69 100644 --- a/file.h +++ b/file.h @@ -33,7 +33,7 @@ #include -#if defined(CALC_SRC) /* if we are building from the calc source tree */ +#if defined(CALC_SRC) /* if we are building from the calc source tree */ # include "value.h" # include "have_fgetsetpos.h" #else From 0d722173f5c7a50a4a696942a2fef1034a308754 Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Mon, 15 Sep 2025 00:31:59 -0700 Subject: [PATCH 20/21] fix use strlcat(3) and strlcpy(3) On systems that have `strlcat(3)` and `strlcpy(3)`, not everyone uses the same function prototype. We renamed the static functions in `custom/u_pfe.c` to begin with `private_`. --- custom/u_pfe.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/custom/u_pfe.c b/custom/u_pfe.c index 4fcdc28f2..4d21dc257 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -103,8 +103,8 @@ static VALUE *u_pfe_poll_TIMEOUT_DFLT = NULL; /* * forward declarations */ -static size_t strlcat(char *dst, const char *src, size_t dsize); -static size_t strlcpy(char *dst, const char *src, size_t dsize); +static size_t private_strlcat(char *dst, const char *src, size_t dsize); +static size_t private_strlcpy(char *dst, const char *src, size_t dsize); static const char * type2str(short type); static VALUE * associndex_int(ASSOC *assoc, long index); static VALUE * associndex_str(ASSOC *assoc, STRING *index); @@ -173,7 +173,7 @@ static char * strext(char **subject, char *with); /* - * strlcat - size-bounded string concatenation + * private_strlcat - size-bounded string concatenation * * Sadly, strlcat(3) is not portable enough for a number of supported calc v2 enviroments. * So we will include as a static function below, strlcat.c from: @@ -187,7 +187,7 @@ static char * strext(char **subject, char *with); * If retval >= dsize, truncation occurred. */ static size_t -strlcat(char *dst, const char *src, size_t dsize) +private_strlcat(char *dst, const char *src, size_t dsize) { const char *odst = dst; const char *osrc = src; @@ -222,7 +222,7 @@ strlcat(char *dst, const char *src, size_t dsize) /* - * strlcpy - size-bounded string copying + * private_strlcpy - size-bounded string copying * * Copy string src to buffer dst of size dsize. At most dsize-1 * chars will be copied. Always NUL terminates (unless dsize == 0). @@ -234,7 +234,7 @@ strlcat(char *dst, const char *src, size_t dsize) * https://github.com/libressl/openbsd/blob/master/src/lib/libc/string/strlcpy.c */ static size_t -strlcpy(char *dst, const char *src, size_t dsize) +private_strlcpy(char *dst, const char *src, size_t dsize) { const char *osrc = src; size_t nleft = dsize; @@ -1762,7 +1762,7 @@ strext(char **subject, char *with) free(*subject); return NULL; } - strlcat(*subject, with, n + 1); + private_strlcat(*subject, with, n + 1); return *subject; } @@ -2043,7 +2043,7 @@ u_vadd_basename(char *UNUSED(name), int count, VALUE **vals) strp = valv_get_strp(custname, count, vals, 0, "path"); - strlcpy(buf, basename(strp->v_str->s_str), sizeof(buf)); + private_strlcpy(buf, basename(strp->v_str->s_str), sizeof(buf)); if (!*buf) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); @@ -2081,7 +2081,7 @@ u_vadd_dirname(char *UNUSED(name), int count, VALUE **vals) strp = valv_get_strp(custname, count, vals, 0, "path"); - strlcpy(buf, dirname(strp->v_str->s_str), sizeof(buf)); + private_strlcpy(buf, dirname(strp->v_str->s_str), sizeof(buf)); if (!*buf) { math_error("%s: "__FILE__ ": %d: %s", custname, __LINE__, strerror(errno)); From 3112846a243baf69e28916392f1a244c8555c5e8 Mon Sep 17 00:00:00 2001 From: Landon Curt Noll Date: Mon, 15 Sep 2025 00:50:27 -0700 Subject: [PATCH 21/21] use S_FUNC in custom/u_pfe.c For calc v2, we need to declare static functions with `S_FUNC`. --- custom/u_pfe.c | 150 ++++++++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/custom/u_pfe.c b/custom/u_pfe.c index 4d21dc257..6fe6f1722 100644 --- a/custom/u_pfe.c +++ b/custom/u_pfe.c @@ -94,89 +94,89 @@ typedef enum { /* - * static declations + * S_FUNC declations */ -static VALUE *pfe_select_TIMEOUT_DFLT = NULL; -static VALUE *u_pfe_poll_TIMEOUT_DFLT = NULL; +S_FUNC VALUE *pfe_select_TIMEOUT_DFLT = NULL; +S_FUNC VALUE *u_pfe_poll_TIMEOUT_DFLT = NULL; /* * forward declarations */ -static size_t private_strlcat(char *dst, const char *src, size_t dsize); -static size_t private_strlcpy(char *dst, const char *src, size_t dsize); -static const char * type2str(short type); -static VALUE * associndex_int(ASSOC *assoc, long index); -static VALUE * associndex_str(ASSOC *assoc, STRING *index); -static void associndex_int_int(ASSOC *assoc, long index, long value); -static void associndex_str_int(ASSOC *assoc, STRING *index, long value); -static valv_opt valv_optional_type_check(int count, VALUE **vals, int idx, +S_FUNC size_t private_strlcat(char *dst, const char *src, size_t dsize); +S_FUNC size_t private_strlcpy(char *dst, const char *src, size_t dsize); +S_FUNC const char * type2str(short type); +S_FUNC VALUE * associndex_int(ASSOC *assoc, long index); +S_FUNC VALUE * associndex_str(ASSOC *assoc, STRING *index); +S_FUNC void associndex_int_int(ASSOC *assoc, long index, long value); +S_FUNC void associndex_str_int(ASSOC *assoc, STRING *index, long value); +S_FUNC valv_opt valv_optional_type_check(int count, VALUE **vals, int idx, const char *UNUSED(name), short wanted); -static valv_opt valv_optional_ref_type_check(int count, VALUE **vals, int idx, +S_FUNC valv_opt valv_optional_ref_type_check(int count, VALUE **vals, int idx, const char *UNUSED(name), short wanted); -static bool valv_type_check(int UNUSED(count), VALUE **vals, int idx, +S_FUNC bool valv_type_check(int UNUSED(count), VALUE **vals, int idx, const char *UNUSED(name), short wanted); -static void valv_type_require(const char *custname, int count, VALUE **vals, int idx, +S_FUNC void valv_type_require(const char *custname, int count, VALUE **vals, int idx, const char *name, short wanted); -static bool valv_ref_type_check(int UNUSED(count), VALUE **vals, int idx, +S_FUNC bool valv_ref_type_check(int UNUSED(count), VALUE **vals, int idx, const char *UNUSED(name), short wanted); -static void valv_ref_type_require(const char *custname, int count, VALUE **vals, int idx, +S_FUNC void valv_ref_type_require(const char *custname, int count, VALUE **vals, int idx, const char *name, short wanted); -static long valv_get_num_long(const char *custname, int count, VALUE **vals, int idx, +S_FUNC long valv_get_num_long(const char *custname, int count, VALUE **vals, int idx, const char *name); -static VALUE * valv_optional_get_num(int count, VALUE **vals, int *idx, const char *name, +S_FUNC VALUE * valv_optional_get_num(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt); #if 0 /* function defined but not used */ -static VALUE * valv_optional_ref_num(int count, VALUE **vals, int *idx, const char *name, +S_FUNC VALUE * valv_optional_ref_num(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt); #endif /* function defined but not used */ -static VALUE * valv_ref_num(const char *custname, int count, VALUE **vals, int idx, +S_FUNC VALUE * valv_ref_num(const char *custname, int count, VALUE **vals, int idx, const char *name); #if 0 /* function defined but not used */ -static VALUE * valv_get_num(const char *custname, int count, VALUE **vals, int idx, +S_FUNC VALUE * valv_get_num(const char *custname, int count, VALUE **vals, int idx, const char *name); #endif /* function defined but not used */ -static char * valv_get_str(const char *custname, int count, VALUE **vals, int idx, +S_FUNC char * valv_get_str(const char *custname, int count, VALUE **vals, int idx, const char *name); -static VALUE * valv_get_strp(const char *custname, int count, VALUE **vals, int idx, +S_FUNC VALUE * valv_get_strp(const char *custname, int count, VALUE **vals, int idx, const char *name); #if 0 /* function defined but not used */ -static VALUE * valv_optional_ref_list(int count, VALUE **vals, int *idx, const char *name, +S_FUNC VALUE * valv_optional_ref_list(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt); #endif /* function defined but not used */ -static VALUE * valv_optional_get_list(int count, VALUE **vals, int *idx, const char *name, +S_FUNC VALUE * valv_optional_get_list(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt); -static VALUE * valv_get_list(const char *custname, int count, VALUE **vals, int idx, +S_FUNC VALUE * valv_get_list(const char *custname, int count, VALUE **vals, int idx, const char *name); -static VALUE * valv_ref_list(const char *custname, int count, VALUE **vals, int idx, +S_FUNC VALUE * valv_ref_list(const char *custname, int count, VALUE **vals, int idx, const char *name); #if 0 /* function defined but not used */ -static VALUE * valv_optional_get_assoc(int count, VALUE **vals, int *idx, const char *name, +S_FUNC VALUE * valv_optional_get_assoc(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt); #endif /* function defined but not used */ -static VALUE * valv_optional_ref_assoc(int count, VALUE **vals, int *idx, const char *name, +S_FUNC VALUE * valv_optional_ref_assoc(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt); #if 0 /* function defined but not used */ -static VALUE * valv_get_assoc(const char *custname, int count, VALUE **vals, int idx, +S_FUNC VALUE * valv_get_assoc(const char *custname, int count, VALUE **vals, int idx, const char *name); #endif /* function defined but not used */ -static VALUE * valv_ref_assoc(const char *custname, int count, VALUE **vals, int idx, +S_FUNC VALUE * valv_ref_assoc(const char *custname, int count, VALUE **vals, int idx, const char *name); -static VALUE * optional_valv_ref_list2fd_set(const char *custname, int count, VALUE **vals, +S_FUNC VALUE * optional_valv_ref_list2fd_set(const char *custname, int count, VALUE **vals, int *idx, const char *name, fd_set *fds, int *setsize); -static VALUE * alloc_list(LIST *list); -static VALUE * alloc_assoc(ASSOC *assoc); -static VALUE * list_fd_get(LIST *in, fd_set *fds); -static VALUE * alloc_num(NUMBER *num); -static VALUE * alloc_str(STRING *str); -static char * strext(char **subject, char *with); +S_FUNC VALUE * alloc_list(LIST *list); +S_FUNC VALUE * alloc_assoc(ASSOC *assoc); +S_FUNC VALUE * list_fd_get(LIST *in, fd_set *fds); +S_FUNC VALUE * alloc_num(NUMBER *num); +S_FUNC VALUE * alloc_str(STRING *str); +S_FUNC char * strext(char **subject, char *with); /* * private_strlcat - size-bounded string concatenation * * Sadly, strlcat(3) is not portable enough for a number of supported calc v2 enviroments. - * So we will include as a static function below, strlcat.c from: + * So we will include as a S_FUNC function below, strlcat.c from: * * https://github.com/libressl/openbsd/blob/master/src/lib/libc/string/strlcat.c * @@ -186,7 +186,7 @@ static char * strext(char **subject, char *with); * Returns strlen(src) + MIN(dsize, strlen(initial dst)). * If retval >= dsize, truncation occurred. */ -static size_t +S_FUNC size_t private_strlcat(char *dst, const char *src, size_t dsize) { const char *odst = dst; @@ -229,11 +229,11 @@ private_strlcat(char *dst, const char *src, size_t dsize) * Returns strlen(src); if retval >= dsize, truncation occurred. * * Sadly, strlcpy(3) is not portable enough for a number of supported calc v2 enviroments. - * So we will include as a static function below, strlcpy.c from: + * So we will include as a S_FUNC function below, strlcpy.c from: * * https://github.com/libressl/openbsd/blob/master/src/lib/libc/string/strlcpy.c */ -static size_t +S_FUNC size_t private_strlcpy(char *dst, const char *src, size_t dsize) { const char *osrc = src; @@ -266,7 +266,7 @@ private_strlcpy(char *dst, const char *src, size_t dsize) } -static const char * +S_FUNC const char * type2str(short type) { /* originally from c_argv.c */ @@ -334,7 +334,7 @@ u_pfe_fork(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) } -static VALUE * +S_FUNC VALUE * associndex_int(ASSOC *assoc, long index) { VALUE i; @@ -352,7 +352,7 @@ associndex_int(ASSOC *assoc, long index) } -static VALUE * +S_FUNC VALUE * associndex_str(ASSOC *assoc, STRING *index) { VALUE i; @@ -370,7 +370,7 @@ associndex_str(ASSOC *assoc, STRING *index) } -static void +S_FUNC void associndex_int_int(ASSOC *assoc, long index, long value) { VALUE *i; @@ -383,7 +383,7 @@ associndex_int_int(ASSOC *assoc, long index, long value) } -static void +S_FUNC void associndex_str_int(ASSOC *assoc, STRING *index, long value) { VALUE *i; @@ -429,7 +429,7 @@ u_pfe_pipe(char *UNUSED(name), int UNUSED(count), VALUE **UNUSED(vals)) } -static valv_opt +S_FUNC valv_opt valv_optional_type_check(int count, VALUE **vals, int idx, const char *UNUSED(name), short wanted) { @@ -447,7 +447,7 @@ valv_optional_type_check(int count, VALUE **vals, int idx, } -static valv_opt +S_FUNC valv_opt valv_optional_ref_type_check(int count, VALUE **vals, int idx, const char *UNUSED(name), short wanted) { @@ -471,7 +471,7 @@ valv_optional_ref_type_check(int count, VALUE **vals, int idx, } -static bool +S_FUNC bool valv_type_check(int UNUSED(count), VALUE **vals, int idx, const char *UNUSED(name), short wanted) { @@ -483,7 +483,7 @@ valv_type_check(int UNUSED(count), VALUE **vals, int idx, } -static void +S_FUNC void valv_type_require(const char *custname, int count, VALUE **vals, int idx, const char *name, short wanted) { @@ -496,7 +496,7 @@ valv_type_require(const char *custname, int count, VALUE **vals, int idx, } -static bool +S_FUNC bool valv_ref_type_check(int UNUSED(count), VALUE **vals, int idx, const char *UNUSED(name), short wanted) { @@ -508,7 +508,7 @@ valv_ref_type_check(int UNUSED(count), VALUE **vals, int idx, } -static void +S_FUNC void valv_ref_type_require(const char *custname, int count, VALUE **vals, int idx, const char *name, short wanted) { @@ -527,7 +527,7 @@ valv_ref_type_require(const char *custname, int count, VALUE **vals, int idx, } -static long +S_FUNC long valv_get_num_long(const char *custname, int count, VALUE **vals, int idx, const char *name) { @@ -537,7 +537,7 @@ valv_get_num_long(const char *custname, int count, VALUE **vals, int idx, } -static VALUE * +S_FUNC VALUE * valv_optional_get_num(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { @@ -566,7 +566,7 @@ valv_optional_get_num(int count, VALUE **vals, int *idx, const char *name, #if 0 /* function defined but not used */ -static VALUE * +S_FUNC VALUE * valv_optional_ref_num(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { @@ -599,7 +599,7 @@ valv_optional_ref_num(int count, VALUE **vals, int *idx, const char *name, #endif /* function defined but not used */ -static VALUE * +S_FUNC VALUE * valv_ref_num(const char *custname, int count, VALUE **vals, int idx, const char *name) { @@ -610,7 +610,7 @@ valv_ref_num(const char *custname, int count, VALUE **vals, int idx, #if 0 /* function defined but not used */ -static VALUE * +S_FUNC VALUE * valv_get_num(const char *custname, int count, VALUE **vals, int idx, const char *name) { @@ -621,7 +621,7 @@ valv_get_num(const char *custname, int count, VALUE **vals, int idx, #endif /* function defined but not used */ -static char * +S_FUNC char * valv_get_str(const char *custname, int count, VALUE **vals, int idx, const char *name) { @@ -631,7 +631,7 @@ valv_get_str(const char *custname, int count, VALUE **vals, int idx, } -static VALUE * +S_FUNC VALUE * valv_get_strp(const char *custname, int count, VALUE **vals, int idx, const char *name) { @@ -642,7 +642,7 @@ valv_get_strp(const char *custname, int count, VALUE **vals, int idx, #if 0 /* function defined but not used */ -static VALUE * +S_FUNC VALUE * valv_optional_ref_list(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { @@ -672,7 +672,7 @@ valv_optional_ref_list(int count, VALUE **vals, int *idx, const char *name, #endif /* function defined but not used */ -static VALUE * +S_FUNC VALUE * valv_optional_get_list(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { @@ -700,7 +700,7 @@ valv_optional_get_list(int count, VALUE **vals, int *idx, const char *name, } -static VALUE * +S_FUNC VALUE * valv_get_list(const char *custname, int count, VALUE **vals, int idx, const char *name) { @@ -710,7 +710,7 @@ valv_get_list(const char *custname, int count, VALUE **vals, int idx, } -static VALUE * +S_FUNC VALUE * valv_ref_list(const char *custname, int count, VALUE **vals, int idx, const char *name) { @@ -721,7 +721,7 @@ valv_ref_list(const char *custname, int count, VALUE **vals, int idx, #if 0 /* function defined but not used */ -static VALUE * +S_FUNC VALUE * valv_optional_get_assoc(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { @@ -750,7 +750,7 @@ valv_optional_get_assoc(int count, VALUE **vals, int *idx, const char *name, #endif /* function defined but not used */ -static VALUE * +S_FUNC VALUE * valv_optional_ref_assoc(int count, VALUE **vals, int *idx, const char *name, VALUE *dflt) { @@ -778,7 +778,7 @@ valv_optional_ref_assoc(int count, VALUE **vals, int *idx, const char *name, #if 0 /* function defined but not used */ -static VALUE * +S_FUNC VALUE * valv_get_assoc(const char *custname, int count, VALUE **vals, int idx, const char *name) { @@ -788,7 +788,7 @@ valv_get_assoc(const char *custname, int count, VALUE **vals, int idx, #endif /* function defined but not used */ -static VALUE * +S_FUNC VALUE * valv_ref_assoc(const char *custname, int count, VALUE **vals, int idx, const char *name) { @@ -1034,7 +1034,7 @@ u_pfe_read(char *UNUSED(name), int count, VALUE **vals) return result; } -static VALUE * +S_FUNC VALUE * optional_valv_ref_list2fd_set(const char *custname, int count, VALUE **vals, int *idx, const char *name, fd_set *fds, int *setsize) { @@ -1080,7 +1080,7 @@ optional_valv_ref_list2fd_set(const char *custname, int count, VALUE **vals, } -static VALUE * +S_FUNC VALUE * alloc_list(LIST *list) { VALUE *result; @@ -1094,7 +1094,7 @@ alloc_list(LIST *list) } -static VALUE * +S_FUNC VALUE * alloc_assoc(ASSOC *assoc) { VALUE *result; @@ -1108,7 +1108,7 @@ alloc_assoc(ASSOC *assoc) } -static VALUE * +S_FUNC VALUE * list_fd_get(LIST *in, fd_set *fds) { VALUE *out; @@ -1132,7 +1132,7 @@ list_fd_get(LIST *in, fd_set *fds) } -static VALUE * +S_FUNC VALUE * alloc_num(NUMBER *num) { VALUE *result; @@ -1146,7 +1146,7 @@ alloc_num(NUMBER *num) } -static VALUE * +S_FUNC VALUE * alloc_str(STRING *str) { VALUE *result; @@ -1752,7 +1752,7 @@ u_pfe_pwrite(char *UNUSED(name), int count, VALUE **vals) } -static char * +S_FUNC char * strext(char **subject, char *with) { size_t n;