c
c   Copyright (c) 1993 by Dwight Meglan
c
c     This program is copyrighted but may be freely distributed and various
c     sections used and/or modified by others under the following restrictions
c
c     1) When this code or some part is used proper attribution to the 
c        developers of this code- Dwight Meglan and the Gait Analysis Lab
c        of The Ohio State University- must be given.
c
c     2) If you make changes to the code and redistribute it subsequently,
c        these changes must be clearly described and marked.
c
c     3) This code must be provided free of charge if it is redistrbuted,
c        except for recovery of the cost of distribution.
c
c     4) NO part of this code may be included in any commercial software.
c        It may NOT be provided as an addon to a commercial product by the
c        manufacturer or distributor, even if no charge is made for it.
c
c     5) No profit should be derived from the use of this code. If it is used
c        in a clinical context, then cost recovery fees may be charged by the
c        user(s).
c
c     WARRANTY - THERE IS NONE !!
c
c     I, and the Ohio State University, take NO responsiblity for the accuracy
c     of the numerical calculations in this code. I accept NO liability for any 
c     difficulties resulting from the use of the results of this code.
c
c     SORRY for the heavy handed language but in this crazy world of finger
c     pointing lawsuits, you just never know what will happen...
c
c
c     This code is UNSUPPORTED. It has been used extensively in both clinical
c     and research contexts and I have tried to find all the bugs, but with 
c     something all encompassing there are bound to be some latent problems.
c     I am interested in hearing about uses of the code by others, improvements,
c     or problems indentified. I cannot help with debugging or teaching others
c     about what is in here. This is intended to be used as a teaching tool
c     for engineers primarily, not as a finished clinical product. In reality
c     it is being used as such and I am confident that it carries out this
c     role well, but I do not have the time or desire to support this as a
c     clinical product would require.
c
c     Comments can be sent to: Dwight Meglan, dmeglan@merle.acns.nwu.edu
c     Address should be valid until at least Spring/Summer 1994. I would prefer
c     email contact because of the potential for people calling me inspite
c     of all the disclaimers above.
c
c
c     NOTE
c     As of July 1993 there is a compatibility library based upon a public
c     domain graphics package named VOGLE which replaces the DI3000 calls.
c     This package just maps the DI3000 calls into equivalent VOGLE calls.
c     I have changed as many of the DI3000 calls to direct VOGLE calls as
c     possible. The VOGLE package runs on many platforms but has only been 
c     tested by myself with the PC version of Show3D
c
c
c  Debug statements are included in this file. They are activated by the 
c  /DEF=DEBUG compiler directive in the makefile. 
c  These compiler directives are specific to the watcom compiler.
c
      PROGRAM Telio
      implicit none 

      include 'vogle.fi'

      include 'tel_cons.inc'                                  
      include 'tel_strc.inc'
      include 'tel_file.inc'
      include 'tel_name.inc'
      include 'tel_grph.inc'
      include 'tel_3dvu.inc'
      include 'tel_plt.inc'
      include 'tel_chrt.inc'
c
c     Initialize name constants
c
      include 'tel_init.inc'

      integer*4 i,j    
      real*4    ratio
      logical*4 error,AllGraphs,done
      character line*80,ans*1
      
      record /CmndLine/    CMND
      record /MacroStuff/  MACRO

*$ifdef DEBUG
      common /debug_info/ CMND,MACRO
*$endif

c
c     Initialize file structure logical unit numbers
c
      FD(1).LU= 1
      FD(2).LU= 2
      FD(3).LU= 3
      FD(4).LU= 4
      FD(5).LU= 7
      FD(6).LU= 8
c
c     Initialize segment and joint names
c
      call SetUpFullBodyNames
c                    
c     Initialize graph options
c
      AllGraphs= .true.
      call ResetGrOpt( 1,AllGraphs )
c
c     Initialize Strip Chart options
c
      call ResetSChartOpt
c
c     Setup initial screen and print display state
c
      do i= 1, MAX_CHART
        GROPT(i).Print=  .false.
        GROPT(i).Screen= .true.
        GROPT(i).UsePostPrint= .false.
      end do
      CHOPT.Print=        .false.
      CHOPT.Screen=       .true.
      CHOPT.UsePostPrint= .true.
c                                   
c     Main Event Loop
c                       
      call SetupGraphics( ratio )  
      write(6,10)
