define FOGR,0  rem  section dealing with graph as a whole
define FSGR,1
define FAGR,2
define TCGR,3
define LCGR,4
define LWGR,5
define PDGR,6
define PSGR,7
define BGGR,8
define PWGR,9
define PHGR,10
define BWGR,11
define DCOLGR,12
define GRGR,17
define ROWS,18
define COLUMNS,19
define TDGR,20
define GRAPHTYPE,21
define XLABEL,22
define YLABELS,23
define THICKNESSGR,29
define FRGR,30
define OLGR,31
define OTGR,32
define ORGR,33
define OBGR,34
define ILGR,35
define ITGR,36
define IRGR,37
define IBGR,38
define MTGR,39
define MSGR,40
define PIGR,41
define MAGR,42
define PSIZE,43
define FOA,0   rem  Section dealing with axis
define FSA,1
define FAA,2
define TCA,3
define LCA,4
define LWA,5
define STA,6
define LGA,7
define INA,8
define UPA,9
define LOA,10
define NSA,11
define AA,12
define BA,13
define WIDTHA,14
define HEIGHTA,15
define HOTXA,16
define HOTYA,17
define FORMATA,18
define LENGTHA,19
define PAXIS,20
define FOD,0    rem Section dealing with data set
define FSD,1
define FAD,2
define TCD,3
define LWD,4
define LCD,5
define PDD,6
define PSD,7
define FCD,8
define MTD,9
define MSD,10
define MCD,11
define FRD,12
define TDD,13
define PDATA, 14
define FOM,0    rem Section dealing with marker keys - text properties
define FSM,1
define FAM,2
define TCM,3
define LWM,4    rem line properties
define LCM,5
define PDM,6
define PSM,7
define MTM,8    rem marker properties- repeated 5 times
define MSM,9
define MCM,10
define XSM,28
define YSM,29
define XEM,30
define YEM,31
define NSM,32
define MDATA,33
define FOC,0    rem Section dealing with colour keys - text properties
define FSC,1
define FAC,2
define TCC,3
define LWC,4    rem line properties
define LCC,5
define PDC,6
define PSC,7
define FCC,8    rem colour (repeated 16 times)
define XSC,20
define YSC,21
define XEC,22
define YEC,23
define CDATA,24
define LINES_ONLY,0
define POINTS_ONLY,1
define LINES_AND_POINTS,2
define VERTICAL_HISTOGRAM,3
define HORIZONTAL_HISTOGRAM,4
define BOXES,3
define STACKED_VERTICAL_HISTOGRAM,5
define STACKED_HORIZONTAL_HISTOGRAM,6
define PICTOGRAM,7
define PIE_CHART,8
define TWO_LINES,9
define BOX_AND_TAILS,10
define DISTRIBUTION,11
define GENERAL,12
define LINE_HISTO,13
define DRAG_ALLOWED, 0x1
define SELECT_ALLOWED, 0x2
define TEXT_EFFECTS, 0x4
define FILL_EFFECTS, 0x8
define LINE_EFFECTS, 0x10
define GRAPH_COLOUR_ALLOWED, 0x20
define THREE_DEE_ALLOWED, 0x40
define GRID_ALLOWED, 0x80
define EXPLODE_ALLOWED, 0x100
define COLOURS_ALLOWED, 0x200
define BAR_WIDTH_ALLOWED, 0x400
define POINT_DETAILS_ALLOWED, 0x800
define TICKS_ALLOWED, 0x1000
define DIMENSIONS_ALLOWED, 0x2000
define TOP_ALLOWED, 0x4000
define DELETE_ALLOWED, 0x8000
define ALL_SELECTED, 0x10000
define NONE_SELECTED, 0x20000
define REDRAW_NEEDED, 0x40000

rem : *************************************************************
rem : Next pair of macros fin the lesser and greater of two numbers
rem :

macro CRM_mymin(a,b)
if a<b then 
    =a
else
    =b
endif
endmacro

macro CRM_mymax (a,b)
if a> b then
   =a
else
   =b
endif
endmacro


rem : ******************************************************************
rem  : This macro finds the dimensions of the text t according to the
rem  : axis parameter z. The function returns a compound
rem  : string of the form x=nn,y=mm where both nn and mm are in OS-units 

rem macro finddims(w,z(),t)
rem    local x,y,res
rem    on_error_exit
rem    if len(t) = 0 then = "x=0 y=0"
rem    res  = font(w,z(FOA),z(FSA), int(z(FSA)*z(FAA)/100))
rem    x = textwidth(w,t) + z(FSA)/2
rem    y = textheight(w,t)
rem    = "x=" cat x cat "y=" cat y
rem endmacro



