



		    calc.pl1                        01/23/89  1235.3rew 01/23/89  1228.6      170109



/****^  ************************************************************
        *                                                          *
        * Copyright, (C) Honeywell Bull Inc., 1989                 *
        *                                                          *
        * Copyright, (C) Honeywell Information Systems Inc., 1982  *
        *                                                          *
        * Copyright, (C) Honeywell Information Systems Inc., 1980. *
        *                                                          *
        ************************************************************ */




/****^  HISTORY COMMENTS:
  1) change(88-10-19,Lee), approve(88-11-21,MCR8025), audit(88-12-23,Flegel),
     install(89-01-23,MR12.3-1010):
     Commands 421 (phx09588, phx18231) - modified to not set up a pi
     handler if it is being invoked as an active function.
  2) change(88-10-19,Lee), approve(88-11-21,MCR8025), audit(88-12-23,Flegel),
     install(89-01-23,MR12.3-1010):
     Commands 464 (phx10119, phx20071) - modified to complain about
     invalid characters specified in function names.
  3) change(88-10-19,Lee), approve(88-11-21,MCR8025), audit(88-12-23,Flegel),
     install(89-01-23,MR12.3-1010):
     Commands 805 (phx21221) - modified to accept "reasonable" variable
     names and to clean up invalid variables left after an error occurs.
                                                   END HISTORY COMMENTS */


/* The calc command provides the user with a calculator capable of evaluatiing PL/I-like expressions */
/* with operator precedence, a set of often used functions, and an addressable-by-identifier memory. */

/* Changed to work as an active function by S. Herbst 10/07/78 */
/* Handlers added for pi, oveflow, underflow 09/28/79 S. Herbst */
/* . and .. features added 12/12/79 S. Herbst */
/* Red & black shifts removed, "q =" bug fixed 04/14/80 S. Herbst */
/* Fixed not to prompt with a space 01/12/81 S. Herbst */

/* format: style4,ind3 */

calc: proc;

dcl  arg char (arg_len) based (arg_ptr);
dcl  return_string char (return_len) varying based (return_ptr);

dcl  (af_sw, expr_arg_sw) bit (1) aligned;

dcl  (arg_ptr, return_ptr) ptr;

dcl  (arg_count, arg_len, return_len) fixed bin;

dcl  error_table_$not_act_fnc fixed bin (35) ext;

dcl  (active_fnc_err_, active_fnc_err_$af_suppress_name) entry options (variable);
dcl  (com_err_, com_err_$suppress_name) entry options (variable);
dcl  cu_$af_return_arg entry (fixed bin, ptr, fixed bin, fixed bin (35));
dcl  cu_$arg_ptr entry (fixed bin, ptr, fixed bin, fixed bin (35));


dcl  (calls static internal, ss, fv, fv_save, num) fixed bin (17);
dcl  code fixed bin (35);
dcl  dum float bin (27);
dcl  (sv, iptr, fvp, mp, vp) ptr;
dcl  floatval float bin (27) based (fvp);
dcl  in char (1300) unaligned;
dcl  move char (20) based (mp);
dcl  space (52) ptr;
dcl  error_string char (32);
dcl  out char (32) aligned;
dcl  var_name_chars char (63) static options (constant)	/* for variable/function name check */
	init ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_");
dcl  valid_token_delimiters char (9)			/* for variable/function name delimiter check */
	static options (constant) init (" .()=+-*/");

dcl  1 in_structure unaligned based (addr (in)),
       2 pad char (2),
       2 in_com char (1298);

dcl  1 s (0:63) aligned,				/* the stack */
       2 type fixed bin (17),
       2 op fixed bin (17),
       2 value float bin (27),
       2 var ptr;

dcl  1 vars based (vp) aligned,			/* the list of variables and values */
       2 next ptr,
       2 d (0:31),
         3 name char (8) aligned,
         3 value float bin (27);

