Ejemplo n.º 1
0
epicsShareFunc int
epicsParseDouble(const char *str, double *to, char **units)
{
    int c;
    char *endp;
    double value;

    while ((c = *str) && isspace(c))
        ++str;

    errno = 0;
    value = epicsStrtod(str, &endp);

    if (endp == str)
        return S_stdlib_noConversion;
    if (errno == ERANGE)
        return (value == 0) ? S_stdlib_underflow : S_stdlib_overflow;

    while ((c = *endp) && isspace(c))
        ++endp;
    if (c && !units)
        return S_stdlib_extraneous;

    *to = value;
    if (units)
        *units = endp;
    return 0;
}
Ejemplo n.º 2
0
/*
 * Internal commands
 */
static void varHandler(const iocshVarDef *v, const char *setString)
{
    switch(v->type) {
    default:
        fprintf(epicsGetStderr(), "Can't handle variable %s of type %d.\n",
            v->name, v->type);
        return;
    case iocshArgInt: break;
    case iocshArgDouble: break;
    }
    if(setString == NULL) {
        switch(v->type) {
        default: break;
        case iocshArgInt:
            fprintf(epicsGetStdout(), "%s = %d\n", v->name, *(int *)v->pval);
            break;
        case iocshArgDouble:
            fprintf(epicsGetStdout(), "%s = %g\n", v->name, *(double *)v->pval);
            break;
        }
    }
    else {
        switch(v->type) {
        default: break;
        case iocshArgInt:
          {
            char *endp;
            long ltmp = strtol(setString, &endp, 0);
            if((*setString != '\0') && (*endp == '\0'))
                *(int *)v->pval = ltmp;
            else
                fprintf(epicsGetStderr(),
                    "Invalid integer value. Var %s not changed.\n", v->name);
            break;
          }
        case iocshArgDouble:
          {
            char *endp;
            double dtmp = epicsStrtod(setString, &endp);
            if((*setString != '\0') && (*endp == '\0'))
                *(double *)v->pval = dtmp;
            else
                fprintf(epicsGetStderr(),
                    "Invalid double value. Var %s not changed.\n", v->name);
            break;
          }
        }
    }
}
Ejemplo n.º 3
0
int main (int argc, char *argv[])
{
    int i;
    int result;                 /* CA result */
    OutputT format = plain;     /* User specified format */
    RequestT request = get;     /* User specified request type */
    int isArray = 0;            /* Flag for array operation */
    int enumAsString = 0;       /* Force ENUM values to be strings */

    int count = 1;
    int opt;                    /* getopt() current option */
    chtype dbrType = DBR_STRING;
    char *pend;
    EpicsStr *sbuf;
    double *dbuf;
    char *cbuf = 0;
    char *ebuf = 0;
    void *pbuf;
    int len = 0;
    int waitStatus;
    struct dbr_gr_enum bufGrEnum;

    int nPvs;                   /* Number of PVs */
    pv* pvs;                /* Array of PV structures */

    LINE_BUFFER(stdout);        /* Configure stdout buffering */
    putenv("POSIXLY_CORRECT="); /* Behave correct on GNU getopt systems */

    while ((opt = getopt(argc, argv, ":cnlhatsS#:w:p:F:")) != -1) {
        switch (opt) {
        case 'h':               /* Print usage */
            usage();
            return 0;
        case 'n':               /* Force interpret ENUM as index number */
            enumAsNr = 1;
            enumAsString = 0;
            break;
        case 's':               /* Force interpret ENUM as menu string */
            enumAsString = 1;
            enumAsNr = 0;
            break;
        case 'S':               /* Treat char array as (long) string */
            charArrAsStr = 1;
            isArray = 0;
            break;
        case 't':               /* Select terse output format */
            format = terse;
            break;
        case 'l':               /* Select long output format */
            format = all;
            break;
        case 'a':               /* Select array mode */
            isArray = 1;
            charArrAsStr = 0;
            break;
        case 'c':               /* Select put_callback mode */
            request = callback;
            break;
        case 'w':               /* Set CA timeout value */
            if(epicsScanDouble(optarg, &caTimeout) != 1)
            {
                fprintf(stderr, "'%s' is not a valid timeout value "
                        "- ignored. ('caput -h' for help.)\n", optarg);
                caTimeout = DEFAULT_TIMEOUT;
            }
            break;
        case '#':               /* Array count */
            if (sscanf(optarg,"%d", &count) != 1)
            {
                fprintf(stderr, "'%s' is not a valid array element count "
                        "- ignored. ('caput -h' for help.)\n", optarg);
                count = 0;
            }
            break;
        case 'p':               /* CA priority */
            if (sscanf(optarg,"%u", &caPriority) != 1)
            {
                fprintf(stderr, "'%s' is not a valid CA priority "
                        "- ignored. ('caget -h' for help.)\n", optarg);
                caPriority = DEFAULT_CA_PRIORITY;
            }
            if (caPriority > CA_PRIORITY_MAX) caPriority = CA_PRIORITY_MAX;
            break;
        case 'F':               /* Store this for output and tool_lib formatting */
            fieldSeparator = (char) *optarg;
            break;
        case '?':
            fprintf(stderr,
                    "Unrecognized option: '-%c'. ('caput -h' for help.)\n",
                    optopt);
            return 1;
        case ':':
            fprintf(stderr,
                    "Option '-%c' requires an argument. ('caput -h' for help.)\n",
                    optopt);
            return 1;
        default :
            usage();
            return 1;
        }
    }

    nPvs = argc - optind;       /* Remaining arg list are PV names and values */

    if (nPvs < 1) {
        fprintf(stderr, "No pv name specified. ('caput -h' for help.)\n");
        return 1;
    }
    if (nPvs == 1) {
        fprintf(stderr, "No value specified. ('caput -h' for help.)\n");
        return 1;
    }

    nPvs = 1;                   /* One PV - the rest is value(s) */

    epId = epicsEventCreate(epicsEventEmpty);  /* Create empty EPICS event (semaphore) */

                                /* Start up Channel Access */

    result = ca_context_create(ca_enable_preemptive_callback);
    if (result != ECA_NORMAL) {
        fprintf(stderr, "CA error %s occurred while trying "
                "to start channel access.\n", ca_message(result));
        return 1;
    }
                                /* Allocate PV structure array */

    pvs = calloc (nPvs, sizeof(pv));
    if (!pvs) {
        fprintf(stderr, "Memory allocation for channel structure failed.\n");
        return 1;
    }
                                /* Connect channels */

    pvs[0].name = argv[optind] ;   /* Copy PV name from command line */

    result = connect_pvs(pvs, nPvs); /* If the connection fails, we're done */
    if (result) {
        ca_context_destroy();
        return result;
    }

                                /* Get values from command line */
    optind++;

    if (isArray) {
        optind++;               /* In case of array skip first value (nr
                                 * of elements) - actual number of values is used */
        count = argc - optind;

    } else {                    /* Concatenate the remaining line to one string
                                 * (sucks but is compatible to the former version) */
        for (i = optind; i < argc; i++) {
            len += strlen(argv[i]);
            len++;
        }
        cbuf = calloc(len, sizeof(char));
        if (!cbuf) {
            fprintf(stderr, "Memory allocation failed.\n");
            return 1;
        }
        strcpy(cbuf, argv[optind]);

        if (argc > optind+1) {
            for (i = optind + 1; i < argc; i++) {
                strcat(cbuf, " ");
                strcat(cbuf, argv[i]); 
            }
        }

        if ((argc - optind) >= 1)
            count = 1;
        argv[optind] = cbuf;
    }

    sbuf = calloc (count, sizeof(EpicsStr));
    dbuf = calloc (count, sizeof(double));
    if(!sbuf || !dbuf) {
        fprintf(stderr, "Memory allocation failed\n");
        return 1;
    }

                                /*  ENUM? Special treatment */

    if (ca_field_type(pvs[0].chid) == DBR_ENUM) {

                                /* Get the ENUM strings */

        result = ca_array_get (DBR_GR_ENUM, 1, pvs[0].chid, &bufGrEnum);
        result = ca_pend_io(caTimeout);
        if (result == ECA_TIMEOUT) {
            fprintf(stderr, "Read operation timed out: ENUM data was not read.\n");
            return 1;
        }

        if (enumAsNr) {         /* Interpret values as numbers */

            for (i = 0; i < count; ++i) {
                dbuf[i] = epicsStrtod(*(argv+optind+i), &pend);
                if (*(argv+optind+i) == pend) { /* Conversion didn't work */
                    fprintf(stderr, "Enum index value '%s' is not a number.\n",
                            *(argv+optind+i));
                    return 1;
                }
                if (dbuf[i] >= bufGrEnum.no_str) {
                    fprintf(stderr, "Warning: enum index value '%s' may be too large.\n",
                            *(argv+optind+i));
                }
            }
            dbrType = DBR_DOUBLE;

        } else {                /* Interpret values as strings */

            for (i = 0; i < count; ++i) {
                epicsStrnRawFromEscaped(sbuf[i], sizeof(EpicsStr), *(argv+optind+i), sizeof(EpicsStr));
                *( sbuf[i]+sizeof(EpicsStr)-1 ) = '\0';
                dbrType = DBR_STRING;

                                /* Compare to ENUM strings */
                for (len = 0; len < bufGrEnum.no_str; len++)
                    if (!strcmp(sbuf[i], bufGrEnum.strs[len]))
                        break;

                if (len >= bufGrEnum.no_str) {
                                         /* Not a string? Try as number */
                    dbuf[i] = epicsStrtod(sbuf[i], &pend);
                    if (sbuf[i] == pend || enumAsString) {
                        fprintf(stderr, "Enum string value '%s' invalid.\n", sbuf[i]);
                        return 1;
                    }
                    if (dbuf[i] >= bufGrEnum.no_str) {
                        fprintf(stderr, "Warning: enum index value '%s' may be too large.\n", sbuf[i]);
                    }
                    dbrType = DBR_DOUBLE;
                }
            }
        }

    } else {                    /* Not an ENUM */

        if (charArrAsStr) {
            dbrType = DBR_CHAR;
            ebuf = calloc(len, sizeof(char));
            if(!ebuf) {
                fprintf(stderr, "Memory allocation failed\n");
                return 1;
            }
            count = epicsStrnRawFromEscaped(ebuf, len, cbuf, len-1) + 1;
        } else {
            for (i = 0; i < count; ++i) {
                epicsStrnRawFromEscaped(sbuf[i], sizeof(EpicsStr), *(argv+optind+i), sizeof(EpicsStr));
                *( sbuf[i]+sizeof(EpicsStr)-1 ) = '\0';
            }
            dbrType = DBR_STRING;
        }
    }

                                /* Read and print old data */
    if (format != terse) {
        printf("Old : ");
        result = caget(pvs, nPvs, format, 0, 0);
    }

                                /* Write new data */
    if (dbrType == DBR_STRING) pbuf = sbuf;
    else if (dbrType == DBR_CHAR) pbuf = ebuf;
    else pbuf = dbuf;

    if (request == callback) {
        /* Use callback version of put */
        pvs[0].status = ECA_NORMAL;   /* All ok at the moment */
        result = ca_array_put_callback (
            dbrType, count, pvs[0].chid, pbuf, put_event_handler, (void *) pvs);
    } else {
        /* Use standard put with defined timeout */
        result = ca_array_put (dbrType, count, pvs[0].chid, pbuf);
    }
    result = ca_pend_io(caTimeout);
    if (result == ECA_TIMEOUT) {
        fprintf(stderr, "Write operation timed out: Data was not written.\n");
        return 1;
    }
    if (request == callback) {   /* Also wait for callbacks */
        waitStatus = epicsEventWaitWithTimeout( epId, caTimeout );
        if (waitStatus)
            fprintf(stderr, "Write callback operation timed out\n");

        /* retrieve status from callback */
        result = pvs[0].status;
    }

    if (result != ECA_NORMAL) {
        fprintf(stderr, "Error occured writing data.\n");
        return 1;
    }

                                /* Read and print new data */
    if (format != terse)
        printf("New : ");

    result = caget(pvs, nPvs, format, 0, 0);

                                /* Shut down Channel Access */
    ca_context_destroy();

    return result;
}
Ejemplo n.º 4
0
static int
cvtArg (const char *filename, int lineno, char *arg, iocshArgBuf *argBuf,
    const iocshArg *piocshArg)
{
    char *endp;

    switch (piocshArg->type) {
    case iocshArgInt:
        if (arg && *arg) {
            errno = 0;
            argBuf->ival = strtol (arg, &endp, 0);
            if (errno == ERANGE) {
                errno = 0;
                argBuf->ival = strtoul (arg, &endp, 0);
                if (errno == ERANGE) {
                    showError(filename, lineno, "Integer '%s' out of range",
                        arg);
                    return 0;
                }
            }
            if (*endp) {
                showError(filename, lineno, "Illegal integer '%s'", arg);
                return 0;
            }
        }
        else {
            argBuf->ival = 0;
        }
        break;

    case iocshArgDouble:
        if (arg && *arg) {
            argBuf->dval = epicsStrtod (arg, &endp);
            if (*endp) {
                showError(filename, lineno, "Illegal double '%s'", arg);
                return 0;
            }
        }
        else {
            argBuf->dval = 0.0;
        }
        break;

    case iocshArgString:
        argBuf->sval = arg;
        break;

    case iocshArgPersistentString:
        argBuf->sval = (char *) malloc(strlen(arg) + 1);
        if (argBuf->sval == NULL) {
            showError(filename, lineno, "Out of memory");
            return 0;
        }
        strcpy(argBuf->sval, arg);
        break;

    case iocshArgPdbbase:
        /* Argument must be missing or 0 or pdbbase */
        if(!arg || !*arg || (*arg == '0') || (strcmp(arg, "pdbbase") == 0)) {
            if(!iocshPpdbbase || !*iocshPpdbbase) {
                showError(filename, lineno, "pdbbase not present");
                return 0;
            }
            argBuf->vval = *iocshPpdbbase;
            break;
        }
        showError(filename, lineno, "Expecting 'pdbbase' got '%s'", arg);
        return 0;

    default:
        showError(filename, lineno, "Illegal argument type %d",
            piocshArg->type);
        return 0;
    }
    return 1;
}
Ejemplo n.º 5
0
/* sCalcPostfix
 *
 * convert an infix expression to a postfix expression
 */