rem : ******************************************************************
rem  : This macro finds displays the text t according to the
rem  : axis parameter z. The function returns 0 

rem macro CRM_showlabel(w,z(),t,xs,ys)
rem    local res,x,y
rem    on_error_exit
rem    res  = font(w,z(FOA),z(FSA), int(z(FSA)*z(FAA)/100))
rem    res = string(w,xs,ys,t,z(TCA),0xffffff00)
rem    =0
rem endmacro


rem : ******************************************************************
rem : This macro is entered with a string in A and a two-letter
rem : code in B.  The macro searches a for an occurence of B.
rem : if found it returns the number which immediately follows 
rem : the occurence. 
rem :
rem : The macro is used to decode the result strings of macros which
rem : return several values (like  scale)

macro CRM_extract (a,b)
   local res
   on_error_exit
   res = find(a,b)
   =mid(a,res+2,res+35)+0.0
endmacro



rem:  *****************************************************************
rem:  X is a one-letter parameter code type code.  This function
rem:  returns asc(first letter)
rem:

macro CRM_code (x)
   = asc(x)
endmacro



rem : *****************************************************************
rem : This macro returns the (decimal) antilog of X.
rem : the constant is the natural log of 10

macro CRM_antilog (x)
   = exp(2.302585093 * x)
endmacro



rem : *****************************************************************
rem :  This macro calculates an appropriate linear scale for displaing
rem :  values in the range (SMALLEST to LARGEST) in a space of SIZE 
rem :  os-units.  The macro returns a string of the form 
rem :      a=aa b=bb i = ii l = ll h = hh      where    
rem :  aa and bb let any value be transformed to a display
rem :  coordinate according to the formula  x = aa*value + bb
rem :  ii gives the number of intervals on the axis
rem :  ll and hh are the lowest and highest plottable values
rem :  note that (ll - hh) encloses (smallest - largest)
rem :  if smallest and largest are the same the function returns "0:0"

macro CRM_linear_scale(smallest,largest,size)

   local dump,power,diff,span,lowest,highest,interval,a,b
   if (smallest = largest)  then 
         largest = smallest+0.45
         smallest = smallest - 0.45
   endif
        
   loop:
   diff = abs(largest-smallest)
   if (diff < 10e-50) then = "0:0"
                   rem : Establish scales to the nearest power of 10

   power=0
   while(diff >= 10)
       power=power+1
       diff=diff/10
   endwhile
   while(diff < 1)
       power=power-1
       diff=diff*10
   endwhile
   
                   rem : adjust scale by smaller factors

   if diff > 5 then span=10
   if diff <= 5 & diff > 2 then span = 5
   if diff <= 2 & diff > 1 then span = 2
   if diff = 1 then span = 1 
   span = span * (10^power)
   
   interval = span/10
   lowest = floor(smallest/interval) * interval
   highest = ceil(largest / interval) *interval
   a=size/(highest-lowest)
   b= -(lowest*a)
   = "a=" cat a cat "b=" cat b cat "i=" cat interval cat "l=" cat lowest cat "h=" cat highest 
endmacro



rem : **********************************************************************
rem : This macro calculates an appropriate logarithmic scale for displaying
rem : values in the range (SMALLEST to LARGEST) in a space of SIZE os_units.
rem : The axis always contains an integral number of decades.
rem : The macro returns a string of the form a=aa b=bb i = ii l = ll h = hh
rem : where    
rem : aa and bb let any value be transformed to a display
rem : coordinate according to the formula  x = aa*log(value) + bb
rem : ii gives the number of decades on the axis
rem : ll and hh are the lowest and highest plottable values
rem : note that (ll - hh) encloses (smallest - largest)
rem : If the scale cannot be drawn because smallest > largest or 
rem : smallest <= 0 the function returns "0:0"

macro CRM_log_scale(smallest,largest,size)
   local lowest, highest,aa,bb,ii,ll,hh
   on_error_exit
   if smallest >= largest  then ="0:0"
   if smallest <= 0 then ="0.0"
   lowest = floor(log(smallest))
   highest = ceil(log(largest))
   ii = highest - lowest
   ll = CRM_antilog(lowest)
   hh = CRM_antilog(highest)
   aa = size/ii
   bb = -lowest *aa
   = "a="cat aa cat"b="cat bb cat"i="cat ii cat"l="cat ll cat"h="cat hh 
endmacro



rem : *********************************************************************
rem : given a parameter string s and a two-letter code key, this
rem : function opens the string and tries to select the substring with
rem : the given key. If found it exits with a handle. If not, it returns -1
rem : Note that after the handle has been used the string must be closed by
rem : calling close_string