dcl  ffip entry (ptr, fixed bin (17), fixed bin (17), float bin (27));
dcl  ffop entry (char (32) aligned, fixed bin (17), float bin (27));
dcl  (ioa_, ioa_$ioa_switch) entry options (variable);
dcl  iox_$error_output ptr external;
dcl  iox_$get_line entry (ptr, ptr, fixed bin, fixed bin, fixed bin (35));
dcl  iox_$put_chars entry (ptr, ptr, fixed bin, fixed bin (35));
dcl  iox_$user_output ptr ext;
dcl  iox_$user_input ptr ext;
dcl  cu_$cp entry (ptr, fixed bin, fixed bin (35));
dcl  cu_$grow_stack_frame entry (fixed bin (17), ptr, fixed bin (35));
dcl  (noprt, ileq) bit (1);
dcl  funcs (0:6) char (8) static internal init ("sin", "cos", "tan", "atan", "abs", "ln", "log");
dcl  (abs, addr, atan, cos, fixed, index, length, log, log10, ltrim) builtin;
dcl  (mod, null, rtrim, sin, substr, tan, verify) builtin;

dcl  (fixedoverflow, overflow, program_interrupt, underflow) condition;
						/*						*/


      call cu_$af_return_arg (arg_count, return_ptr, return_len, code);
      if code = error_table_$not_act_fnc then do;
         if arg_count > 1 then do;
	  call com_err_$suppress_name (0, "calc", "Usage:  calc {expression}");
	  return;
         end;
         else if arg_count = 1 then expr_arg_sw = "1"b;
         else expr_arg_sw = "0"b;
         af_sw = "0"b;
      end;
      else do;
         if arg_count = 0 | arg_count > 1 then do;
	  call active_fnc_err_$af_suppress_name (0, "calc", "Usage:  [calc expression]");
	  return;
         end;
         af_sw, expr_arg_sw = "1"b;
      end;

      vp, sv = addr (space);				/* initialize vars with e and pi */
      iptr = addr (in);
      vars.next = null;
      vars.d.name (0) = "pi";
      vars.d.value (0) = 3.14159265e0;
      vars.d.name (1) = "e";
      vars.d.value (1) = 2.7182818e0;
      fv = 2;

      if ^af_sw then				/* phx09588,phx18231: */
	 on program_interrupt go to new_line;		/* set up pi handler only if not active function */

      on overflow, fixedoverflow begin;
         error_string = "Overflow";
         go to HANDLE_FAULT;
      end;
      on underflow begin;
         error_string = "Exponent too small";
         go to HANDLE_FAULT;
      end;

new_line: ss = -1;					/* reinitialize variables */
      calls = 0;
      noprt, ileq = "0"b;
      if fv > 31 then do;
         call cu_$grow_stack_frame (104, vp, code);	/* if vars too big, get more space */
         if code ^= 0 then do;
	  call ioa_ ("Fatal out of space");
	  return;
         end;
         vars.next = sv;
         sv = vp;
         fv = 0;
      end;

      if expr_arg_sw then do;
         call cu_$arg_ptr (1, arg_ptr, arg_len, code);

         begin;
dcl  expr_arg char (arg_len + 1);

	  expr_arg = arg || "
";
	  call prec_calc (expr_arg, arg_len + 1, dum, code);

         end;

         return;
      end;

GET_LINE: call iox_$get_line (iox_$user_input, iptr, length (in), num, (0));

      if num = 1 then go to GET_LINE;			/* newline */
      else if num = 2 & substr (in, 1, 1) = "." then do;
         call ioa_ ("CALC 1.1");
         go to GET_LINE;
      end;
      else if substr (in, 1, 2) = ".." then do;
         call cu_$cp (addr (in_com), num - 2, code);
         go to GET_LINE;
      end;

      fv_save = fv;					/* phx21221: save to restore on error */
      call prec_calc (in, num, dum, code);
      if code > 1 then return;
      go to new_line;


HANDLE_FAULT:
      if af_sw then call active_fnc_err_ (0, "calc", "^a", error_string);
      else call ioa_$ioa_switch (iox_$error_output, "^a", error_string);
      if expr_arg_sw then return;
      else go to new_line;
						/*						*/
/**** ****************************INTERNAL PROC PREC_CALC************************************* ****/


/* prec_calc does the actual work of the calc command.  It is recursive so function references may */
/* contain expressions (including other function references). */

prec_calc: proc (in, num, fval, code);
						/* declarations */