epicsShareFunc long
	sCalcPostfix(const char *psrc, unsigned char * const ppostfix, short *perror)
{
	ELEMENT stack[80];
	ELEMENT *pstacktop = stack, *ps1;
	const ELEMENT *pel;
	int operand_needed = TRUE;
	int runtime_depth = 0;
	int cond_count = 0;
	unsigned char *pout = ppostfix;
	char *pnext;
	double lit_d;
	int lit_i;
	char c;
	int handled;

	if (psrc == NULL || pout == NULL || perror == NULL) {
		if (perror) *perror = CALC_ERR_NULL_ARG;
		if (pout) *pout = END_EXPRESSION;
		return -1;
	}
	if (*psrc == '\0') {
		if (pout) *pout = END_EXPRESSION;
		return 0;
	}

	/* place the expression elements into postfix */
	*pout++ = NO_STRING;
	*pout = END_EXPRESSION;
	*perror = CALC_ERR_NONE;

	while (get_element(operand_needed, &psrc, &pel)) {

		if (sCalcPostfixDebug) printf("\tget_element:%s (%s) runtime_depth=%d\n",
			opcodes[(int) pel->code], pel->name, runtime_depth);

		if (*ppostfix != USES_STRING) {
			switch (pel->code) {

			case FETCH_AA: case FETCH_BB: case FETCH_CC: case FETCH_DD: case FETCH_EE: case FETCH_FF:
			case FETCH_GG: case FETCH_HH: case FETCH_II: case FETCH_JJ: case FETCH_KK: case FETCH_LL:
			case FETCH_SVAL:
			case TO_STRING:
			case PRINTF:
			case BIN_WRITE:
			case SSCANF:
	 		case BIN_READ:
			case LITERAL_STRING:
			case SUBRANGE:
			case REPLACE:
			case A_SFETCH:
			case TR_ESC:
			case ESC:
			case CRC16:
			case MODBUS:
			case LRC:
			case AMODBUS:
			case XOR8:
			case ADD_XOR8:
			case LEN:
				*ppostfix = USES_STRING;
				break;
			default:
				break;
			}
		}


		switch (pel->type) {

		case OPERAND:
			*pout++ = pel->code;
			if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pel->code]);
			runtime_depth += pel->runtime_effect;
			operand_needed = FALSE;
			break;

		case LITERAL_OPERAND:
			runtime_depth += pel->runtime_effect;

			psrc -= strlen(pel->name);
			lit_d = epicsStrtod(psrc, &pnext);
			if (pnext == psrc) {
				if (sCalcPostfixDebug) printf("***LITERAL_OPERAND***\n");
				*perror = CALC_ERR_BAD_LITERAL;
				goto bad;
			}
			psrc = pnext;
			lit_i = lit_d;
			if (lit_d != (double) lit_i) {
				*pout++ = pel->code;
				if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pel->code]);
				memcpy(pout, (void *)&lit_d, sizeof(double));
				pout += sizeof(double);
			} else {
				*pout++ = LITERAL_INT;
				if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) LITERAL_INT]);
				memcpy(pout, (void *)&lit_i, sizeof(int));
				pout += sizeof(int);
			}

			operand_needed = FALSE;
			break;

		case STORE_OPERATOR:
			handled = 0;
			/* search stack for A_FETCH (@) or A_SFETCH (@@) */
			for (ps1=pstacktop; ps1>stack; ps1--) {
				if (sCalcPostfixDebug) printf("STORE_OPERATOR:stacktop code=%s (%d)\n",
					opcodes[(int) ps1->code], ps1->code);
				if ((ps1->code == A_FETCH) || (ps1->code == A_SFETCH)) break;
			}
			if (ps1->code == A_FETCH) {
				handled = 1;
				*ps1 = *pel; ps1->code = A_STORE;
			} else if (ps1->code == A_SFETCH) {
				handled = 1;
				*ps1 = *pel; ps1->code = A_SSTORE;
			}

			if (handled) {
				/* Move operators of >= priority to the output, but stop before ps1 */
				while ((pstacktop > ps1) && (pstacktop > stack) &&
					   (pstacktop->in_stack_pri >= pel->in_coming_pri)) {
					*pout++ = pstacktop->code;
					if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
					if (pstacktop->type == VARARG_OPERATOR) {
						*pout++ = 1 - pstacktop->runtime_effect;
						if (sCalcPostfixDebug>=5) printf("put run-time effect %d to postfix\n", 1 - pstacktop->runtime_effect);
					}
					runtime_depth += pstacktop->runtime_effect;
					pstacktop--;
				}
			} else {
				/* convert FETCH_x or FETCH_xx (already posted to postfix string) */
				if (pout > ppostfix && pout[-1] >= FETCH_A && pout[-1] <= FETCH_P) {
					if (sCalcPostfixDebug) printf("STORE_OPERATOR:pout[-1] is a scalar fetch\n");
					/* Convert fetch into a store on the stack */
					pout--;
					if (sCalcPostfixDebug>=5) printf("retracted %s from postfix\n", opcodes[(int) pout[-1]]);
					*++pstacktop = *pel;
					pstacktop->code = STORE_A + *pout - FETCH_A;
				} else if (pout > ppostfix && pout[-1] >= FETCH_AA && pout[-1] <= FETCH_LL) {
					if (sCalcPostfixDebug) printf("STORE_OPERATOR:pout[-1] is a string fetch\n");
					pout--;
					if (sCalcPostfixDebug>=5) printf("retracted %s from postfix\n", opcodes[(int) pout[-1]]);
					*++pstacktop = *pel;
					pstacktop->code = STORE_AA + *pout - FETCH_AA;
				} else {
					if (sCalcPostfixDebug) printf("***STORE_OPERATOR***\n");
					*perror = CALC_ERR_BAD_ASSIGNMENT;
					goto bad;
				}
			}
			runtime_depth -= 1;
			operand_needed = TRUE;
			break;

		case UNARY_OPERATOR:
		case VARARG_OPERATOR:
			/* Move operators of >= priority to the output */
			while ((pstacktop > stack) &&
				   (pstacktop->in_stack_pri >= pel->in_coming_pri)) {
				*pout++ = pstacktop->code;
				if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
				if (sCalcPostfixDebug) printf("UNARY/VARARG op '%s': moved '%s' from stack\n", pel->name, pstacktop->name);
				if (pstacktop->type == VARARG_OPERATOR) {
					*pout++ = 1 - pstacktop->runtime_effect;
					if (sCalcPostfixDebug>=5) printf("put run-time effect %d to postfix\n", 1 - pstacktop->runtime_effect);
				}
				runtime_depth += pstacktop->runtime_effect;
				pstacktop--;
			}

			/* Push new operator onto stack */
			pstacktop++;
			*pstacktop = *pel;
			break;

		case BINARY_OPERATOR:
			/* Move operators of >= priority to the output */
			while ((pstacktop > stack) &&
				   (pstacktop->in_stack_pri >= pel->in_coming_pri)) {
				*pout++ = pstacktop->code;
				if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
				if (sCalcPostfixDebug) printf("BINARY op '%s': moved '%s' from stack\n", pel->name, pstacktop->name);
				if (pstacktop->type == VARARG_OPERATOR) {
					*pout++ = 1 - pstacktop->runtime_effect;
					if (sCalcPostfixDebug>=5) printf("put run-time effect %d to postfix\n", 1 - pstacktop->runtime_effect);
				}
				runtime_depth += pstacktop->runtime_effect;
				pstacktop--;
			}

			/* Push new operator onto stack */
			pstacktop++;
			*pstacktop = *pel;

			operand_needed = TRUE;
			break;

		case SEPARATOR:
			/* Move operators to the output until open paren or bracket or curly */
			while ((pstacktop->name[0] != '(') && (pstacktop->name[0] != '[')
					&& (pstacktop->name[0] != '{')) {
				if (pstacktop <= stack+1) {
					if (sCalcPostfixDebug) printf("***SEPARATOR***\n");
					*perror = CALC_ERR_BAD_SEPARATOR;
					goto bad;
				}
				*pout++ = pstacktop->code;
				if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
				if (pstacktop->type == VARARG_OPERATOR) {
					*pout++ = 1 - pstacktop->runtime_effect;
					if (sCalcPostfixDebug>=5) printf("put run-time effect %d to postfix\n", 1 - pstacktop->runtime_effect);
				}
				runtime_depth += pstacktop->runtime_effect;
				pstacktop--;
			}
			operand_needed = TRUE;
			pstacktop->runtime_effect -= 1;
			break;

		case CLOSE_PAREN:
			/* Move operators to the output until matching paren */
			while (pstacktop->name[0] != '(') {
				if (pstacktop <= stack+1) {
					if (sCalcPostfixDebug) printf("***CLOSE_PAREN***\n");
					*perror = CALC_ERR_PAREN_NOT_OPEN;
					goto bad;
				}
				*pout++ = pstacktop->code;
				if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
				if (pstacktop->type == VARARG_OPERATOR) {
					*pout++ = 1 - pstacktop->runtime_effect;
					if (sCalcPostfixDebug>=5) printf("put run-time effect %d to postfix\n", 1 - pstacktop->runtime_effect);
				}
				runtime_depth += pstacktop->runtime_effect;
				pstacktop--;
			}
			pstacktop--;	/* remove ( from stack */
			/* if there is a vararg operator before the opening paren,
			   it inherits the (opening) paren's stack effect */
			if ((pstacktop > stack) &&
				pstacktop->type == VARARG_OPERATOR) {
				pstacktop->runtime_effect = (pstacktop+1)->runtime_effect;
				/* check for no arguments */
				if (pstacktop->runtime_effect > 0) {
					if (sCalcPostfixDebug) printf("***CLOSE_PAREN_1***\n");
					*perror = CALC_ERR_INCOMPLETE;
					goto bad;
				}
			}
			break;

		case CLOSE_BRACKET:
			if (sCalcPostfixDebug) printf("CLOSE_BRACKET: \n");
			/* Move operators to the output until matching paren */
			while (pstacktop->name[0] != '[') {
				if (sCalcPostfixDebug) printf("CLOSE_BRACKET: stacktop code=%s (%d)\n",
					opcodes[(int) pstacktop->code], pstacktop->code);
				if (pstacktop <= stack+1) {
					if (sCalcPostfixDebug) printf("***CLOSE_BRACKET***\n");
					*perror = CALC_ERR_BRACKET_NOT_OPEN;
					goto bad;
				}
				*pout++ = pstacktop->code;
				if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
				if (pstacktop->type == VARARG_OPERATOR) {
					*pout++ = 1 - pstacktop->runtime_effect;
					if (sCalcPostfixDebug>=5) printf("put run-time effect %d to postfix\n", 1 - pstacktop->runtime_effect);
				}
				runtime_depth += pstacktop->runtime_effect;
				pstacktop--;
			}
			/* add SUBRANGE operator to postfix */
			*pout++ = pstacktop->code;
			if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
			runtime_depth += pstacktop->runtime_effect;
			pstacktop--;

			if (sCalcPostfixDebug) printf("CLOSE_BRACKET: stacktop code=%s (%d)\n",
					opcodes[(int) pstacktop->code], pstacktop->code);
			break;

		case CLOSE_CURLY:
			/* Move operators to the output until matching paren */
			while (pstacktop->name[0] != '{') {
				if (pstacktop <= stack+1) {
					if (sCalcPostfixDebug) printf("***CLOSE_CURLY***\n");
					*perror = CALC_ERR_CURLY_NOT_OPEN;
					goto bad;
				}
				*pout++ = pstacktop->code;
				if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
				if (sCalcPostfixDebug) printf("CLOSE_CURLY op '%s': moved '%s' from stack\n", pel->name, pstacktop->name);
				if (pstacktop->type == VARARG_OPERATOR) {
					*pout++ = 1 - pstacktop->runtime_effect;
					if (sCalcPostfixDebug>=5) printf("put run-time effect %d to postfix\n", 1 - pstacktop->runtime_effect);
				}
				runtime_depth += pstacktop->runtime_effect;
				pstacktop--;
			}
			/* add REPLACE operator to postfix */
			*pout++ = pstacktop->code;
			if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
			runtime_depth += pstacktop->runtime_effect;
			pstacktop--;
			break;

		case CONDITIONAL:
			/* Move operators of > priority to the output */
			while ((pstacktop > stack) &&
				   (pstacktop->in_stack_pri > pel->in_coming_pri)) {
				*pout++ = pstacktop->code;
				if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
				if (sCalcPostfixDebug) printf("CONDITIONAL op '%s': moved '%s' from stack\n", pel->name, pstacktop->name);
				if (pstacktop->type == VARARG_OPERATOR) {
					*pout++ = 1 - pstacktop->runtime_effect;
					if (sCalcPostfixDebug>=5) printf("put run-time effect %d to postfix\n", 1 - pstacktop->runtime_effect);
				}
				runtime_depth += pstacktop->runtime_effect;
				pstacktop--;
			}

			/* Add new element to the output */
			*pout++ = pel->code;
			if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pel->code]);
			runtime_depth += pel->runtime_effect;

			/* For : operator, also push COND_END code to stack */
			if (pel->name[0] == ':') {
				if (--cond_count < 0) {
					if (sCalcPostfixDebug) printf("***CONDITIONAL(:)***\n");
					*perror = CALC_ERR_CONDITIONAL;
					goto bad;
				}
				pstacktop++;
				*pstacktop = *pel;
				pstacktop->code = COND_END;
				pstacktop->runtime_effect = 0;
			} else {
				cond_count++;
			}

			operand_needed = TRUE;
			break;

		case UNTIL_OPERATOR:
			/* Move operators of >= priority to the output */
			while ((pstacktop > stack) &&
				   (pstacktop->in_stack_pri >= pel->in_coming_pri)) {
				*pout++ = pstacktop->code;
				if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
				if (sCalcPostfixDebug) printf("UNTIL_OPERATOR op '%s': moved '%s' from stack\n", pel->name, pstacktop->name);
				if (pstacktop->type == VARARG_OPERATOR) {
					*pout++ = 1 - pstacktop->runtime_effect;
					if (sCalcPostfixDebug>=5) printf("put run-time effect %d to postfix\n", 1 - pstacktop->runtime_effect);
				}
				runtime_depth += pstacktop->runtime_effect;
				pstacktop--;
			}

			/* Push UNTIL to output */
			*pout++ = pel->code;
			if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pel->code]);
			runtime_depth += pel->runtime_effect;

			/* Push UNTIL_END code to stack */
			pstacktop++;
			*pstacktop = *pel;
			pstacktop->code = UNTIL_END;
			pstacktop->runtime_effect = 0;
			break;

		case EXPR_TERMINATOR:
			/* Move everything from stack to the output */
			/* while (pstacktop > stack) { */
			while ((pstacktop > stack) && (pstacktop->name[0] != '(')) {
				*pout++ = pstacktop->code;
				if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
				if (sCalcPostfixDebug) printf("EXPR_TERMINATOR op '%s': moved '%s' from stack\n", pel->name, pstacktop->name);
				if (pstacktop->type == VARARG_OPERATOR) {
					*pout++ = 1 - pstacktop->runtime_effect;
					if (sCalcPostfixDebug>=5) printf("put run-time effect %d to postfix\n", 1 - pstacktop->runtime_effect);
				}
				runtime_depth += pstacktop->runtime_effect;
				pstacktop--;
			}
			operand_needed = TRUE;
			break;

		case STRING_OPERAND:
			runtime_depth += pel->runtime_effect;
			*pout++ = pel->code;
			if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pel->code]);
			c = psrc[-1]; /* " or ' character */
			while (*psrc != c && *psrc) *pout++ = *psrc++;
			*pout++ = '\0';
			if (*psrc) psrc++;
			operand_needed = FALSE;
			break;

		default:
			if (sCalcPostfixDebug) printf("***default***\n");
			*perror = CALC_ERR_INTERNAL;
			goto bad;
		}

		if (runtime_depth < 0) {
			if (sCalcPostfixDebug) printf("***runtime_depth<0***\n");
			*perror = CALC_ERR_UNDERFLOW;
			goto bad;
		}
		if (runtime_depth >= SCALC_STACKSIZE) {
			if (sCalcPostfixDebug) printf("***runtime_depth>=SCALC_STACKSIZE***\n");
			*perror = CALC_ERR_OVERFLOW;
			goto bad;
		}
	}

	if (*psrc != '\0') {
		if (sCalcPostfixDebug) printf("*** *psrc != 0 ***\n");
		*perror = CALC_ERR_SYNTAX;
		goto bad;
	}

	/* Move everything from stack to the output */
	while (pstacktop > stack) {
		if (pstacktop->name[0] == '(') {
			if (sCalcPostfixDebug) printf("*** pstacktop->name[0] == ( ***\n");
			*perror = CALC_ERR_PAREN_OPEN;
			goto bad;
		}
		*pout++ = pstacktop->code;
			if (sCalcPostfixDebug>=5) printf("put %s to postfix\n", opcodes[(int) pstacktop->code]);
		if (sCalcPostfixDebug) printf("done parsing: moved '%s' from stack\n", pstacktop->name);
		if (pstacktop->type == VARARG_OPERATOR) {
			*pout++ = 1 - pstacktop->runtime_effect;
			if (sCalcPostfixDebug>=5) printf("put run-time effect %d to postfix\n", 1 - pstacktop->runtime_effect);
		}
		runtime_depth += pstacktop->runtime_effect;
		pstacktop--;
	}
	*pout = END_EXPRESSION;

	if (cond_count != 0) {
		if (sCalcPostfixDebug) printf("*** cond_count != 0 ***\n");
		*perror = CALC_ERR_CONDITIONAL;
		goto bad;
	}
	if (operand_needed) {
		if (sCalcPostfixDebug) printf("*** operand_needed ***\n");
		*perror = CALC_ERR_INCOMPLETE;
		goto bad;
	}
	if (runtime_depth != 1) {
		if (sCalcPostfixDebug) printf("*** runtime_depth!=1 (==%d) ***\n", runtime_depth);
		*perror = CALC_ERR_INCOMPLETE;
		goto bad;
	}
	if (sCalcPostfixDebug) printf("\nsCalcPostfix: returning success\n");
	return 0;

bad:
	if (sCalcPostfixDebug) {
		printf("\n***error*** '%s'\n", sCalcErrorStr(*perror));
		sCalcExprDump(ppostfix);
	}
	*ppostfix = END_EXPRESSION;
	return -1;
}