macro CRM_find_substring(s,key)
   local v,q
   v =  psregister(s)
   if iserror(v) then = v
   repeat 
       q = psstep (v)
       if iserror(q) then = -1
       if q = CRM_code(key) then = v
   until  q = 0 or iserror(q)
   = (-1)
endmacro



rem : ********************************************************************
rem : This function closes the string with current handle v
macro CRM_close_string(v)
   local q
   repeat
      q = psstep(v)
      if iserror(q) then = 0
   until q=0
   =0
endmacro



rem : ********************************************************************
rem  : This macro finds the dimensions of the text t according to the
rem  : parameter array indicated by p. The function returns a compound
rem  : string of the form x=nn,y=mm where both nn and mm are in OS-units 
macro CRM_finddims(w,p(),t)
   local res,x,y
   res  = font(w,p(FOA),p(FSA), int(p(FSA)*p(FAA)/100))
   x = textwidth(w,t) + p(FSA)/2
   y = textheight(w,t)
   = "x=" cat x cat "y=" cat y
endmacro


rem : ********************************************************************
rem  : This macro finds displays the text t at xs,ys according to the
rem  : parameter array indicated by p. The function returns 0 
macro CRM_showlabel(w,p(),t,xs,ys)
   local res
   res  = font(w,p(FOA),p(FSA), int(p(FSA)*p(FAA)/100))
   res = string(w,xs,ys,t,p(TCA),0xffffff00)
   =0
endmacro



rem : ********************************************************************
rem : Macro datasets is called with a control string registered
rem : at v.  It computes and returns the number of data sets
rem : making proper assumption for defaults
rem : The number is limited to 5

macro CRM_datasets(v, cols, rows)
   local n,u,p,s
   p = psexhex(v,"P",-1)
   u = pscontains(v,"u")
   n=0
   if pscontains(v,"Q") then n=n+1     
   if pscontains(v,"R") then n=n+1
   if pscontains(v,"S") then n=n+1
   if pscontains(v,"T") then n=n+1
   if pscontains(v,"U") then n=n+1
   if (p < 0 and n= 0) then
        s = if u then rows+1 else cols+1 endif
    endif
rem case 2:  x axis selected only. Take rest
    if (p>= 0 and n = 0) then
          s = if u then rows-p else cols-p endif
    endif
rem case 3  y_axes given (with or without x-axis)
    if (n > 0) then
          s = n+1
    endif
    = if s < 6 then s else 6 endif
endmacro

macro CRM_psexcol(v,s,def)
   local q
   q = psexhex(v,s,0xffffffff)
   if q = 0xffffffff then =def
   = q
endmacro

rem : **************************************************
rem : New colour handling code starts here.

macro crm_get_hex(a,b)
     rem gets a hex value from string a starting at position b
local x,y,z,w
z=0
for x = 0 to 5
  y = mid(a,b+x,b+x)
  if y >= "0" and y <= "9" then w = asc(y) - asc("0")
  if y >= "A" and y <= "F" then w = asc(y) - asc("A")+10
  if y >= "a" and y <= "f" then w = asc(y) - asc("a")+10
  z=(z<<4)  or w
next x
  =z<<8
endmacro