dcl  (i, j, k, num, last, level, ip, strt) fixed bin (17);
dcl  code fixed bin (35);
dcl  (x, fval) float bin (27);
dcl  wrk char (1);
dcl  wrka char (8);
dcl  in char (*);
dcl  msg char (40) aligned;

      code, ip, last = 1; level = 0;
      calls = calls + 1; ss = ss + 1;
      s.type (ss) = 0;
      s.op (ss) = 1;				/* put a start-of-stack char on s */
      strt = ss - 1;

start: if s.op (ss) ^= 0 then go to op_red;		/* if s: <op> */
      i = s.op (ss - 1);
      if i = 0 then do;				/* if s: <val> <val>  then error */
miss_op: msg = "Missing operator";
         go to err;
      end;
      if ss - 2 = strt then go to add;			/* if s: "sos" <val>  then add */
      if s.op (ss - 2) = 0 then go to add;		/* if s: <val> <op> <val> then add */
      if i ^= 4 then
	 if i ^= 5 then do;				/* if s ^ : <op> "+"|"-" <val>  error */
ill_prefix:   msg = "Invalid prefix operator";
	    go to err;
	 end;
      go to add;					/* syntax is OK so add to prefix to check prec */

op_red: i = s.op (ss);
      if i = 1 then go to add;			/* if s: "sos" then add */
      j = s.op (ss - 1);
      if j ^= 0 then do;				/* if s: <op> "-"|"+"  then add */
         if i = 4 then go to add;
         if i = 5 then go to add;
      end;
      if i = 2 then
	 if j = 1 then do;				/* if s: "sos" "eoi"  error */
	    if calls = 1 then return;
	    else do;
	       msg = "Null expression";
	       go to err;
	    end;
	 end;
      if i > 2 then
	 if j ^= 0 then go to ill_prefix;		/* error if: <op> ^"eoi" */
      j = s.op (ss - 2);
      if j = 0 then go to miss_op;			/* error */
      if i = 2 then
	 if j = 1 then go to print;			/* if: "sos" <any> "eoi"  then print */
						/* if op1>op2 then add, i.e. check precedence */
      if ss - 3 = strt then go to add;			/* if <val2> is really "sos" then add */
      if s.op (ss - 3) ^= 0 then do;			/* check fo r prefix op */
         if s.type (ss) > s.type (ss - 2) + 4 then go to add; /* check precdence - prefix is very strong */
         if j = 5 then s.value (ss - 1) = -s.value (ss - 1);/* do negation */
         addr (s.type (ss - 2)) -> move = addr (s.type (ss - 1)) -> move; /* move over sign */
         addr (s.type (ss - 1)) -> move = addr (s.type (ss)) -> move;
         ss = ss - 1;
         go to start;
      end;
      if s.type (ss) > s.type (ss - 2) then go to add;	/* s is: <val2><op2><val1><op1> */
      j = j - 3;
      go to operator (j);

operator (0):
ASSIGN: s.var (ss - 3) -> floatval = s.value (ss - 1);	/* do assignment */
      noprt = "1"b;
      go to clean;
operator (1):
ADD:  s.value (ss - 3) = s.value (ss - 3) + s.value (ss - 1); /* do addition */
      go to clean;
operator (2):
SUBTRACT: s.value (ss - 3) = s.value (ss - 3) - s.value (ss - 1); /* do subtraction */
      go to clean;
operator (3):
MULTIPLY: s.value (ss - 3) = s.value (ss - 3) * s.value (ss - 1); /* do multiplication */
      go to clean;
operator (4):
DIVIDE: if s.value (ss - 1) = 0e0 then do;		/* division by zero */
         msg = "Divide by zero";
         go to err;
      end;
      s.value (ss - 3) = s.value (ss - 3) / s.value (ss - 1); /* do division */
      go to clean;
operator (5):
EXPONENT: if s.value (ss - 3) < 0e0 then do;		/* ** of neg number */
         if mod (s.value (ss - 1), 1e0) = 0e0 then do;	/* neg to integer power */
	  s.value (ss - 3) = s.value (ss - 3) ** fixed (s.value (ss - 1), 17, 0);
	  go to clean;
         end;
         msg = "Neg num ** non-integer";
         go to err;
      end;
      if s.value (ss - 1) = 0e0 then
	 if s.value (ss - 3) = 0e0 then do;		/* zero ** zero */
	    msg = "Zero ** zero";
	    go to err;
	 end;
      s.value (ss - 3) = s.value (ss - 3) ** s.value (ss - 1); /* do exponentiation */

