FUNCTION MVMATH(A1, A2, OP, PAD) /* This is a general routine to do MV math on arrays of different sizes. Arguments: ---------- A1 First array - @VM delimited A2 Second array - @VM delimited OP The operation to be performed (+, - , * , /, :). If an invalid operator is passed, the function returns null. PAD The default character(s) used to pad the shorter array, if applicable. These default values are used if PAD is not supplied or is invalid: + = 0 - = 0 * = 1 / = 1 : = "" (null) If the wildcard character "*" is passed, the entire shorter array is used distributively against the longer array. If the characters "**" are used, the "*" is used as the pad (for concantenation only). */ EQU OPS$ TO "+-*/:" EQU PADS$ TO "0011" EQU NULL$ TO "" EQU TRUE$ TO 1 EQU FALSE$ TO 0 EQU OTHERWISE$ TO 1 DECLARE FUNCTION UNASSIGNED * Calculate default pad character for current operator POS = INDEX(OPS$, OP, 1) DEFAULT_PAD = PADS$[POS,1] * Copy arrays (so as not to corrupt originals in calling program) ARRAY1 = A1 ARRAY2 = A2 ANS = NULL$ ;* Return value * Which array is longer? CNT1 = COUNT(ARRAY1, @VM) + (ARRAY1 NE NULL$) CNT2 = COUNT(ARRAY2, @VM) + (ARRAY2 NE NULL$) IF CNT1 NE CNT2 THEN DIFF = ABS(CNT2 - CNT1) SHORT = NULL$ IF CNT1 < CNT2 THEN TRANSFER CNT1 TO CNT TRANSFER ARRAY1 TO SHORT GOSUB PAD TRANSFER SHORT TO ARRAY1 END ELSE TRANSFER CNT2 TO CNT TRANSFER ARRAY2 TO SHORT GOSUB PAD TRANSFER SHORT TO ARRAY2 END END * Do the math BEGIN CASE CASE OP = "+" ANS = ARRAY 1 +++ ARRAY2 CASE OP = "-" ANS = ARRAY1 --- ARRAY2 CASE OP = "*" ANS = ARRAY1 *** ARRAY2 CASE OP = "/" ANS = ARRAY1 /// ARRAY2 CASE OP = ":" ANS = ARRAY1 ::: ARRAY2 CASE OTHERWISE$ ANS = NULL$ END CASE RETURN ANS /*********************************************************************** INTERNAL SUBROUTINES ***********************************************************************/ PAD: ARRAY_PAD = FALSE$ ;* Flag used to see if pad is an array * If no pad specified, use default value IF PAD = NULL$ OR UNASSIGNED(PAD) THEN PAD = DEFAULT_PAD END ELSE * "*" is wildcard character meaning distribute short array IF PAD = "*" THEN PAD = SHORT END IF INDEX(SHORT, @VM, 1) THEN * pad value is an array ARRAY_PAD = TRUE$ END /* "**" is self-escapeing value meaning pad char = "*", (for concat only) */ IF OP = ":" THEN IF PAD = "**" THEN PAD = "*" END END ELSE * check for valid numeric pad, override with default if not * numeric IF ARRAY_PAD THEN FOR CNTR = 1 TO CNT IF NUM(SHORT<1,CNTR>) ELSE SHORT<1,CNTR> = DEFAULT_PAD END NEXT CNTR END ELSE IF NUM(PAD) ELSE PAD = DEFAULT_PAD END END END END * create pad, add to short array IF ARRAY_PAD THEN /* If pad is mv array, concatenate onto short array until it reaches value count of the longer array. */ LONG_CNT = CNT + DIFF SHORT_CNT = CNT LOOP SHORT := @VM : PAD SHORT_CNT += CNT UNTIL SHORT_CNT >= LONG_CNT REPEAT * adjust if it got to be longer than the long array IF SHORT_CNT > LONG_CNT THEN SHORT = FIELD(SHORT, @VM, 1, LONG_CNT) END END ELSE * single character pad PAD = STR(@VM : PAD, DIFF) SHORT := PAD END RETURN