rem : *******************************************************************
rem : Macro get_gr_params scans a gr control substring and extracts
rem : values for FO,FC,FA,TC,LC,LW,PD,PS,BG,PW,PH,TD,OL,OT,OR,OB,IL,IT,IR,IB
macro CRM_get_gr_params(p(),v)
local q
    p(FOGR) = psexstr(v,"#","Trinity.Medium")
    p(FSGR) = psexdec(v,"H",12)
    p(FAGR) = psexhex(v,"I",100)
    p(TCGR) = CRM_psexcol(v,"J",0)
    p(LCGR) = CRM_psexcol(v,"L",0)
    p(LWGR) = psexhex(v,"M",0)
    p(PDGR) = psexhex(v,"N",1)
    p(PSGR) = psexhex(v,"O",0)
    p(PWGR) = psexhex(v,"i",800)
    p(PHGR) = psexhex(v,"j",600)
    q = psexhex(v,"g",0x05050505)
    p(OLGR) =  (q & 0xff000000) >> 22
    p(OTGR) =  (q & 0xff0000) >> 14
    p(ORGR) =  (q & 0xff00) >> 6
    p(OBGR) =  (q & 0xff) << 2

   q = psexhex(v,"h",0x05050505)
    p(ILGR) = (q & 0xff000000) >> 22
    p(ITGR) = (q & 0xff0000) >> 14
    p(IRGR) = (q & 0xff00) >> 6
    p(IBGR) = (q & 0xff) << 2
    p(TDGR) = pscontains(v,"W")
    p(BGGR) = psexstr(v,"@","no")
    if p(BGGR) ="no" then
           REM set default colours
          p(BGGR) = 0xECECEC00
          p(DCOLGR) = 0xA0A0A000
          p(DCOLGR+1) = 0xff0000
          p(DCOLGR+2) = 0xff00
          p(DCOLGR+3) = 0xff000000
          p(DCOLGR+4) = 0xffff0000
          p(MAGR) = 0xffffff00
       else
          p(DCOLGR) = crm_get_hex(p(BGGR),7)
          p(DCOLGR+1) = crm_get_hex(p(BGGR),13)
          p(DCOLGR+2) = crm_get_hex(p(BGGR),19)
          p(DCOLGR+3) = crm_get_hex(p(BGGR),25)
          p(DCOLGR+4) = crm_get_hex(p(BGGR),31)
          p(MAGR) = crm_get_hex(p(BGGR),37)
          p(BGGR) = crm_get_hex(p(BGGR),1)
    endif

    p(GRGR) = pscontains(v,"V")
    p(FRGR) = psexhex(v,"o",70)
    p(THICKNESSGR) = if p(TDGR)=0 then 0 else 28 endif
    p(MTGR) = psexhex(v,"q",1)
    p(MSGR) = psexhex(v,"r",20)
    p(PIGR) = psexstr(v,"$","blob")
    =0
endmacro



rem : *******************************************************************
rem: macro get_ax_params extracts axis parameters from an ax or ay
rem: control substring.
macro CRM_get_ax_params(p(),q(),v)
    q(FOA) = psexstr(v,"#",p(FOGR))
    q(FSA) = psexdec(v,"H",p(FSGR))
    q(FAA) = psexhex(v,"I",p(FAGR))
    q(TCA) = CRM_psexcol(v,"J",p(TCGR))
    q(LCA) = CRM_psexcol(v,"L",p(LCGR))
    q(LWA) = psexhex(v,"M",p(LWGR))
    q(STA) = psexhex(v,"t",0)
    q(LGA) = pscontains(v,"s")
    q(INA) = 0
    q(UPA) = psexdec(v,"v",-1)
    q(LOA) = psexdec(v,"w",-1)
    q(NSA) = pscontains(v,"G")
    =0
endmacro



rem : *******************************************************************
rem : macro get_di_params extracts data set parameters from a DI string
rem : macro CRM_get_di_params(p(),q(),v,type)
rem :     q(FOD) = psexstr(v,"#",p(FOGR))
rem :     q(FSD) = psexdec(v,"H",p(FSGR))
rem :     q(FAD) = psexhex(v,"I",p(FAGR))
rem :     q(TCD) = CRM_psexcol(v,"J",p(TCGR))
rem :     q(LWD) = psexhex(v,"L",p(LWGR))
rem :     q(LCD) = CRM_psexcol(v,"L",p(DCOLGR+type-1))
rem :     q(PDD) = psexhex(v,"N",p(PDGR))
rem :     q(PSD) = psexhex(v,"O",p(PSGR))
rem :     q(FCD) = CRM_psexcol(v,"K",0xffffff00)
rem :     q(MTD) = if p(MTGR)=0 then 0 else (p(MTGR)-2+type) %5 +1  endif
rem :     q(MSD) = psexhex(v,"r",p(MSGR))
rem :     q(MCD) = CRM_psexcol(v,"n",p(DCOLGR+type-1))
rem :     q(FRD) = psexhex(v,"o",75)
rem :     q(TDD) = pscontains(v,"W") or p(TDGR)
rem :     =0
rem : endmacro



rem : *******************************************************************
rem : macro get_di_default_params sets up a data set parameters if
rem : there is no DI string. The marker type is given as a parameter.
rem : It also returns a dummy string to be used as a tag
macro CRM_get_di_default_params (p(),q(),type)
    q(FOD) = p(FOGR)
    q(FSD) = p(FSGR)
    q(FAD) = p(FAGR)
    q(TCD) = p(TCGR)
    q(LWD) = p(LWGR)
    q(LCD) = p(DCOLGR+type-1)
    q(PDD) = p(PDGR)
    q(PSD) = p(PSGR)
    q(FCD) = 0xffffff00
    q(MTD) = if p(MTGR) = 0 then 0 else (p(MTGR)-2+type)%5+1  endif
    q(MSD) = p(MSGR)
    q(MCD) = p(DCOLGR+type-1)
    q(LCD) = q(MCD)
    q(FRD) = 75
    q(TDD) = p(TDGR)
    = "D(q" cat type cat ")"