clean: addr (s.type (ss - 2)) -> move = addr (s.type (ss)) -> move; /* remove top of stack */
      ss = ss - 2;
      go to start;

print: fval = s.value (ss - 1);
      if calls > 1 then go to no_print;

      if af_sw then do;
         ip = 1;
         call ffop (out, ip, fval);			/* convert value to char string */
         return_string = rtrim (ltrim (substr (out, 1, ip - 1)));
         return;
      end;

      if noprt then go to no_print;
      ip = 5;
      substr (out, 1, 5) = "=   ";			/* set up output line */
      call ffop (out, ip, fval);			/* convert value to char string */
      substr (out, ip, 1) = "
";						/* append NL to output line */
      call iox_$put_chars (iox_$user_output, addr (out), ip, (0));
no_print: calls = calls - 1;				/* return to caller */
      code = 0;
      ss = strt;
      return;

add:  ss = ss + 1;					/* put new cell on stack */
      if ss > 63 then do;				/* too many tokens on stack */
         msg = "Simplify expression";
         go to err;
      end;
blank: if ip >= num then do;				/* look for end of input line */
         if level ^= 0 then do;
	  msg = "Too few )'s";
	  go to err;
         end;
         s.type (ss) = 0;
         s.op (ss) = 2;				/* put "eoi" on stack */
         go to start;
      end;
      wrk = substr (in, ip, 1);
      if wrk ^= " " then go to non_blank;		/* look for non-blank */
incr: ip = ip + 1;
      go to blank;
non_blank:
      i = index ("0123456789.()=+-*/", wrk);
      if i = 0 then go to var_ref;			/* if not as in index, then go to var_ref */
      if i <= 11 then do;
         call ffip (addr (in), num - 1, ip, s.value (ss));	/* if numeric then call ffip for conversion */
         s.op (ss) = 0;
         ileq = "1"b;
         last = 2;
         go to start;
      end;
      if i = 12 then do;				/* if open paren then up prec level */
         if last ^= 1 then
	    if last ^= 3 then do;			/* error if ( follows value or ) */
	       msg = "Invalid use of (";
	       go to err;
	    end;
         last = 3;
         level = level + 5;
         ileq = "1"b;
         go to incr;
      end;

      if i = 13 then do;				/* if ) check for error then lower prec level */
         if level = 0 then do;
	  msg = "Too many )'s";
	  go to err;
         end;
         if last ^= 2 then
	    if last ^= 4 then do;			/* error if ) follows ( or operator */
	       msg = "Invalid use of )";
	       go to err;
	    end;
         last = 4;
         level = level - 5;
         ileq = "1"b;
         go to incr;
      end;

      if last = 3 then
	 if i ^= 15 then
	      if i ^= 16 then do;			/* "(" <op>^="+"|"-" */
	         msg = "Invalid op after (";
	         go to err;
	      end;
      last = 1;
      if substr (in, ip, 2) = "**" then do;
         i = 19;					/* check for ** */
         ip = ip + 1;
      end;

      if i = 14 then
	 if ileq then do;				/* anything but <variable> before "=" is error */
	    msg = "Invalid use of =";
	    go to err;
	 end;
      k = level + 1;
      if i > 18 then k = k + 3;			/* assign precedence level to operator */
      else if i > 16 then k = k + 2;
      else if i > 14 then k = k + 1;
      s.type (ss) = k;
      s.op (ss) = i - 11;
      ileq = "1"b;
      ip = ip + 1;
      go to start;

var_ref: i = ip;					/* save start of var name */
      last = 2;
      if verify (wrk, var_name_chars) ^= 0 then do;	/* phx10119,20071,21221: name validity check */
bad_char: msg = "Invalid char " || wrk;
         go to err;
      end;
      go to first;
var_loop: ip = ip + 1;
      wrk = substr (in, ip, 1);
first: if ip < num then do;
         if verify (wrk, var_name_chars) = 0 then		/* phx10119,20071,21221: name validity check */
	    go to var_loop;				/* find end of name */

         if verify (wrk, valid_token_delimiters) ^= 0 then	/* check for invalid */
	    go to bad_char;				/* char after name */
      end;

      wrka = substr (in, i, ip - i);			/* wrka is var name */

      if expr_arg_sw then do;
         do i = 0 to 6;
	  if wrka = funcs (i) then go to func_ref;
         end;
         if af_sw then call active_fnc_err_ (0, "calc", "Variables not allowed in expression argument.");
         else call com_err_ (0, "calc", "Variables not allowed in expression argument.");
         return;
      end;

      vp = sv;
      k = fv - 1;
