+ execargs= newargs;
+ execpath= fn;
+ return 0;
+}
+
+/* Parsing builtin service requests (execute-builtin) */
+
+static int bispa_none(char ***rnewargs) {
+ return pa_mnl();
+}
+
+static int bispa_parameter(char ***rnewargs) {
+ int r, i;
+ char **parmvalues, *name, **newargs;
+
+ r= pa_mwsp(); if (r) return r;
+ r= pa_parameter(&parmvalues,&name); if (r) return r;
+ for (i=0; parmvalues[i]; i++);
+ newargs= xmalloc(sizeof(char*)*(i+2));
+ newargs[0]= name;
+ memcpy(newargs+1,parmvalues,sizeof(char*)*(i+1));
+ free(parmvalues);
+ r= pa_mnl(); if (r) { free(newargs); return r; }
+ *rnewargs= newargs;
+ return 0;
+}
+
+int df_executebuiltin(int dtoken) {
+ int r;
+ builtinserviceexec_fnt *bisexec;
+ char *newpath, **newargs;
+
+ r= pa_mwsp(); if (r) return r;
+ r= yylex(); if (r == tokv_error) return r;
+ if (!(r & tokt_builtinservice)) return unexpected(r,-1,"builtin service name");
+ bisexec= lr_bisexec;
+ newpath= xstrsave(yytext);
+ newargs= 0;
+ r= lr_bispa(&newargs); if (r) { free(newpath); return r; }
+
+ execreset();
+ execute= tokv_word_executebuiltin;
+ execbuiltin= bisexec;
+ execpath= newpath;
+ execargs= newargs;
+ return 0;
+}
+
+/* Directives for changing other execution parameters */
+
+int dfg_setflag(int dtoken) {
+ int r;
+
+ r= pa_mnl(); if (r) return r;
+ *lr_flag= lr_flagval;
+ return 0;
+}
+
+int df_reset(int dtoken) {
+ int r;
+
+ r= pa_mnl(); if (r) return r;
+ r= parse_string(RESET_CONFIGURATION,"<builtin reset configuration>",1);
+ assert(!r);
+ return 0;
+}
+
+int dfg_fdwant(int dtoken) {
+ int fdmin, fdmax, r, needreadwrite, havereadwrite, fd;
+
+ needreadwrite= lr_fdwant_readwrite;
+ r= pa_mwsp(); if (r) return r;
+ r= yylex(); if (r == tokv_error) return r;
+ if (!(r & tokt_fdrange)) return unexpected(r,-1,"file descriptor range");
+ fdmin= lr_min; fdmax= lr_max;
+ if (fdmin<0 || fdmin>MAX_ALLOW_FD ||
+ (fdmax != -1 && fdmax<0) || fdmax>MAX_ALLOW_FD) {
+ parseerrprint("file descriptor in range is negative or far too large");
+ return tokv_error;
+ }
+ r= yylex(); if (r == tokv_error) return r;
+ if (r == tokv_newline) {
+ if (needreadwrite > 0) {
+ parseerrprint("read or write is required");
+ return tokv_error;
+ }
+ havereadwrite= 0;
+ } else if (r == tokv_lwsp) {
+ if (needreadwrite < 0) {
+ parseerrprint("read or write not allowed"); return tokv_error;
+ }
+ r= yylex(); if (r == tokv_error) return r;
+ if (!(r & tokt_readwrite))
+ return unexpected(r,-1,"read or write (or perhaps newline)");
+ havereadwrite= r;
+ r= pa_mnl(); if (r) return r;
+ } else {
+ return unexpected(r,-1,"whitespace before read or write or newline");
+ }
+ ensurefdarray(fdmin);
+ if (fdmax == -1) {
+ if (!(dtoken == tokv_word_rejectfd || dtoken == tokv_word_ignorefd))
+ parseerrprint("unspecified maximum only allowed with reject-fd and ignore-fd");
+ fdmax= fdarrayused-1;
+ restfdwantstate= dtoken;
+ restfdwantrw= havereadwrite;
+ }
+ ensurefdarray(fdmax);
+ for (fd=fdmin; fd<=fdmax; fd++) {
+ fdarray[fd].wantstate= dtoken;
+ fdarray[fd].wantrw= havereadwrite;
+ }