endmacro


rem : *******************************************************************
rem : macro get_legend_params extracts legend parameters from a LE string
macro CRM_get_legend_params(p(),q(),v)
    q(FOM) = psexstr(v,"#",p(FOGR))
    q(FSM) = psexdec(v,"H",p(FSGR))
    q(FAM) = psexhex(v,"I",p(FAGR))
    q(TCM) = CRM_psexcol(v,"J",p(TCGR))
    q(LWM) = psexhex(v,"M",p(LWGR))
    q(LCM) = CRM_psexcol(v,"L",p(LCGR))
    q(PDM) = psexhex(v,"N",p(PDGR))
    q(PSM) = psexhex(v,"O",p(PSGR))
    q(MSM) = psexhex(v,"r",20)
    q(XSM) = psexdec(v,"X",0)
    q(YSM) = psexdec(v,"Y",0)
    q(NSM) = pscontains(v,"G")
    =0
endmacro



rem : *******************************************************************
rem : macro get_legend_default_params sets up legend parameters if
rem : there is no LE string. 
rem : It also returns a dummy string to be used as a tag
macro CRM_get_legend_default_params (p(),q())
    q(FOM) = p(FOGR)
    q(FSM) = p(FSGR)
    q(FAM) = p(FAGR)
    q(TCM) = p(TCGR)
    q(LWM) = p(LWGR)
    q(LCM) = p(LCGR)
    q(PDM) = p(PDGR)
    q(PSM) = p(PSGR)
    q(MSM) = 20
    q(XSM) = 0
    q(YSM) = 0
    q(NSM)=0

    = "F()"
endmacro



rem : ******************************************************************
rem : handle_text looks after a text sub-string. W is the current window, 
rem : V is the handle to the parameter substring, and T is the text to be
rem : used by default if the parameter substring holds no text
rem :
rem : The parameter string MUST include  XS,YS (position) and FS 
rem : (character size) fields.
rem : It MAY include TC (text colour), FA (aspect ratio) AL (alignment) 
rem :FO(font) and TT (text to be used instead of default text T)
macro CRM_handle_text (w,v,t,p())

   local xs, ys, bg,fs,tc,fc,fa,al,fo, tt,res,width,substring
   rem extract parameters and put in defaults
   xs = psexdec(v,"X",0)
   ys = psexdec(v,"Y",0)
   fs = psexdec(v,"H",0)
   if (xs = 0 or ys = 0 or fs = 0) then =0

   tc = CRM_psexcol(v,"J",0)
   fc = CRM_psexcol(v,"k",p(BGGR)) 
   fa = psexhex(v,"I",100)
   al = psexhex(v,"p",0)
   tt = psexstr(v,"&",t)
   fo = psexstr(v,"#","Trinity.Medium")
   res = font(w,fo,fs, int(fs*fa/100))
   if (al > 0) then
      width = textwidth(w,tt)
      if al = 1 then xs = xs - width/2
      if al = 2 then xs=xs-width
   endif
   if xs < 0 then xs = 0
   if ys < 0 then ys = 0
   substring = psexsub(v)
   res  = res or settag(substring,DRAG_ALLOWED+SELECT_ALLOWED+TEXT_EFFECTS)
   res = res or string(w,xs,ys,tt,tc,fc)
   =res
endmacro


rem : ********************************************************************
rem : Handles a solid sub-string. W is the current window, V is the handle 
rem : to the parameter substring.
rem : The substring MUST include XS,YS (position) , XY,YE (extent) and FC 
rem : (colour)
rem : It may include LC (line colour) and LW (line thickness)
macro CRM_handle_solid (w,v,flag)

   local xs, ys, xe,ye,fc,lw,lc,substring,res
   rem extract parameters and put in defaults
   xs = psexdec(v,"X",0)
   ys = psexdec(v,"Y",0)
   xe = psexdec(v,"x",0)
   ye = psexdec(v,"y",0)
   fc = CRM_psexcol(v,"K",(-1))
   if (xs = 0 or ys = 0 or ye=0 or xe = 0) then =0
   lc = CRM_psexcol(v,"L",fc)
   lw = psexhex(v,"M",0)
   substring = psexsub(v)
   res = res or settag(substring,DRAG_ALLOWED+SELECT_ALLOWED+FILL_EFFECTS)
   res = res or lineattributes(w,1,lw,lc,0x14)
   if flag = CRM_code("b") then
       res = res or box(w,xs,ys,xe,ye,fc)
   endif
   if flag = CRM_code("f") then
      res = res or ellipse(w, xs+xe/2,ys+ye/2,0,360,xe/2,ye/2,0,fc)
   endif
   if flag = CRM_code("c") then
      res = res or arc(w,xs+xe/2,ys+ye/2,0,360,xe/2,fc)
   endif
   =res