next_v: do j = k to 0 by -1;				/* search vars for wrka */
         if wrka = vars.d.name (j) then go to found;
      end;
      vp = vars.next;				/* chain to next block of vars */
      k = 31;
      if vp ^= null then go to next_v;			/* if null then name is undefined */
      if wrka = "q" then do;				/* a name of "q" is a quit so return  with quit code */
         if num > 2 then do;				/* other chars on the line */
	  msg = "Invalid var q";
	  go to err;
         end;
         code = 2;
         return;
      end;
      if wrka = "list" then do;			/* a name of "list" means list all vars */
         wrk = "
";						/* set wrk = NL */
         call iox_$put_chars (iox_$user_output, addr (wrk), 1, (0)); /* print a NL */
         vp = sv;
         k = fv - 1;
another: do j = k to 0 by -1;				/* go through vars printing out values and names */
	  substr (out, 1, 8) = vars.d.name (j);
	  substr (out, 9, 4) = " =  ";
	  ip = 13;
	  call ffop (out, ip, vars.d.value (j));	/* call ffop to convert value to char string */
	  substr (out, ip, 1) = "
";						/* insert NL */
	  call iox_$put_chars (iox_$user_output, addr (out), ip, (0));
         end;
         vp = vars.next;
         k = 31;
         if vp ^= null then go to another;
         call ioa_ (" ");
         return;
      end;
      do i = 0 to 6;				/* see if var name is func name */
         if wrka = funcs (i) then go to func_ref;
      end;
      if ileq then do;				/* since not command or func then undef var */
						/* so invalid if not first in line */
         msg = "Undef var " || wrka;
         go to err;
      end;
      vp = sv;
      j = fv;
      fv = fv + 1;					/* define var */
      vars.d.name (j) = wrka;
      vars.d.value (j) = 0e0;
found: s.op (ss) = 0;
      s.value (ss) = vars.d.value (j);			/* put <val> on stack */
      s.var (ss) = addr (vars.d.value (j));
      go to start;

func_ref: do ip = ip to num while (substr (in, ip, 1) ^= "("); /* find open paren */
      end;
      j = 0;
      do k = ip to num;				/* find close paren */
         if substr (in, k, 1) = "(" then j = j + 1;
         if substr (in, k, 1) = ")" then j = j - 1;
         if j = 0 then go to end_ref;
      end;
      msg = "Missing ) after " || wrka;
      go to err;
end_ref: call prec_calc (substr (in, ip, k - ip + 2), k - ip + 2, x, code);
      if code ^= 0 then return;
      code = 1;
      ip = k + 1;
      s.op (ss) = 0;
      s.var (ss) = null;
      go to func (i);
func (0):
SIN:  s.value (ss) = sin (x); go to start;
func (1):
COS:  s.value (ss) = cos (x); go to start;
func (2):
TAN:  s.value (ss) = tan (x); go to start;
func (3):
ATAN: s.value (ss) = atan (x); go to start;
func (4):
ABS:  s.value (ss) = abs (x); go to start;
func (5):
LN:   s.value (ss) = log (x); go to start;
func (6):
LOG:  s.value (ss) = log10 (x); go to start;

err:						/* error printout section */
      if af_sw then do;
         call active_fnc_err_ (0, "calc", "^a", msg);
      end;
      else call ioa_$ioa_switch (iox_$error_output, "^a", msg);
      fv = fv_save;					/* phx21221 - clean up invalid variables on error */

      return;

   end prec_calc;

/**** *****************************************END INTERNAL PROC PREC_CALC********************************** ****/


   end calc;




		    ffip.pl1                        11/04/82  1904.3rew 11/04/82  1613.3       21141



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1982 *
   *                                                         *
   * Copyright (c) 1972 by Massachusetts Institute of        *
   * Technology and Honeywell Information Systems, Inc.      *
   *                                                         *
   *********************************************************** */