10    format(32x,'Welcome to Telio'/
     &       25x,'A Human Motion Display System'//
     &       22x,'Copyright (c) by Dwight Meglan 1990'/
     &       17x,'The Ohio State University Gait Analysis Lab'//
     &       20x,'For Academic and Noncommercial use only'//)
      MACRO.On=   .false.
      MACRO.Echo= .true.
      NumFileOpen= 0             
 5    done= .false.
      do while ( .not. done )
        error= .false.       
        if ( .not. MACRO.On ) then
          do i= 1, 80                                           
            line(i:i)= ' '
          end do
          if ( .not. CMND.Continue ) then
            write(6,100)                                     
100         format(' telio> ',$)
          else
            write(6,105) CMND.NumLine + 1
105         format(' line',i1,'> ',$)
          end if
          read(5,110,end=99) line
110       format(a80)   
        else
          if ( Macro.Echo ) write(6,120) line
120       format(a80)                                 
        end if                            
99      call ParseLine( line,CMND )
        if ( (.not. CMND.Continue) .or.
     &       ( (CMND.Continue) .and. 
     &         ((CMND.CmndText(1) .eq. 'GRA') .or.
     &          (CMND.CmndText(1) .eq. 'SCH')     ) ) ) then
          if ( CMND.CmndText(1) .eq. 'GRA' ) then
            call DoGraph( CMND,MACRO,ratio,error )

          else if ( CMND.CmndText(1) .eq. 'SCH' ) then
            call DoStripChart( CMND,MACRO,ratio,error )
          
          else if ( (CMND.CmndText(1) .eq. '3DS') .or.
     &              (CMND.CmndText(1) .eq. '3DM')      ) then
            call Do3dView( CMND,MACRO,ratio,error )
                                   
          else if ( CMND.CmndText(1) .eq. 'HEL' ) then
            write(6,300)
300         format(/' Help has not been implemented yet'//)
c            call DisplayHelp

          else if ( CMND.CmndText(1) .eq. 'REA' ) then
            call ReadFileParam( CMND,error )
          
          else if ( CMND.CmndText(1) .eq. 'OPT' ) then
            call SetOptions( CMND,MACRO )
          
          else if ( CMND.CmndText(1) .eq. 'STA' ) then
            call ShowStatus( CMND )
          
          else if ( CMND.CmndText(1) .eq. 'MAC' ) then
            if ( .not. MACRO.On ) then
              call DoMacro( CMND,MACRO,error )
              MACRO.LineNum= 1       
            else                        
              MACRO.On= .false.
              write(6,220)
220           format(' Error- MACro command cannot be executed within a macro',
     &               ' itself...')
            end if
                                              
          else if ( (CMND.CmndText(1) .ne. 'END') .and. 
     &              (CMND.CmndText(1) .ne. 'BYE') .and.
     &              (CMND.CmndText(1) .ne. 'QUI') .and. 
     &              (CMND.CmndText(1) .ne. 'DON') .and.
     &              (CMND.CmndText(1) .ne. 'EXI')       ) then
            write(6,130)
130         format(' Error- Invalid command.  Valid commands are:'/
     &             '        REAd GRAph  Macro  StripCHart'/
     &             '        HELp OPTion STAtus END')

          else if ( (CMND.CmndText(1) .eq. 'END') .or.
     &              (CMND.CmndText(1) .eq. 'BYE') .or.
     &              (CMND.CmndText(1) .eq. 'QUI') .or.
     &              (CMND.CmndText(1) .eq. 'DON') .or.
     &              (CMND.CmndText(1) .eq. 'EXI')      ) then
            done= .true.
          end if
        end if ! not command line continued
        if ( MACRO.On .and. (.not. done) ) then
          if ( error ) then
            MACRO.On= .false.   
            write(6,240)
240         format(' Error- Macro execution terminated to due error...')
          else
            if ( MACRO.LineNum .le. MACRO.NumLines(MACRO.MacroNum) ) then
              line= MACRO.Text(MACRO.LineNum,MACRO.MacroNum)
              MACRO.LineNum= MACRO.LineNum + 1
            else
              MACRO.On= .false.
              if ( MACRO.Echo ) write(6,250)
250           format(' Macro completed...')
              MACRO.LineNum= 1
            end if          
          end if ! error
        end if ! MACRO.On
      end do ! while                     
      write(6,260)
260   format(' Do you want to exit telio ? (y/[n]) : ',$)
      read(5,270) ans
270   format(a1)                                            
      if ( (ans .ne. 'y') .and. (ans .ne. 'Y') ) goto 5
999   call dvexit
      write(6,500)
500   format(12(/),21x,'Leaving Telio.  Have a nice day :-)',11(/))
      STOP ' '
      END   
c
c   Copyright (c) 1993 by Dwight Meglan
c
      subroutine SetupGraphics(ratio)

      include 'vogle.fi'

      real*4 ratio

      call getdevices
      ratio= getaspect()
      call dviewport( -1.0,1.0,-ratio,ratio )
      call ortho2( -1.0,1.0,-ratio,ratio )
      call clipping( .TRUE. )
      call color(0)
      return
      end
c
c   Copyright (c) 1990 by Dwight Meglan
c
      subroutine ParseLine( line,CMND )
      implicit none

      include 'tel_cons.inc'
      include 'tel_strc.inc'                      

      character line*80
      record /CmndLine/ CMND

      integer*4 i,j,k,nc,LastChar,ns,ob,oe,slash(6)
      character MakeUpperCase*80,ACmnd*3
      logical*4 temp,MakeReal
c
c     First check whether this is a continuation line, a line to be continued,
c     or just a new line.  Also, find the first and last characters in the
c     line.
c
      if ( .not. CMND.Continue ) then ! zero out the CMND structure
        CMND.NumCmnd= 0
        CMND.NumLine= 0
        do i= 1, MAX_NUM_CMND
          CMND.CmndText(i)= '   '
          CMND.CmndNumOK(i)= .false.
          CMND.CmndIntVal(i)= 0
          CMND.CmndRealVal(i)= 0.0
          CMND.CmndStart(i)= 0
          CMND.CmndEnd(i)= 0
          CMND.NumOpt(i)=  0
          do j= 1, MAX_NUM_CMND_OPT
             CMND.OptText(j,i)= '   '
             CMND.OptNumOK(j,i)= .false.
             CMND.OptIntVal(j,i)= 0
             CMND.OptRealVal(j,i)= 0.0
             CMND.OptStart(j,i)= 0
             CMND.OptEnd(j,i)= 0
          end do
        end do
      end if 

      if ( CMND.NumLine .ge. MAX_NUM_CMND_LINES ) return ! no more than MAX_NUM_CMND_LINES lines 
      line= MakeUpperCase( line )                        ! of text allowed
      i= 80   
      do while( (i .gt. 0) .and. (line(i:i) .eq. ' ') )
        i= i - 1
      end do
      if ( i .eq. 0 ) return
      if ( line(i:i) .eq. '_' ) then !
        CMND.Continue= .true.
        LastChar= i - 1                 
      else
        CMND.Continue= .false.
        LastChar= i
      end if
      CMND.NumLine= CMND.NumLine + 1
      do i= 1, 80
        CMND.Text(CMND.NumLine)(i:i)= ' '
      end do
      CMND.Text(CMND.NumLine)= line(1:LastChar)
c
c     Now process each command checking each for options.  The commands
c     have the form: CMND1/OPT1/OPT2=3/OPT3/OPT4/OPT5 CMND2/OPT CMND3/...
c     where the options can be text, numbers or text=numbers depending upon
c     the situation.  Store the results for each in the CMND structure.
c     AT present the maximum number of commands is 50 with 5 options per
c     command allowable.
c
c     First isolate the command text
c
      i= 1
      do while ( (i .lt. LastChar) .and. (CMND.NumCmnd .lt. MAX_NUM_CMND) )
        do while ( (i .lt. LastChar) .and. (line(i:i) .eq. ' ') )
          i= i + 1
        end do     
        CMND.NumCmnd= CMND.NumCmnd + 1
        nc= CMND.NumCmnd
        CMND.CmndStart(nc)= i
        do while ( (i .le. LastChar) .and. (line(i:i) .ne. ' ') )
          i= i + 1
        end do
        CMND.CmndEnd(nc)= i - 1
        CMND.CmndText(nc)= '   '
        if ( (CMND.CmndEnd(nc)-CMND.CmndStart(nc)) .lt. 2 ) then
          CMND.CmndText(nc)= line(CMND.CmndStart(nc):CMND.CmndEnd(nc))
        else
          ACmnd= line(CMND.CmndStart(nc):CMND.CmndStart(nc)+2)
          if ( index(Acmnd,'/') .eq. 0 ) then
            CMND.CmndText(nc)= ACmnd
          else
            CMND.CmndText(nc)= ACmnd(1:index(ACmnd,'/')-1)
          end if
        end if
c
c       Now isolate the option text
c             
        j= CMND.CmndStart(nc)
        ns= 0 ! number of /'s
        do while ( (j .le. CMND.CmndEnd(nc)) .and. 
     &             (ns .lt. MAX_NUM_CMND_OPT+1)    )
          if ( (line(j:j) .eq. '/') .and. (ns .lt. MAX_NUM_CMND_OPT+1) ) then
            ns= ns + 1
            slash(ns)=j
          else if( (j .eq. CMND.CmndEnd(nc)) .and. 
     &             (ns .lt. MAX_NUM_CMND_OPT+1)        ) then
            ns= ns + 1
            slash(ns)= j+1
          end if
          j= j + 1
        end do ! find option delimiters- /'s
        if ( ns .gt. 1 ) then ! there are options present
          j= 1
          do while (j .lt. ns-1) ! check for zero length options
            if ( (slash(j+1)-slash(j)) .le. 1 ) then ! delete option
              do k= j, ns-1
                slash(k)= slash(k+1)
              end do
              ns= ns - 1
            end if
            j= j + 1
          end do
          CMND.NumOpt(nc)= ns-1
          if ( ns .lt. 1 ) CMND.NumOpt(nc)= 0
c
c         Check for = sign and if present isolate number following it
c
          do j= 1, ns-1
            ob= slash(j) + 1   ! option beginning position
            oe= slash(j+1) - 1 ! option ending position
            CMND.OptText(j,nc)= '   '
            CMND.OptStart(j,nc)= ob
            CMND.OptEnd(j,nc)=   oe
            k= ob + index(line(ob:oe),'=') - 1
            if ( k .gt. ob ) then         ! = present
              if ( (k - ob) .gt. 3 ) then
                CMND.OptText(j,nc)= line(ob:ob+2)
              else
                CMND.OptText(j,nc)= line(ob:k-1)
              end if
              CMND.OptNumOK(j,nc)= MakeReal(line,k+1,oe,CMND.OptRealVal(j,nc))
              if ( CMND.OptRealVal(j,nc) .gt. 2.0e9 ) then
                CMND.OptIntVal(j,nc)=  2e9
              else if ( CMND.OptRealVal(j,nc) .lt. -2.0e9 ) then
                CMND.OptIntVal(j,nc)= -2e9
              else
                CMND.OptIntVal(j,nc)= nint(CMND.OptRealVal(j,nc))
              end if
              CMND.OptEnd(j,nc)= k - 1
            else
              if ( (oe - ob) .gt. 2 ) then
                CMND.OptText(j,nc)= line(ob:ob+2)
              else
                CMND.OptText(j,nc)= line(ob:oe)
              end if
              CMND.OptNumOK(j,nc)= MakeReal(line,ob,oe,CMND.OptRealVal(j,nc))
              if ( CMND.OptRealVal(j,nc) .gt. 2.0e9 ) then
                CMND.OptIntVal(j,nc)=  2e9
              else if ( CMND.OptRealVal(j,nc) .lt. -2.0e9 ) then
                CMND.OptIntVal(j,nc)= -2e9
              else
                CMND.OptIntVal(j,nc)= nint(CMND.OptRealVal(j,nc))
              end if
            end if
          end do ! interpret option
        else ! no options
          CMND.NumOpt(nc)= 0
        end if ! options are present
        if ( CMND.NumOpt(nc) .gt. 0 ) CMND.CmndEnd(nc)= CMND.OptStart(1,nc)-2
        CMND.CmndNumOK(nc)= MakeReal(line,CMND.CmndStart(nc),CMND.CmndEnd(nc),
     &                               CMND.CmndRealVal(nc))     
        if ( CMND.CmndRealVal(nc) .gt. 2.0e9 ) then
          CMND.CmndIntVal(nc)=  2e9
        else if ( CMND.CmndRealVal(nc) .lt. -2.0e9 ) then
          CMND.CmndIntVal(nc)= -2e9
        else
          CMND.CmndIntVal(nc)= nint(CMND.CmndRealVal(nc))
        end if
      end do ! next command
      return
      end                              
c
c   Copyright (c) 1990 by Dwight Meglan
c
      function MakeUpperCase( string )
                
      character*(*) string,MakeUpperCase
      integer*4   i                          

      do i= 1, len(string)
        if ( (ichar(string(i:i)) .ge. ichar('a')) .and. 
     &       (ichar(string(i:i)) .le. ichar('z'))       )
     &     string(i:i)= char( ichar(string(i:i)) - ichar('a') + ichar('A') )
        MakeUpperCase(i:i)= string(i:i)
      end do                        
      return
      end
c
c   Copyright (c) 1990 by Dwight Meglan
c
      logical*4 function MakeReal(string,start,end,number)
      implicit none

      character string*80
      integer*4 start,end
      real*4    number,sign

      integer*4 first_char,last_char,numeral,decimal,i,power
                  
      MakeReal= .false. ! error
      if ( end .lt. start ) goto 999
      sign= 1.0
      first_char= start
      last_char=  end
      if ( string(first_char:first_char) .eq. '-' ) then
        sign= -1.0       
        first_char= first_char + 1
      end if
      if ( first_char .gt. last_char ) goto 999 ! trap case of a - only
      power= last_char - first_char
      decimal= index(string(first_char:last_char),'.')
      if ( decimal .ne. 0 ) power= decimal - 2
      number= 0.0
      do i= first_char, last_char
        if ( ((string(i:i) .lt. '0') .or. (string(i:i) .gt. '9')) .and.
     &       (string(i:i) .ne. '.')                                   ) goto 999
        if ( string(i:i) .ne. '.' ) then
          numeral= ichar(string(i:i)) - ichar('0')
          number= number + float(numeral)*10**float(power)
          power= power - 1              
        end if
      end do
      number= sign*number
      MakeReal= .true. ! no error   
      return
999   number= -999.0
      return
      end
c
c   Copyright (c) 1990 by Dwight Meglan
c
      subroutine DisplayHelp
      implicit none
      return
      end
c
c   Copyright (c) 1990 by Dwight Meglan
c
      subroutine DoMacro( CMND,MACRO,error )
      implicit none

      include 'tel_cons.inc'
      include 'tel_strc.inc'
                                       
      record /CmndLine/   CMND
      record /MacroStuff/ MACRO

      logical*4 error

      integer*4 i,j,end,start,bracket,ErrNum,MacroNum,NumLines,ierr
      character filename*40,input*80
      logical   Done,none,FirstLine
                                               
      MACRO.On= .false.                     
      if ( CMND.NumCmnd .lt. 2 ) goto 1000  ! error- not enough info
      if ( (CMND.CmndText(2) .eq. 'REA') .or.
     &     (CMND.CmndText(2) .eq. 'SAV')      ) then
        if ( CMND.NumCmnd .ge. 3 ) then ! there is a macro file name
          do i= 1, 40         
            filename(i:i)= ' '
          end do
          start= CMND.CmndStart(3)
          end=   CMND.CmndEnd(3)
          i= 1
          do while ( (i .le. 40) .and. (i+start-1 .le. end) )
            filename(i:i)= CMND.Text(1)(i+start-1:i+start-1)
            i= i + 1
          end do
        else
          write(6,100)
100       format(' Macro file name [.mac]: ',$)
          read(5,110) filename
110       format(a40)
        end if
c                                     
c       Add .MAC extension to file if no extension is present
c                
        i= 40                              
        end= 0
        do while ( (i .gt. 0) .and. (end .eq. 0) )
          if ( filename(i:i) .ne. ' ' ) end= i
          i= i-1                             
        end do
        if ( end .eq. 0 ) end= 1
        bracket= index(filename(1:end),'\') ! was ] in VMS
        if ( index(filename(bracket+1:end),'.') .eq. 0 ) 
     &     filename= filename(bracket:end)//'.mac'
        write(6,30)
 30     format(\'File: "',a40,'"'\)
        if ( CMND.CmndText(2) .eq. 'REA' ) then ! read in macros from file
          open( unit=2,file=filename,status='old',
     &          carriagecontrol='no',err=1010,iostat=ierr ) ! bad file name
          do i= 1, 10
            MACRO.OK(i)= .false.
            MACRO.NumLines(i)= 0
          end do
          ErrNum= 0                
          FirstLine= .true.                   
          do while( ErrNum .eq. 0 )
            do i= 1, 80
              input(i:i)= ' '
            end do
            read(2,120,iostat=ErrNum) input
120         format(a80)                            
            if ( ErrNum .eq. 0 ) then
              if ( (input(1:1) .ne. '#') .and. FirstLine ) goto 1020 ! bad macrofile^start
              if ( input(1:1) .eq. '#' ) then           
                FirstLine= .false.   
                MacroNum= ichar(input(2:2)) - ichar('0') ! macro number
                if ( (MacroNum .lt. 0) .or. 
     &               (MacroNum .gt. MAX_NUM_MACRO-1) ) goto 1060  ! bad macro number
                MacroNum= MacroNum + 1                  
                do j= 3, 80
                  MACRO.Description(MacroNum)(j-2:j-2)= input(j:j)
                end do                     
                NumLines= 0
                MACRO.NumLines(MacroNum)= 0
                MACRO.OK(MacroNum)= .true.
              else 
                NumLines= NumLines + 1
                if ( NumLines .le. MAX_NUM_MACRO_LINES ) then ! only first ten lines used
                  MACRO.NumLines(MacroNum)= NumLines
                  do i= 1, 80  
                    MACRO.Text(NumLines,MacroNum)(i:i)= input(i:i)
                  end do
                else if ( NumLines .eq. MAX_NUM_MACRO_LINES+1 ) then
                  write(6,123) MAX_NUM_MACRO_LINES,MacroNum,MAX_NUM_MACRO_LINES
123               format(' More than ',i2,' lines have been read for macro# ',i2,'.'/
     &                   ' Only the first ',i2,' lines of the macro will be used.'/)
                end if ! <= MAX_NUM_MACRO_LINES
              end if ! new macro or another line for present macro
            end if ! .not. at end of file
          end do ! while .not. at end of file -> ErrNum .ne. 0  
          close( unit=2 )
          write(6,124)
124       format(' Read Macro #''s :')
          do i= 1, 10
            if ( MACRO.OK(i) ) write(6,125) i-1,MACRO.Description(i)(1:65)
125         format('  ',i2,' : ',a65)
          end do
        else ! CMND.CmndText(2) = 'SAV'  save present macros
          open( unit=3,file=filename,status='new',
     &          carriagecontrol='no',err=1017,iostat=ierr )
          do MacroNum= 1, 10
            if ( MACRO.OK(MacroNum) ) then
              write(3,210) MacroNum-1,MACRO.Description(MacroNum)
210           format('#',i1,' ',a80)
              do j= 1, MACRO.NumLines(MacroNum)
                write(3,220) MACRO.Text(j,MacroNum)
220             format(a80)
              end do 
            end if ! Good Macro
          end do ! MacroNum
          close( unit=3 )
          write(6,126)
126       format(' Macro #''s saved')
          do i= 1, 10
            if ( MACRO.OK(i) ) write(6,127) i-1,MACRO.Description(i)(1:65)
127         format(' #',i2,' : ',a65)
          end do
        end if ! REA or SAV               
      else if ( CMND.CmndText(2) .eq. 'DEF' ) then
        if ( (CMND.CmndIntVal(3) .lt. 0) .or.
     &       (CMND.CmndIntVal(3) .gt. MAX_NUM_MACRO-1) ) goto 1040 ! bad macro #
        MacroNum= CMND.CmndIntVal(3)+1
        MACRO.NumLines(MacroNum)= 0
        MACRO.OK(MacroNum)= .true.
        write(6,136) MacroNum-1,MAX_NUM_MACRO_LINES
136     format(' Type in macro #',i1,' one line at a time.'/
     &         ' First line is a description of the macro'/
     &         ' Type "done" or Cntrl-Z when finished'/
     &         ' NOTE:  Macro limited to ',i2,' lines'/)
        Done= .false.
        write(6,128) 
128     format(' description : ',$)
        read(5,120,end=999) MACRO.Description(MacroNum)
        do while ( (MACRO.NumLines(MacroNum) .lt. MAX_NUM_MACRO_LINES) .and. 
     &             (.not. Done) )
          write(6,130) MACRO.NumLines(MacroNum)
130       format(' line',i2': ',$)            
          read(5,120,end=999) input
          if ( (input(1:2) .ne. 'do') .and. (input(1:2) .ne. 'DO') ) then
            MACRO.NumLines(MacroNum)= MACRO.NumLines(MacroNum) + 1
            do i= 1, 80
              MACRO.Text(MACRO.NumLines(MacroNum),MacroNum)(i:i)= input(i:i)
            end do
          else    
            Done= .true.
          end if      
        end do ! while NumLines <= MAX_NUM_MACRO_LINES
      else if ( CMND.CmndText(2) .eq. 'SHO' ) then
        if ( CMND.NumCmnd .eq. 2 ) then ! tell which macros are defined
          write(6,140)
140       format(' Macro #''s presently defined: ',$)            
          none= .true.                              
          do MacroNum= 1, MAX_NUM_MACRO
            if ( MACRO.OK(MacroNum) ) then
              write(6,150) MacroNum-1,MACRO.Description(MacroNum)(1:65)
150           format('  ',i2,' : ',a65)              
              none= .false.
            end if                    
          end do ! MacroNum
          if ( none ) then
            write(6,160)
160         format('+Macro #''s presently defined: none')
          end if
        else ! display a macro's contents
          MacroNum= CMND.CmndIntVal(3) + 1
          if ( (MacroNum .lt. 1) .or. 
     &         (MacroNum .gt. MAX_NUM_MACRO) ) goto 1040 ! bad
          if ( .not. MACRO.OK(MacroNum) ) goto 1050 ! macro not defined
          write(6,180) MacroNum-1,MACRO.Description(MacroNum)(1:65)
180       format(' Contents of macro #',i2/
     &           '  Description: ',a65)
          do i= 1, MACRO.NumLines(MacroNum)
            write(6,190) i,MACRO.Text(i,MacroNum)(1:65)
190         format('  line #',i2,': ',a65)
          end do
        end if                                          
      else ! assume that a macro is to be executed
        MacroNum= CMND.CmndIntVal(2) + 1
        if ( (MacroNum .lt. 1) .or. 
     &       (MacroNum .gt. MAX_NUM_MACRO) ) goto 1000 ! bad#
        if ( .not. MACRO.OK(MacroNum) ) goto 1050 ! macro not defined
        MACRO.MacroNum= MacroNum
        MACRO.LineNum= 1           
        MACRO.On= .true.                                    
      end if  ! cmnd(2) = 'REA','SAV','DEF','SHO' or macro #  
999   return
            
1000  write(6,1005)
1005  format(' Error- Invalid MACro command.'/
     &       '        Valid commands are: REAd DEFine SHOw or macro# to execute.'/
     &       '        SHOw alone will tell which macros are defined while providing'/
     &       '        a macro # will cause the macro''s contents to be displayed.')
      return                    
            
1010  write(6,1015) filename,ierr
1015  format(/' Error- Macro file named: ',a40/
     &       '        could not be read. Error number ',i4,' occurred')
      close( unit=2 )
      return
            
1017  write(6,1019) filename,ierr
1019  format(/' Error- Macro file named: ',a40/
     &       '        could be created. Error number ',i4,' occurred')
      close( unit=3 ) 
      return
            
1020  write(6,1025)
1025  format(' Error- A new macro in the input file must be proceeded by a "#"'/
     &       '        in the first column, but none was present in the first line'/
     &       '        read.  Please recheck the file...')
      return
      
1030  write(6,1035) MAX_NUM_MACRO
1035  format(' Only the first ',i2,' macros defined in the input file will be',
     &       ' used.')
      return          
                              
1040  write(6,1045) CMND.CmndText(3),MAX_NUM_MACRO-1
1045  format(' Error- ',a3,'is an invalid macro #'/
     &       '        Macro #''s must be between 0 and ',i2)
      return
                              
1050  write(6,1055) MacroNum-1
1055  format(' Error- Macro #',i1,' is not currently defined.')
      return                                                          
                     
1060  write(6,1065) input(2:2)
1065  format(' Error- The input macro file contains an incorrect macro number'/
     &       '        ',a1,' is the number which was read from the file.' )
      close(unit=2)
      return                  

1070  write(6,1075) MacroNum-1,MAX_NUM_MACRO-1
1075  format(' Error- Macro #',i1,' is not a valid macro number'/
     &       '        Valid macro #''s are 0 to ',i2)
      return                                                          
      end            
                            
                   
