void o_doscanf (void) { struct operand o; struct operand o_sv[64]; char format[SZ_LINE]; int nargs, i; /* Get number of arguments. */ o = popop(); nargs = o.o_val.v_i; /* Get scan format. Unfortunately the way the parser works this * is the last operand on the stack. We need to pop and save the * first nargs-1 operands and restore them when done. */ for (i=0; i < nargs-1; i++) o_sv[i] = popop(); o = popop(); if ((o.o_type & OT_BASIC) != OT_STRING) cl_error (E_UERR, "scanf: bad format string\n"); strcpy (format, o.o_val.v_s); for (--i; i >= 0; i--) pushop (&o_sv[i]); /* Do the scan. */ cl_scanf (format, nargs-2, "stdin"); }
/* <value to be concatenated onto named parameter> . */ void o_catassign (memel *argp) { char *pname = (char *) argp; char *pk, *t, *p, *f; char s1[1024+1]; struct operand o1, o2; struct param *pp; breakout (pname, &pk, &t, &p, &f); pp = paramsrch (pk, t, p); paramget (pp, *f); /* If param value is undefined merely assign into it, otherwise * concatenate operand to current value. */ o1 = popop(); if (!opundef(&o1)) { /* Must copy string value off of operand stack or the next * pushop below will reuse the space! */ o2 = popop(); strncpy (s1, o2.o_val.v_s, 1024); s1[1024] = EOS; o2.o_val.v_s = s1; pushop (&o1); pushop (&o2); binop (OP_CONCAT); } paramset (pp, *f); pp->p_flags |= P_SET; }
/* CL_VOCSTOP -- Stop the VO Client interface. */ void cl_vocstop (void) { register struct pfile *pfp; struct operand o; int n, status; if (VOClient_initialized == 1) { c_xwhen (X_IPC, old_onipc, &old_onipc); pfp = newtask->t_pfp; if ((n = nargs (pfp)) > 1) { cl_error (E_UERR, e_posargs, "vocstop"); return; } else if (n < 1) { voc_closeVOClient (1); } else { pushbparams (pfp->pf_pp); popop(); /* discard fake name. */ opcast (OT_INT); o = popop(); /* get ltask */ voc_closeVOClient (o.o_val.v_i); } VOClient_initialized = 0; } }
/* CL_VOCINIT -- Initialize the VO Client interface. */ void cl_vocinit (void) { register struct pfile *pfp; struct operand o; int n, status; if (VOClient_initialized == 0) { c_xwhen (X_IPC, voc_onipc, &old_onipc); pfp = newtask->t_pfp; if ((n = nargs (pfp)) > 1) { cl_error (E_UERR, e_posargs, "vocinit"); return; } else if (n < 1) { status = voc_initVOClient (envget("vo_runid")); } else { pushbparams (pfp->pf_pp); popop(); /* discard fake name. */ opcast (OT_STRING); o = popop(); /* get ltask */ status = voc_initVOClient (o.o_val.v_s); } if (status) { cl_error (E_UERR, "Can't init VOClient", "vocinit"); } else VOClient_initialized = 1; } }
/* <string operand> . * if argument to which we are assigning is a simple string or filename (or * list, since assigning to a list sets a filename too), set it to o_val.v_s, * else use o_val.v_s as the name of a parameter and use its value as the name * of the variable, that is, do an indirect through o_val.v_s. * compiled when the parser sees a simple identifier, not in an expression. * this avoids quotes around simple strings and filenames. * if the parameter is to be fake, make it type string and do not do the * indirection. */ void o_indirabsset (memel *argp) { char *argname = (char *) argp; char *pk, *t, *p, *f; struct pfile *pfp; struct param *pp; int type, string_len; pfp = newtask->t_pfp; if (pfp->pf_flags & PF_FAKE) { struct operand o; o = popop(); string_len = strlen (o.o_val.v_s); pp = newfakeparam (pfp, argname, 0, OT_STRING, string_len); f = argname; *f = FN_NULL; pushop (&o); } else { breakout (argname, &pk, &t, &p, &f); if (*pk) cl_error (E_UERR, e_simplep, p); pp = ppfind (pfp, t, p, 0, NO); if (pp == NULL) cl_error (E_UERR, e_pnonexist, p); if ((XINT)pp == ERR) cl_error (E_UERR, e_pambig, p, pfp->pf_ltp->lt_lname); } /* lone identifiers are treated as strings, rather than variables, * if the corresponding parameter is a simple string, filename or list. * note that fakeparams are made as strings. */ type = pp->p_type; if (type & (PT_FILNAM|PT_LIST|PT_PSET)) { struct operand o; o = popop(); pushop (&o); } else if ((type & OT_BASIC) != OT_STRING || type & (PT_STRUCT|PT_IMCUR|PT_GCUR|PT_UKEY)) { opindir(); /* replace top op with value of o_val.v_s */ } paramset (pp, *f); if (pp->p_type & PT_PSET) psetreload (pfp, pp); pp->p_flags |= P_CLSET; }
/* . * given the name of a parameter, print it on t_out, the task pipe channel. */ void o_inspect (memel *argp) { char *pname = (char *) argp; char *pk, *t, *p, *f; struct param *pp; struct operand o; breakout (pname, &pk, &t, &p, &f); pp = paramsrch (pk, t, p); if (*f == FN_NULL && (pp->p_type & PT_LIST)) { /* Hitting EOF from a list is ok during an inspect stmt so * avoid using paramget() with its EOF error. * readlist() may set P_LEOF. */ o = readlist (pp); if ((pp->p_flags & P_LEOF) || inrange (pp, &o)) pushop (&o); else query (pp); } else validparamget (pp, *f); o = popop(); if (cldebug && (o.o_type & OT_BASIC) == OT_STRING) eprintf ("Inspect--%s\n", o.o_val.v_s); prop (&o); tprintf ("\n"); }
/* <name of file to be used as stderr> . * redirect everything, including the stderr channel. */ void o_allredir (void) { struct operand o; char *fname, *mode; opcast (OT_STRING); o = popop(); fname = (o.o_val.v_s); if (newtask->t_flags & T_FOREIGN && newtask->t_stdout == stdout && newtask->t_stderr == stderr) { /* If foreign task and i/o has not already been redirected by * the parent, let ZOSCMD open the spool file. */ newtask->ft_out = newtask->ft_err = comdstr (fname); } else { mode = (newtask->t_flags & T_STDOUTB) ? "wb" : "w"; if ((newtask->t_stderr = fopen (fname, mode)) == NULL) cl_error (E_UERR, e_wopen, fname); newtask->t_stdout = newtask->t_stderr; newtask->t_flags |= (T_MYOUT|T_MYERR); } }
/* <new value for argument at command position *argp> . */ void o_posargset (memel *argp) { int pos = (int) *argp; struct pfile *pfp; struct param *pp; struct operand o; int string_len=0; pfp = newtask->t_pfp; if (pos < 0) { /* Lone comma in arg list, merely bump nargs counter */ pfp->pf_n++; return; } if (pfp->pf_flags & PF_FAKE) { o = popop(); if ((o.o_type & OT_BASIC) == OT_STRING) string_len = strlen (o.o_val.v_s); pp = newfakeparam (pfp, (char *) NULL, pos, o.o_type, string_len); pushop (&o); } else { pp = paramfind (pfp, (char *) NULL, pos, NO); if (pp == NULL) cl_error (E_UERR, e_posargs, newtask->t_ltp->lt_lname); } paramset (pp, FN_NULL); pfp->pf_n++; pp->p_flags |= P_CLSET; }
/* <name of file to be used as stdout> . */ void o_redir (void) { struct operand o; char *fname, *mode; opcast (OT_STRING); o = popop(); fname = (o.o_val.v_s); if (newtask->t_flags & T_FOREIGN && newtask->t_stdout == stdout) { /* If foreign task let ZOSCMD open the spool file. */ newtask->ft_out = comdstr (fname); } else if (strcmp (fname, IPCOUT) == 0) { /* Redirect the task stdout via IPC to a subprocess. */ newtask->t_stdout = newtask->t_out; newtask->t_flags |= T_IPCIO; } else { mode = (newtask->t_flags & T_STDOUTB) ? "wb" : "w"; if ((newtask->t_stdout = fopen (fname, mode)) == NULL) cl_error (E_UERR, e_wopen, fname); newtask->t_flags |= T_MYOUT; } }
/* <paramn> ... <param1> <source> <n> . * Do the fscan function. First op on stack is number of string ops to * follow. Next one is the name of the source parameter, rest are names of * destination params. */ void o_dofscan (void) { struct operand o; o = popop(); cl_scan (o.o_val.v_i - 1, ""); }
void o_dofscanf (void) { struct operand o, o_sv[64]; char format[SZ_LINE]; char pname[SZ_FNAME]; int nargs, i; /* Get number of arguments. */ o = popop(); nargs = o.o_val.v_i; /* Get scan format and input parameter name. The arguments on the * stack are pushed in the order input param name, format string, * and then the output arguments. */ /* Get output arguments. */ for (i=0; i < nargs-2; i++) o_sv[i] = popop(); /* Get format string. */ o = popop(); if ((o.o_type & OT_BASIC) != OT_STRING) cl_error (E_UERR, "fscanf: bad format string\n"); strcpy (format, o.o_val.v_s); /* Get parameter name. */ o = popop(); if ((o.o_type & OT_BASIC) != OT_STRING) cl_error (E_UERR, "fscanf: bad input parameter specification\n"); strcpy (pname, o.o_val.v_s); /* Restore the output argument operands. */ for (--i; i >= 0; i--) pushop (&o_sv[i]); /* Restore the input parameter name operand. */ o.o_type = OT_STRING; o.o_val.v_s = pname; pushop (&o); /* Do the scan. */ cl_scanf (format, nargs-2, ""); }
/* <value to be printed> . * used to print an operand on the stack. not to be confused with doprint. */ void o_immed (void) { struct operand o; o = popop(); prop (&o); tprintf ("\n"); }
/* <truth value> . * branch if false (or INDEF). */ void o_biff (memel *argp) { extern XINT pc; struct operand o; opcast (OT_BOOL); o = popop(); if (!o.o_val.v_i || opindef (&o)) pc += (int)*argp; }
/* <value to be divided into named parameter> . */ void o_divassign (memel *argp) { char *pname = (char *) argp; char *pk, *t, *p, *f; struct param *pp; struct operand o1, o2; breakout (pname, &pk, &t, &p, &f); pp = paramsrch (pk, t, p); validparamget (pp, *f); /* get param value on stack */ o1 = popop(); /* swap operands */ o2 = popop(); pushop (&o1); pushop (&o2); binop (OP_DIV); /* perform the division */ paramset (pp, *f); pp->p_flags |= P_SET; }
/* <increment to be added to named parameter> . */ void o_addassign (memel *argp) { /* order of operands will be incorrect. * strictly speaking, only strings are not commutative but we need * to pop both operands anyway to check. */ char *pname = (char *) argp; char *pk, *t, *p, *f; struct param *pp; struct operand o1, o2; breakout (pname, &pk, &t, &p, &f); pp = paramsrch (pk, t, p); validparamget (pp, *f); o1 = popop(); o2 = popop(); if ((o2.o_type & OT_BASIC) == OT_STRING) { /* copy o2 onto dictionary to avoid overwriting it on stack * when o1 is pushed. we can get by with not worrying about o1 * as long as whatever code copies the string works when the * strings overlap. */ XINT oldtopd = topd; char *s2 = memneed (btoi (strlen (o2.o_val.v_s) + 1)); strcpy (s2, o2.o_val.v_s); o2.o_val.v_s = s2; pushop (&o1); pushop (&o2); topd = oldtopd; /* discard temp string area */ } else { pushop (&o1); pushop (&o2); } binop (OP_ADD); paramset (pp, *f); pp->p_flags |= P_SET; }
/* [<op1> <op2> ... <opn>] <nops> . <result> * intrinsic functions, like sin, cos, mod, etc. * argp is the name of the function to run and the top operand (we guarantee * at least one) is the number of remaining operands to be used. * all the defines are in operand.h. the function names and running them is * done by intrfunc() in gram.c. */ void o_intrinsic (memel *argp) { char *funcname = (char *) argp; struct operand o; int nargs; o = popop(); nargs = o.o_val.v_i; intrfunc (funcname, nargs); }
/* <string operand> . * if argument to which we are assigning is a simple string or filename (or * list, since assigning to a list sets a filename too), set it to o_val.v_s, * else use o_val.v_s as the name of a parameter and use its value as the name * of the variable, that is, do an indirect through o_val.v_s. * compiled when the parser sees a simple identifier, not in an expression. * this avoids quotes around simple strings and filenames. */ void o_indirposset (memel *argp) { int pos = (int) *argp; struct pfile *pfp; struct param *pp; int type, string_len; pfp = newtask->t_pfp; if (pfp->pf_flags & PF_FAKE) { struct operand o; o = popop(); string_len = strlen (o.o_val.v_s); pp = newfakeparam (pfp, (char *) NULL, pos, OT_STRING, string_len); pushop (&o); } else { pp = paramfind (pfp, (char *) NULL, pos, NO); if (pp == NULL) cl_error (E_UERR, e_posargs, newtask->t_ltp->lt_lname); } /* lone identifiers are treated as strings, rather than variables, * if the corresponding parameter is a simple string, filename or list. * note that fakeparams are made as strings. */ type = pp->p_type; if (type & (PT_FILNAM|PT_LIST|PT_PSET)) { struct operand o; o = popop(); pushop (&o); } else if ((type & OT_BASIC) != OT_STRING || type & (PT_STRUCT|PT_IMCUR|PT_GCUR|PT_UKEY)) { opindir(); /* replace top op with value of o_val.v_s */ } paramset (pp, FN_NULL); pfp->pf_n++; pp->p_flags |= P_CLSET; }
/* ** VALOF -- compute value of expression ** ** This is the real expression processor. It handles sequencing ** and precedence. ** ** Parameters: ** terminator -- the symbol which should terminate ** the expression. ** ** Returns: ** The value of the expression. ** ** Side Effects: ** Gobbles input. ** ** Requires: ** exprfind -- to read operands. ** opfind -- to read operators. ** exp_op -- to perform operations. ** ** Called By: ** expr ** ** Diagnostics: ** Extra Parenthesis found: assumed typo ** An unmatched right parenthesis was read. ** It was thrown away. ** Insufficient parenthesis found: assumed zero. ** An unmatched left parenthesis was left ** in the operator stack at the end of the ** expression. The value zero was taken ** for the expression. ** ** Syserrs: ** none */ int valof(int terminator) { register int number; register int operator; pushop(SEPERATOR); /* initialize the stack */ for(;;) { number = exprfind(); if (ExprError) return(0); operator = opfind(); if (ExprError) return(0); if (operator == RIGHTP || operator == END) break; /* Do all previous operations with a higher precedence */ while (ExprPrec[operator] <= ExprPrec[ExprOptr[-1]]) number = exp_op(popop(), popnum(), number); pushop(operator); pushnum(number); } if (operator != terminator) /* ExprError in operators */ if (operator == RIGHTP) printf("Extra parenthesis found: assumed typo.\n"); else { ExprError = TRUE; printf("Insufficient parenthesis found: Assumed zero.\n"); return(0); } /* Empty stack for this call of valof */ while ((operator = popop()) != SEPERATOR) number = exp_op(operator, popnum(), number); return(number); }
/* Push an index value onto the control stack for later use * when the parameter is accessed. */ void o_pushindex (int *mode) { struct operand op; if (cldebug) printf ("PUSHINDEX: mode=%d loopset=%d\n", *mode, imloopset); if (*mode == 0) { /* Normal array index reference. */ opcast(OT_INT); op = popop(); push (op.o_val.v_i); } else if (*mode == -1 || imloopset) { /* Array reference in implicit loop. */ push (oarr_curr[i_oarr]); i_oarr++; if (i_oarr >= n_oarr) i_oarr = 0; } else { /* This is the first array reference in an implicit loop. * It must initialize the loop parameters. The argument * is an offset to the initialization info. */ int stk; stk = pc + *mode; n_oarr = stack[stk++]; for (i_oarr=0; i_oarr<n_oarr; i_oarr++) { oarr_beg[i_oarr] = stack[stk++]; oarr_curr[i_oarr] = oarr_beg[i_oarr]; oarr_end[i_oarr] = stack[stk++]; } /* Set flag so that we don't do this again. */ imloopset++; /* And we still have to push a value. */ push (oarr_curr[0]); i_oarr = 1; if (i_oarr >= n_oarr) i_oarr = 0; } /* Increment counter of number of indexes pushed. */ n_indexes++; }
/* GSREDIR -- Graphics stream redirection. * <filename> . */ void o_gsredir (memel *argp) { register char *ip; register FILE *fp; char *streams = (char *)argp; struct operand o; char *fname; int count; /* Get the filename. */ opcast (OT_STRING); o = popop(); fname = o.o_val.v_s; /* Scan the redir token to determine the file access mode, e.g., if * ">G", create a new file, and if ">>G", append to a file. */ for (count=0, ip=streams; *ip; ip++) if (*ip == '>') count++; if ((fp = fopen (fname, count > 1 ? "ab" : "wb")) == NULL) cl_error (E_UERR, e_wopen, fname); /* The first string operand on the stack is some combination of the * characters GIP, listing the streams (stdgraph, stdimage, stdplot) * to be redirected to the named file. The lexical analyzer guarantees * that we will not be called unless the string consists of some * combination of the characters >GIP, hence error checking for other * char, no chars, etc., is not needed. */ for (ip=streams; *ip; ip++) if (*ip == 'G') { newtask->t_flags |= T_MYSTDGRAPH; newtask->t_stdgraph = fp; } else if (*ip == 'I') { newtask->t_flags |= T_MYSTDIMAGE; newtask->t_stdimage = fp; } else if (*ip == 'P') { newtask->t_flags |= T_MYSTDPLOT; newtask->t_stdplot = fp; } }
/* <new value for named argument> . * Assign the top operand to the named parameter. Also, make the type of the * fake parameter the same as the type of the operand. */ void o_absargset (memel *argp) { char *argname = (char *) argp; char *pk, *t, *p, *f; struct pfile *pfp; struct param *pp; pfp = newtask->t_pfp; if (pfp->pf_flags & PF_FAKE) { /* use full argname and always assign to value field. */ struct operand o; int string_len=0; o = popop(); if ((o.o_type & OT_BASIC) == OT_STRING) string_len = strlen (o.o_val.v_s); pp = newfakeparam (pfp, argname, 0, o.o_type, string_len); pushop (&o); f = argname; *f = FN_NULL; } else { breakout (argname, &pk, &t, &p, &f); if (*pk) cl_error (E_UERR, e_simplep, p); pp = ppfind (pfp, t, p, 0, NO); if (pp == NULL) cl_error (E_UERR, e_pnonexist, p); if ((XINT)pp == ERR) cl_error (E_UERR, e_pambig, p, pfp->pf_ltp->lt_lname); } paramset (pp, *f); if (pp->p_type & PT_PSET) psetreload (pfp, pp); pp->p_flags |= P_CLSET; }
int main() { struct node*sv=NULL; struct node2*sop=NULL; int n,n1,n2,result,i; char thisop; //scanf("%d",&n); char a[100]; scanf("%s",a); i=0; for(;a[i]!='\0';i++) { if(isdigit(a[i])) { sv=pushval(sv,a[i]); } else if(a[i]=='+') { if(sop!=NULL) { n1=popval(&sv); n2=popval(&sv); result=n2+n1; //editing required sv=pushval(sv,result); } else { sop=pushop(sop,a[i]); } } } while(sop!=NULL) { thisop=popop(&sop); n1=popval(&sv); n2=popval(&sv); result=n2+n1;//editing required sv=pushval(sv,result); } result=popval(&sv); printf("%d",result); }
/* <name of file to be used as stdin> . */ void o_redirin (void) { struct operand o; char *fname, *mode; opcast (OT_STRING); o = popop(); fname = (o.o_val.v_s); if (newtask->t_flags & T_FOREIGN && newtask->t_stdin == stdin) { /* If foreign task let ZOSCMD open the command file. */ newtask->ft_in = comdstr (fname); } else { mode = (newtask->t_flags & T_STDINB) ? "rb" : "r"; if ((newtask->t_stdin = fopen (fname, mode)) == NULL) cl_error (E_UERR, e_ropen, fname); newtask->t_flags |= T_MYIN; } }
/* <name of file to be appended> . */ void o_append (void) { struct operand o; char *fname, *mode; opcast (OT_STRING); o = popop(); fname = (o.o_val.v_s); if (newtask->t_flags & T_FOREIGN && newtask->t_stdout == stdout) { /* If foreign task let ZOSCMD open the spool file. */ newtask->ft_out = comdstr (fname); newtask->t_flags |= T_APPEND; } else { mode = (newtask->t_flags & T_STDOUTB) ? "ab" : "a"; if ((newtask->t_stdout = fopen (fname, mode)) == NULL) cl_error (E_UERR, e_appopen, fname); newtask->t_flags |= T_MYOUT; } }
/* QUERY -- Query the user for the value of a parameter. Prompt with the * current value if any. Keep this up until we can push a reasonable value. * Also, store the new value in the parameter (except for list params, where, * since the values are not kept, all that may change is P_LEOF if seen). * Give prompt, or name if none, current value and range if int, real or * filename. Accept CR to leave value unchanged, else take the string * entered to be the new value. Repeat until parameter value is in range. * We mean to talk straight to the user here; thus, interact with the real * stdio, not the effective t_stdio, so that redirections do not get in * the way. In batch mode, a forced query is handled by writing a * message on the terminal of the parent cl (the original stderr), and * leaving some info describing the query in a file in uparm (if there is * no uparm, we abort). We then loop, waiting for the user to run "service" * in the interactive cl to service the query, leaving the answer in a * another file which we read and then delete. If we wait a long time and * get no response, we timeout. */ void query (struct param *pp) { static char *oormsg = "ERROR: Parameter value is out of range; try again"; register char *ip; char buf[SZ_PROMPTBUF+1]; struct operand o; int bastype, batch, arrflag, offset=0, n_ele, max_ele, fd; char *index(), *nlp, *nextstr(); char *bkg_query(), *query_status; char *abuf; bastype = pp->p_type & OT_BASIC; batch = firstask->t_flags & T_BATCH; arrflag = pp->p_type & PT_ARRAY; if (arrflag) { /* We may access the array many */ offset = getoffset (pp); /* times, so save the offset and */ /* push it when necessary. */ poffset (offset); max_ele = size_array (pp) - offset; } else max_ele = 1; forever { if (batch) { /* Query from a background job. */ query_status = bkg_query (buf, SZ_PROMPTBUF, pp); } else if (pp->p_type & (PT_GCUR|PT_IMCUR)) { /* Read a graphics cursor. */ char source[33]; int cursor; /* Determine the source of graphics cursor input, chosen from * either the graphics or image cursor or the terminal. */ if (pp->p_type & PT_GCUR) { if (c_envfind ("stdgcur", source, 32) <= 0) strcpy (source, "stdgraph"); } else { if (c_envfind ("stdimcur", source, 32) <= 0) strcpy (source, "stdimage"); } if (strcmp (source, "stdgraph") == 0) cursor = STDGRAPH; else if (strcmp (source, "stdimage") == 0) cursor = STDIMAGE; else goto text_query; /* get value from terminal */ /* Read a physical graphics cursor. */ pp->p_flags &= ~P_LEOF; if (cursor == STDIMAGE) { /* The following is a kludge used to temporarily implement * the logical image cursor read. In the future this will * be eliminated, and the c_rcursor call below (cursor * mode) will be used for stdimage as well as for stdgraph. * The present code (IMDRCUR) goes directly to the display * server to get the cursor value, bypassing cursor mode * and the (currently nonexistent) stdimage kernel. */ char str[SZ_LINE+1], keystr[10]; int wcs, key; float x, y; if (c_imdrcur ("stdimage", &x,&y,&wcs,&key,str,SZ_LINE, 1, 1) == EOF) { query_status = NULL; } else { if (isprint(key) && !isspace(key)) sprintf (keystr, "%c", key); else sprintf (keystr, "\\%03o", key); sprintf (buf, "%.3f %.3f %d %s %s\n", x, y, wcs, keystr, str); query_status = (char *) ((XINT) strlen(buf)); } } else if (c_rcursor (cursor, buf, SZ_PROMPTBUF) == EOF) { query_status = NULL; } else query_status = (char *) ((XINT) strlen(buf)); } else if (pp->p_type & PT_UKEY) { /* Read a user keystroke command from the terminal. */ pp->p_flags &= ~P_LEOF; if (c_rdukey (buf, SZ_PROMPTBUF) == EOF) query_status = NULL; else query_status = (char *) ((XINT) strlen(buf)); } else { text_query: fd = spf_open (buf, SZ_PROMPTBUF); pquery (pp, fdopen(fd,"a")); spf_close (fd); c_stgputline ((XINT)STDOUT, buf); if (c_stggetline ((XINT)STDIN, buf, SZ_PROMPTBUF) > 0) query_status = (char *) ((XINT) strlen(buf)); else query_status = NULL; } ip = buf; /* Set o to the current value of the parameter. Beware that some * of the logical branches which follow assume that struct o has * been initialized to the current value of the parameter. */ if (pp->p_type & PT_LIST) setopundef (&o); else if (arrflag) { paramget(pp, FN_VALUE); poffset (offset); o = popop(); } else o = pp->p_valo; /* Handle eof, a null-length line (lone carriage return), * and line with more than SZ_LINE chars. Ignore leading whitespace * if basic type is not string. */ if (query_status == NULL) { /* Typing eof will use current value (as will a lone * newline) but if param is a list, it is a meaningful * answer. */ if (pp->p_type & PT_LIST) { closelist (pp); /* close an existing file */ pp->p_flags |= P_LEOF; o = makeop (eofstr, OT_STRING); break; } goto testval; } /* Ignore leading whitespace if it is not significant for this * datatype. Do this before testing for empty line, so that a * return such as " \n" is equivalent to "\n". I.e., do not * penalize the user if they type the space bar by accident before * typing return to accept the default value. */ if (bastype != OT_STRING || (pp->p_type & (PT_FILNAM|PT_PSET))) while (*ip == ' ' || *ip == '\t') ip++; if (*ip == '\n') { /* Blank lines usually just accept the current value * but if the param is a string and is undefined, * it sets the string to a (defined) nullstring. */ *ip = '\0'; if (bastype == OT_STRING && opundef (&o)) o = makeop (ip, bastype); else goto testval; } if ((nlp = index (ip, '\n')) != NULL) *nlp = '\0'; /* cancel the newline */ else goto testval; /* Finally, we have handled the pathological cases... */ if ((pp->p_type & PT_LIST) && (!strcmp (ip,eofstr) || !strcmp (ip,"eof"))) { closelist (pp); pp->p_flags |= P_LEOF; o = makeop (eofstr, OT_STRING); break; } else { if (arrflag) { /* In querying for arrays we may set more than one * element of the array in a single query. However * we must set the first element. So we will pretend * to be a scalar until that first element is set * and then enter a loop where we may set other * elements. */ abuf = ip; ip = nextstr(&abuf, stdin); if (ip == NULL || ip == (char *) ERR || ip == undefval) goto testval; } o = makeop (ip, bastype); } testval: /* If parameter value is in range, we are done. If it is out of * range and we are a batch job or an interactive terminal job, * print an error message and request that the user enter a legal * value. If the CL is being run taking input from a file, abort, * else we will go into a loop reading illegal values from the * input file and printing out lots of error messages. */ if (inrange (pp, &o)) break; else if (batch) eprintf ("\n[%d] %s", bkgno, oormsg); else if (isatty (fileno (stdin))) eprintf ("%s\n", oormsg); else cl_error (E_UERR, oormsg); } if (!(pp->p_type & PT_LIST)) { /* update param with new value. */ if (cldebug) { eprintf ("changing `%s.p_val' to ", pp->p_name); fprop (stderr, &o); eprintf ("\n"); } pushop (&o); paramset (pp, FN_VALUE); pp->p_flags |= P_QUERY; } pushop (&o); if (arrflag && query_status != NULL && *ip != '\0') { /* If we have an array assign values until something * is used up or until we hit any error. */ n_ele = 1; forever { if (n_ele >= max_ele) /* End of array. */ break; ip = nextstr(&abuf, stdin); if (ip == NULL) /* End of query line. */ break; if (ip == (char *) ERR) { /* Error on query line. */ eprintf("Error loading array value.\n"); break; } if (ip != undefval) { o = makeop (ip, bastype); if ( ! inrange (pp, &o) ) { /* Not in range. */ eprintf("Array value outside range.\n"); break; } offset++; /* Next element in array. */ poffset (offset); pushop (&o); paramset (pp, FN_VALUE); } else offset++; n_ele++; } }
/* Calculate the effective mode for the given parameter, considering * its own mode and the modes for the current task and the cl. * Inhibit query mode if set on the command line or hidden but * enable it if the param is not in range. The range test cannot be done * here for list params because we'd have to read the list to do it. * Return a bit-mapped code (built up of M_XXX bits) of the result. * Since learn mode is not defined at the parameter level, pp == NULL * is used to indicate we are just interested in M_LEARN info. * Local variables cannot be prompted for so it is an error if their * values are undefined. */ int effmode (struct param *pp) { static char *localerr = "Attempt to access undefined local variable `%s'.\n"; register int mode, modebits; struct operand o; int clmode, ltmode, pkmode, offset; int interactive; /* Check if param is a local variable. If it is undefined * this is an ERR, if defined just return mode 0 to defeat * querying. */ if (pp != NULL) { if (pp->p_mode & M_LOCAL) { if (opundef (&(pp->p_valo))) cl_error (E_UERR, localerr, pp->p_name); return (0); } } /* Determine whether or not the current task was called interactively. * Menu mode is only permitted for tasks called interactively. */ interactive = 0; if (prevtask) interactive = (prevtask->t_flags & (T_INTERACTIVE|T_BATCH)); if (interactive) modebits = (M_QUERY|M_HIDDEN|M_MENU); else modebits = (M_QUERY|M_HIDDEN); clmode = scanmode (firstask->t_modep->p_val.v_s); ltmode = scanmode (currentask->t_modep->p_val.v_s); pkmode = -1; mode = 0; if (pp != NULL) { /* In determining the effective mode we go up the hierarchy of * parameter, task, package, cl. The mode is taken from the first * of these which is not automatic. */ if ( (mode = (pp->p_mode & modebits)) ) ; else if ( (mode = (ltmode & modebits)) ) ; else { /* Check the mode of the package to which the ltask belongs, * which need not be the "current" package. */ struct pfile *pfp; if ( (pfp = currentask->t_ltp->lt_pkp->pk_pfp) ) { struct param *ppx; ppx = paramfind (pfp, "mode", 0, YES); if ((ppx != NULL) && (ppx != (struct param *)ERR)) pkmode = scanmode (ppx->p_val.v_s); } if (pkmode > 0 && (mode = (pkmode & modebits))) ; else if ( (mode = (clmode & modebits)) ) ; else mode = M_AUTO; } /* Defeat query mode if param set on command line or it's a * hidden param or if menu mode is in effect. */ if ((pp->p_flags & P_CLSET) || (pp->p_mode & M_HIDDEN) || (mode & M_MENU)) mode &= ~M_QUERY; /* Query unconditionally if param is out of range or undefined. */ if (!(mode & M_QUERY) && !(pp->p_type & PT_LIST)) { /* To check whether an array element is in range we * must get the appropriate element of the array. However * the stack must be reset so that the element can be accessed * again by the calling routine. */ if (pp->p_type & PT_ARRAY) { offset = getoffset(pp); poffset (offset); paramget(pp, FN_VALUE); poffset (offset); o = popop(); if (!inrange (pp, &o)) mode |= M_QUERY; } else { /* Use temporary scratch variable for range checking in * this case; sometimes the value of an enumerated * parameter would get trashed in the process. There is * probably some deeper, darker bug lurking down there, * but haven't found it yet, so this will suffice for now. */ o = pp->p_valo; if (!inrange (pp, &o)) mode |= M_QUERY; } } } /* Enable learn mode only for tasks called interactively - don't bother * to learn parameters if the task is called from a script or in batch * mode. */ if (interactive) mode |= (clmode & M_LEARN) | (ltmode & M_LEARN); return (mode); }
/* GQUERY -- Determine if the value of a parameter given by the user is OK. * Also, store the new value in the parameter; in the case of a list * structured parameter, the new value is the name of a new list file. * This routine is called by EPARAM to verify that the new parameter value * is inrange and set the new value if so. */ char * gquery ( struct param *pp, char *string ) { register char *ip; char buf[SZ_LINE]; char *query_status, *nlp, *errmsg; int arrflag, offset, bastype, batch; struct operand o; char *strcpy(), *index(); bastype = pp->p_type & OT_BASIC; batch = firstask->t_flags & T_BATCH; arrflag = pp->p_type & PT_ARRAY; if (arrflag) offset = getoffset(pp); if (batch) { errmsg = e1; return (errmsg); } else query_status = strcpy (buf, string); ip = buf; /* Set o to the current value of the parameter. Beware that some * of the logical branches which follow assume that struct o has * been initialized to the current value of the parameter. */ if (pp->p_type & PT_LIST) { setopundef (&o); } else if (arrflag) { poffset (offset); paramget (pp, FN_VALUE); o = popop (); } else o = pp->p_valo; /* Handle eof, a null-length line (lone carriage return), * and line with more than SZ_LINE chars. Ignore leading whitespace * if basic type is not string. */ if (query_status == NULL) goto testval; /* Ignore leading whitespace if it is not significant for this * datatype. Do this before testing for empty line, so that a * return such as " \n" is equivalent to "\n". I.e., do not * penalize the user if they type the space bar by accident before * typing return to accept the default value. */ if (bastype != OT_STRING || (pp->p_type & PT_LIST)) while (*ip == ' ' || *ip == '\t') ip++; if (*ip == '\n') { /* Blank lines usually just accept the current value * but if the param in a string and is undefined, * it sets the string to a (defined) nullstring. */ if (bastype == OT_STRING && opundef (&o)) { *ip = '\0'; o = makeop (ip, bastype); } else goto testval; } /* Cancel the newline. */ if ((nlp = index (ip, '\n')) != NULL) *nlp = '\0'; /* Finally, we have handled the pathological cases. */ if (pp->p_type & PT_LIST) o = makeop (string, OT_STRING); else o = makeop (ip, bastype); testval: if (*string == '@') errmsg = "OK"; else if (pp->p_type & PT_LIST) errmsg = "OK"; else if (inrange (pp, &o)) errmsg = "OK"; else { errmsg = e2; return (errmsg); } if (cldebug) { eprintf ("changing `%s.p_val' to ", pp->p_name); fprop (stderr, &o); eprintf ("\n"); } /* Update param with new value. */ pushop (&o); if (arrflag) poffset (offset); paramset (pp, FN_VALUE); pp->p_flags |= P_SET; return ("OK"); }
/* Doswitch finds the appropriate location to jump to in the * jump table and goes there. */ void o_doswitch (int *jmpdelta) { int pdft, icase, jmptable; int value=0; struct operand o; memel delta; /* Remember to subtract SZ_CE 'cuz PC has already been incremented. */ jmptable = *jmpdelta + pc - SZ_CE; o = popop(); if (o.o_type == OT_INT) value = o.o_val.v_i; else if (o.o_type == OT_STRING) { if (*o.o_val.v_s != '\0' && *(o.o_val.v_s+1) == '\0') value = (int) *o.o_val.v_s; else cl_error(E_UERR, "Illegal switch value."); } else cl_error (E_UERR, "Illegal switch value."); pdft = stack[jmptable]; if (cldebug) eprintf ("doswitch: pdft=%d\n", pdft); /* Loop over cases. */ for (icase= jmptable + 1; stack[icase] != 0; icase++) { int nval, ival, pcase; memel *val; pcase = stack[icase] + pc - SZ_CE; nval = coderef(pcase)->c_length - (SZ_CE - 1); currentline = coderef(pcase)->c_scriptln; /* Loop over all values for a particular case. */ val = & (coderef(pcase)->c_args); for (ival=0; ival<nval; ival++, val++) { if (*val == value) { /* Remember to skip over the CASE operand itself. */ delta = pcase + (nval+(SZ_CE-1)) - (pc-SZ_CE) - SZ_CE; o_dogoto (&delta); return; } } } /* Default? */ if (pdft != 0) { pdft = pdft + pc - SZ_CE; /* Skipping over DEFAULT block takes 2 ints. */ delta = (pdft+(SZ_CE-1)) - (pc-SZ_CE) - SZ_CE; o_dogoto (&delta); return; } /* If there is no default we just drop through to the * next statement which is a branch beyond the SWITCH. */ }