ffip:	proc(inp, len, ip, ret_value);
/* ffip converts a free format inputted string into a bin float number */
dcl
	(len, code, ip, ex, j, llen) fixed bin(17),
	(val_mult, new_div, ret_value) float bin(27),
	(pos, e_pos, frac) bit(1),
	in char(llen) based(inp1) unaligned,
	(inp, inp1) ptr,
	wrk char(1) aligned,
	(value, new) float bin(63),
	ten float bin(27) static init(10e0);

	code = 5000;
	llen = len;
	inp1 = inp;
blank:	if ip>len then do;
		code = 5001;
		return;
		end;
	if substr(in,ip,1)^=" " then go to non_blank;
	ip = ip+1;
	go to blank;

non_blank:	pos = "1"b; frac = "0"b; val_mult = ten; new_div = 1.e0; value = 0.e0;
	wrk = substr(in,ip,1);
	if wrk="+" then go to plus;
	if wrk^="-" then go to no_sign;
		pos = "0"b;
	 plus:ip = ip+1;
		if ip>len then return;
		wrk = substr(in,ip,1);
no_sign: next:
	new = index("0123456789", wrk)-1;
	if new<0e0 then go to not_num;
	code = 0;
	if frac then do;
		new_div = new_div*ten;
		new = new / new_div;
		end;
	value = val_mult*value+new;
	ip = ip+1;
	if ip>len then go to fin;
	wrk = substr(in,ip,1);
	go to next;
not_num:	if wrk="." then do;
		if frac then go to fin;
		frac = "1"b;
		ip = ip+1;
		if ip>len then go to fin;
		wrk = substr(in,ip,1);
		val_mult = 1.e0;
		go to next;
		end;
	if wrk^="e" then
	   if wrk^="E" then go to fin;
	e_pos = "1"b; ex = 0;
	ip = ip+1;
	if ip>len then go to fin;
	wrk = substr(in,ip,1);
	if wrk="+" then go to e_plus;
	if wrk^="-" then go to e_no_sign;
		e_pos = "0"b;
	 e_plus:ip = ip+1;
		if ip>len then go to fin;
		wrk = substr(in,ip,1);
e_no_sign: e_next:
	j = index("0123456789",wrk)-1;
	if j<0 then go to e_fin;
	ex = ten*ex+j;
	ip = ip+1;
	if ip>len then go to e_fin;
	wrk = substr(in,ip,1);
go to e_next;
e_fin:	if ^e_pos then ex = -ex;
	value = value*10.e0**ex;
fin:	if ^pos then value= - value;
	ret_value = value;
	return;
	end;




		    ffop.pl1                        01/23/89  1235.3rew 01/23/89  1228.8       36243



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1989                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        * Copyright (c) 1972 by Massachusetts Institute of        *
        * Technology and Honeywell Information Systems, Inc.      *
        *                                                         *
        *********************************************************** */




/****^  HISTORY COMMENTS:
  1) change(88-10-19,Lee), approve(88-11-21,MCR8025), audit(88-12-23,Flegel),
     install(89-01-23,MR12.3-1010):
     Commands 393 (phx16310) - fixed bug displaying small numbers when
     ten**(prec-mag) exceeds exponent size.
                                                   END HISTORY COMMENTS */


/* format: style4,ind3 */

ffop: proc (string, ip, value);

dcl  (ip, mag, dif, i, j, k, m, n) fixed bin (17);
dcl  val float bin (63);
dcl  roundit float bin (63) static internal init (0.5e0);
dcl  ten float bin (63) static internal init (10e0);
dcl  (num, numt) fixed bin (71);
dcl  value float bin (27);
dcl  numbers (0:9) char (1) static internal init ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
dcl  string char (32) aligned;
dcl  sign char (1) aligned;
dcl  wrk char (26) aligned;
dcl  (prec init (6), len init (32)) fixed bin (17) internal static;
dcl  temp float bin (63);
dcl  (divide, log10, multiply, substr) builtin;

dcl  1 e aligned,
       2 p bit (1) aligned,
       2 old_mag fixed bin (17) aligned;

      wrk = " ";
      e.p = "0"b;
      sign = " ";
      val = value;
      if val = 0.e0 then do;
         mag = prec - 1;
         go to no_log;
      end;
      if val < 0.e0 then do;
         val = -val;
         sign = "-";
      end;
      mag = log10 (val);
      if mag < 0 then mag = mag - 1;
      if mag > prec then go to e_stuff;
      if mag < -1 then do;