endmacro

rem : *****************************************************************
rem : Handles a line sub-string. W is the current window, W is the 
rem : handle to the parameter substring
rem : The string MUST include XS,YS (position) and XY,YE (extent) 
rem : It may include LC(line colour),LW (line thickness) PD (dots and 
rem : dashes) and PS (Path style)
macro CRM_handle_line (w,v)

   local xs, ys, xe,ye,lw,lc,ps,pd,substring,res
   rem extract parameters and put in defaults
   xs = psexdec(v,"X",0)
   ys = psexdec(v,"Y",0)
   xe = psexdec(v,"x",0)
   ye = psexdec(v,"y",0)
   if (xs = 0 or ys = 0 or ye=0 or xe = 0) then =0
   lc = CRM_psexcol(v,"L",0)
   lw = psexhex(v,"M",1)
   ps = psexhex(v,"O",0)
   pd = psexhex(v,"N",0)
   substring = psexsub(v)
   res = res or settag(substring, DRAG_ALLOWED+SELECT_ALLOWED+LINE_EFFECTS)
   res = res or lineattributes(w,pd,lw,lc,ps)
   res = res or line(w,xs,ys,xe,ye)
   =res
endmacro


rem : *****************************************************************
rem : Handles a drawfile. W is the current window, V is the 
rem : handle to the parameter substring
rem : The string MUST include X,Y (position) and $ (file name).
rem : It may include x,y (extent) and A (picture type)
macro CRM_handle_drawfile (w,v)

   local xs, ys, xe,ye,fn,ft,res,k,substring
   rem extract parameters and put in defaults
   xs = psexdec(v,"X",0)
   ys = psexdec(v,"Y",0)
   xe = psexdec(v,"x",100)
   ye = psexdec(v,"y",100)
   fn = psexstr(v,"$","blob")
   ft = psexhex(v,"A",0)
   substring = psexsub(v)
   res = res or settag(substring, DRAG_ALLOWED+SELECT_ALLOWED)
   k = fetchgraph(fn)
   if ft = 0 then res = picture(w,k,xs,ys)
   if ft=1 then res = scaledpicture(w,k,xs,ys,xe,ye)
   if ft=2 then res = squeezedpicture(w,k,xs,ys,xe,ye)   
   =res
endmacro

rem : ******************************************************
rem : This macro handles all the tail-end substrings at the
rem : end of a parameter string. s is the string parameter
rem : The string is assumed to be unregistered at the 
rem : moment of entry
rem : recent object read
macro CRM_tail_end (w,s,p())
   local v,j,flag
   v = psregister(s)
   flag = psstep(v)
   while (flag > 0)
      if flag = CRM_code("e")  j=CRM_handle_text(w,v,"NULL",p)
      if flag = CRM_code("b")  j= CRM_handle_solid(w,v,flag)
      if flag = CRM_code("a")  j= CRM_handle_line(w,v)
      if flag = CRM_code("f")  j = CRM_handle_solid(w,v,flag)
      if flag = CRM_code("c")  j = CRM_handle_solid(w,v,flag)
      if flag = CRM_code("d")  j = CRM_handle_drawfile(w,v)
      flag = psstep(v)
   endwhile
   = flag
endmacro