e_stuff: e.p = "1"b;
         e.old_mag = mag;

/* fixed for phx16310 - if value if mag is small, */
/* ten**(prec-mag) may generate exponent overflow; */
/* multiply in two steps to prevent this condition */

         val = multiply (val, ten ** (prec), 63);
         val = multiply (val, ten ** (-mag), 63);

         num = val + roundit;
         mag = 0;
         dif = 0;
         go to no_dif;
      end;
      if mag < 0 then mag = mag - 1;

no_log:
      temp = 10e0 ** (prec - mag);
      num = val * temp + roundit;

no_dif:
      mag = mag + 18 - prec;
      i = 18;

next_num:
      if i = mag then do;
         substr (wrk, i, 1) = ".";
         i = i - 1;
      end;
      numt = divide (num, 10, 63, 0);
      k = num - numt * 10;
      num = numt;
      substr (wrk, i, 1) = numbers (k);
      i = i - 1;
      if num > 0 then go to next_num;
      if i >= mag - 1 then go to next_num;
      substr (wrk, i, 1) = sign;
      do j = 18 to mag by -1 while (substr (wrk, j, 1) = "0" | substr (wrk, j, 1) = ".");
      end;
      if e.p then do;
         substr (wrk, j + 1, 1) = "E";
         if e.old_mag < 0 then do;
	  substr (wrk, j + 2, 1) = "-";
	  e.old_mag = -e.old_mag;
         end;
         else substr (wrk, j + 2, 1) = "+";
         m = divide (e.old_mag, 100, 17);
         n = e.old_mag - m * 100;
         if m > 0 then do;
	  substr (wrk, j + 3, 1) = numbers (m);
	  j = j + 1;
         end;
         m = divide (n, 10, 17);
         n = n - m * 10;
         if m > 0 then do;
	  substr (wrk, j + 3, 1) = numbers (m);
	  j = j + 1;
         end;
         substr (wrk, j + 3, 1) = numbers (n);
         j = j + 3;
      end;
      if len - ip < j - i + 1 then do;
         substr (string, ip, len - ip) = (26)"*";
         ip = len + 1;
         return;
      end;
      substr (string, ip, j - i + 1) = substr (wrk, i, j - i + 1);
      ip = ip + j - i + 1;
      return;
   end;




		    bull_copyright_notice.txt       08/30/05  1008.4r   08/30/05  1007.3    00020025

                                          -----------------------------------------------------------


Historical Background

This edition of the Multics software materials and documentation is provided and donated
to Massachusetts Institute of Technology by Group Bull including Bull HN Information Systems Inc. 
as a contribution to computer science knowledge.  
This donation is made also to give evidence of the common contributions of Massachusetts Institute of Technology,
Bell Laboratories, General Electric, Honeywell Information Systems Inc., Honeywell Bull Inc., Groupe Bull
and Bull HN Information Systems Inc. to the development of this operating system. 
Multics development was initiated by Massachusetts Institute of Technology Project MAC (1963-1970),
renamed the MIT Laboratory for Computer Science and Artificial Intelligence in the mid 1970s, under the leadership
of Professor Fernando Jose Corbato.Users consider that Multics provided the best software architecture for 
managing computer hardware properly and for executing programs. Many subsequent operating systems
incorporated Multics principles.
Multics was distributed in 1975 to 2000 by Group Bull in Europe , and in the U.S. by Bull HN Information Systems Inc., 
as successor in interest by change in name only to Honeywell Bull Inc. and Honeywell Information Systems Inc. .

                                          -----------------------------------------------------------

Permission to use, copy, modify, and distribute these programs and their documentation for any purpose and without
fee is hereby granted,provided that the below copyright notice and historical background appear in all copies
and that both the copyright notice and historical background and this permission notice appear in supporting
documentation, and that the names of MIT, HIS, Bull or Bull HN not be used in advertising or publicity pertaining
to distribution of the programs without specific prior written permission.
    Copyright 1972 by Massachusetts Institute of Technology and Honeywell Information Systems Inc.
    Copyright 2006 by Bull HN Information Systems Inc.
    Copyright 2006 by Bull SAS
    All Rights Reserved