rem : ********************************************************************
rem : macro point_plot_row_data is entered with an array a in which the data
rem : sets are in rows and may not be contiguous.  The data set to be used
rem : as x-axis (if any) is given by parameter CA, and the others by CB, CC, etc.
rem : The macro extracts the data sets, and arranges them into compact columns
rem : in array data.  If CA is absent, the first column is filled with the
rem : numbers 1,2,3 ...   This process *normalises* the data.
rem : If any row has a string as its first item, all the first items are
rem : taken as labels and copied to the parameter array p.
rem : 
rem : When the data array has been set up, the function calls a function which
rem : depends on the type of graph being plotted.
rem :   
macro CRM_point_plot_row_data(a(),s,v,p(),w,n,flag)
   local data(w,n)
   local date,val
   local x,t,j,k
   local y(5)
   x = psexhex(v,"P",-1)
   if ( x < 0) then
      y(0) = psexhex(v,"Q",if n>1.5 then 0 else -1 endif)
      y(1) = psexhex(v,"R",if n>2.5 then 1 else -1 endif)
      y(2) = psexhex(v,"S",if n>3.5 then 2 else -1 endif)
      y(3) = psexhex(v,"T",if n>4.5 then 3 else -1 endif)
      y(4) = psexhex(v,"U",if n>5.5 then 4 else -1 endif)
   else
      y(0) = psexhex(v,"Q",if n>0.5 then x+1 else -1 endif)
      y(1) = psexhex(v,"R",if n>1.5 then x+2 else -1 endif)
      y(2) = psexhex(v,"S",if n>2.5 then x+3 else -1 endif)
      y(3) = psexhex(v,"T",if n>3.5 then x+4 else -1 endif)
      y(4) = psexhex(v,"U",if n>4.5 then x+5 else -1 endif)
   endif
                                          rem: look for titles
   t=0
   if x >= 0 and (p(GRAPHTYPE) = LINES_ONLY or p(GRAPHTYPE) = POINTS_ONLY or p(GRAPHTYPE) = LINES_AND_POINTS or p(GRAPHTYPE)=GENERAL) then
       if type(a(x,0)) = 3 then t=1
   endif
   if y(0) >= 0 then
       if type(a(y(0),0)) = 3 then t=1
   endif
   if y(1) >= 0 then
       if type(a(y(1),0)) = 3 then t=1
   endif
   if y(2) >= 0 then
       if type(a(y(2),0)) = 3 then t=1
   endif
   if y(3) >= 0 then
       if type(a(y(3),0)) = 3 then t=1
   endif
   if y(4) >= 0 then
       if type(a(y(4),0)) = 3 then t=1
   endif
   rem extract titles if any
   if t = 1 then
      if x >= 0 then p(XLABEL) = a(x,0)
      for j = 0 to 4
          p(YLABELS+j) = a(y(j),0)
          if p(YLABELS+j) = 0 then p(YLABELS+j) = "" 
      next j
   else
      p(XLABEL) = ""
      for j = 0 to 4
          p(YLABELS+j) = ""
      next j
   endif
   rem set up x-axis

   date = 0
   if x >= 0 then
      for j = t to  w-1
          data(j-t,0) = a(x,j)
          if flag =1 then
             data(j-t,0) = cell(a(x,j)..a(x,j),"Formatted")
          endif
          if flag = 2 then
             val = cell(a(x,j)..a(x,j), "Customformat")
             if (find(val,"%d") >= 0 or find(val,"%m") >= 0 or find(val,"%24")>= 0) then
                 data(j-t,0) = cell(a(x,j)..a(x,j),"Formatted")
                 date=1
             endif 
          endif               
      next j                
    else
       for j = t to w-1
          data(j-t,0) = j-t+1
       next j
    endif
    rem set up y-columns
    for k = 1 to n-1
       for j = t to w-1
          data(j-t,k) = a(y(k-1),j)
       next j
    next k
    p(ROWS) = w-t
    p(COLUMNS) = n
    if t=1 & x = (-1) then p(XLABEL) = "Implicit axis"
   if p(GRAPHTYPE)=LINES_ONLY or p(GRAPHTYPE)=POINTS_ONLY or p(GRAPHTYPE)=LINES_AND_POINTS then
          = CRM_point_plot_x(data,s,p,v)
    endif
    if p(GRAPHTYPE)= VERTICAL_HISTOGRAM or p(GRAPHTYPE) = STACKED_VERTICAL_HISTOGRAM or p(GRAPHTYPE) = LINE_HISTO then
          = CRM_v_histo_plot(data,s,p,v)
    endif
    if p(GRAPHTYPE)= HORIZONTAL_HISTOGRAM or p(GRAPHTYPE) = STACKED_HORIZONTAL_HISTOGRAM then
          = CRM_h_histo_plot(data,s,p,v)
    endif
    if p(GRAPHTYPE) = PIE_CHART then
           = CRM_flex_pie_chart(data,s,p,v)
    endif
    if p(GRAPHTYPE) = PICTOGRAM then
           = CRM_picto_plot (data,s,p,v)
    endif  
    if p(GRAPHTYPE) = GENERAL then
           = CRM_which_type(data,s,p,v,date)
    endif
   ="Unknown graph type"
endmacro



rem : ******************************************************************
rem : macro point_plot_col_data is entered with an array a in which the data
rem : sets are in columns and may not be contiguous.  The data set to be used
rem : as x-axis (if any) is given by parameter CA, and the others by CB, CC, etc.
rem : The macro extracts the data sets, and arranges them into compact columns
rem : in array data.  If P is absent, the first column is filled with the
rem : numbers 1,2,3 ...
rem : If any column has a string as its first item, all the first items are
rem : taken as labels and copied to the parameter array p.
rem : 
rem : When the data array has been set up, the function calls point_plot_x
rem :   
macro CRM_point_plot_col_data(a(),s,v,p(),h,n,flag)
   local data(h,n)
   local x,t,j,k,res
   local y(5)
   local date,val
   x = psexhex(v,"P",-1)
    if ( x < 0) then
      y(0) = psexhex(v,"Q",if n>1.5 then 0 else -1 endif)
      y(1) = psexhex(v,"R",if n>2.5 then 1 else -1 endif)
      y(2) = psexhex(v,"S",if n>3.5 then 2 else -1 endif)
      y(3) = psexhex(v,"T",if n>4.5 then 3 else -1 endif)
      y(4) = psexhex(v,"U",if n>5.5 then 4 else -1 endif)
   else
      y(0) = psexhex(v,"Q",if n>1.5 then x+1 else -1 endif)
      y(1) = psexhex(v,"R",if n>2.5 then x+2 else -1 endif)
      y(2) = psexhex(v,"S",if n>3.5 then x+3 else -1 endif)
      y(3) = psexhex(v,"T",if n>4.5 then x+4 else -1 endif)
      y(4) = psexhex(v,"U",if n>5.5 then x+5 else -1 endif)
   endif
   rem look for titles
   t=0
   if x >= 0 and (p(GRAPHTYPE) = LINES_ONLY or p(GRAPHTYPE) = POINTS_ONLY or p(GRAPHTYPE) = LINES_AND_POINTS or p(GRAPHTYPE)=GENERAL) then
       if type(a(0,x)) = 3 then t=1
   endif
   if y(0) >= 0 then
       if type(a(0,y(0)))=3 then t=1
   endif
   if y(1) >= 0 then
       if type(a(0,y(1))) = 3 then t=1
   endif
   if y(2) >= 0 then
       if type(a(0,y(2))) = 3 then t=1
   endif
   if y(3) >= 0 then
       if type(a(0,y(3))) = 3 then t=1
   endif
   if y(4) >= 0 then
       if type(a(0,y(4))) = 3 then t=1
   endif
   rem extract titles if any
   if t = 1 then
      if x >= 0 then p(XLABEL) = a(0,x)
      for j = 0 to 4
          p(YLABELS+j) = a(0,y(j))
          if p(YLABELS+j) = 0 then p(YLABELS+j) = ""
      next j
   else
      p(XLABEL) = ""
      for j = 0 to 4
          p(YLABELS+j) = ""
      next j
   endif

   rem set up x-axis
   date = 0
   if x >= 0 then
      for j = t to  h-1
          data(j-t,0) = a(j,x)
          if flag =1 then
             data(j-t,0) = cell(a(j,x)..a(j,x),"Formatted")
          endif
          if flag = 2 then
             val = cell(a(j,x)..a(j,x), "Customformat")
             if (find(val,"%d") >= 0 or find(val,"%m") >= 0 or find(val,"%24")>= 0) then
                 data(j-t,0) = cell(a(j,x)..a(j,x),"Formatted")
                 date=1
             endif 
          endif               
      next j                
    else
       for j = t to h-1
          data(j-t,0) = j-t+1
       next j
    endif
    rem set up y-columns
    for k = 1 to n-1
       for j = t to h-1
          data(j-t,k) = a(j,y(k-1))
       next j
    next k
    p(ROWS) = h-t
    p(COLUMNS) = n
    if t=1 & x = (-1) then p(XLABEL) = "Implicit axis"
    if p(GRAPHTYPE)=LINES_ONLY or p(GRAPHTYPE)=POINTS_ONLY or p(GRAPHTYPE)=LINES_AND_POINTS then
          = CRM_point_plot_x(data,s,p,v)
    endif
    if p(GRAPHTYPE)= VERTICAL_HISTOGRAM or p(GRAPHTYPE) = STACKED_VERTICAL_HISTOGRAM or p(GRAPHTYPE) = LINE_HISTO then
          = CRM_v_histo_plot(data,s,p,v)
    endif
    if p(GRAPHTYPE)= HORIZONTAL_HISTOGRAM or p(GRAPHTYPE) = STACKED_HORIZONTAL_HISTOGRAM then
          = CRM_h_histo_plot(data,s,p,v)
    endif      
    if p(GRAPHTYPE) = PIE_CHART then
           = CRM_flex_pie_chart(data,s,p,v)
    endif
    if p(GRAPHTYPE) = PICTOGRAM then
            = CRM_picto_plot(data,s,p,v)
    endif
    if p(GRAPHTYPE) = GENERAL then
           = CRM_which_type(data,s,p,v,date)
    endif
    ="Bad graph type"
endmacro
                  
 
   
   
        



