c
c     Copyright (c) 1999,2000, Compaq Computer Corporation
c
c     See the file "license.terms" for information on usage and redistribution
c     of this file, and for a DISCLAIMER OF ALL WARRANTIES.
c
      subroutine save_plot
      implicit none
c
      include 'sysdep.cmn'
      include 'const.h'
      include 'plot.cmn'
      include 'units.cmn'
      include 'defaults.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'io.cmn'
c
      character*1 ans
      character*(PM_MAX_PATHLEN) savefile
      logical err, overwrite
c
      call clear_screen
      if( save_plot_type .eq. PLOT_NULL_COMMAND ) then
         write(luttyo,1000)
1000     format(' ',
     1   'Error: Plot type not supported, or no plot has been made')
         call get_char(ans,'Hit return to contine...',0)
      else
         savefile = savefilename
         call get_str_with_default(savefile,
     1     'Enter Postmini command file name: ',0)
c        Third argument says to overwrite any existing file (VMS only)
         overwrite = .FALSE.
         call write_savefile(savefile,current_window_id,overwrite,
     1                       err)
         if( .NOT. err ) savefilename = savefile
      endif
c
      return
      end
c
      subroutine read_savefile(savefile,annotations_only,err)
      implicit none
c
c     Read parameters from POSTMINI save file
c
      include 'sysdep.cmn'
      include 'const.h'
      include 'io.cmn'
      include 'plot.cmn'
      include 'units.cmn'
      include 'defaults.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'parser.cmn'
      include 'title.cmn'
c
      character*(*) savefile
      logical annotations_only, err
c
      integer ilen, string_len, current_command, current_axis,
     1        nrecl, ierr, ioerr
      logical check_command
c
      perr = .FALSE.
      iline = 0
      ibuf = LEN(buffer)
c
c     Try to open file
c
      nrecl=0
      call pm_open_file(savefil, savefile,
     1                  'OLD','FORMATTED','READ','LIST',
     2                  'NONSHARED',nrecl, ioerr, ierr)
      if( ierr .ne. 0 ) goto 4000
c
c     OK, file is opened, tell user we're reading it...
      ilen = string_len(savefile)
      write(luttyo,1001) savefile(1:ilen)
1001  format(' ','Reading Postmini command file:'/' ',a)
c
      if( .NOT. annotations_only ) then
         num_curves   = 0
         num_titles   = 0
         title_dat(1) = ' '
         current_command = PLOT_COMMAND
         save_plot_type    = PLOT_NULL_COMMAND
         save_plot_subtype = PLOT_COMPARE_XY_MODE
c        Define parser commands
         num_parse_commands = 8
c        NOTE WELL: Commands *MUST* be entered in array in upper case
c        Current definition of parse_command allows up to 10 commands
         parse_command(1) = 'PLOT'
         parse_command(2) = 'CURVE'
         parse_command(3) = 'AXIS'
         parse_command(4) = 'TITLE'
         parse_command(5) = 'CONTOUR'
         parse_command(6) = 'SURFACE'
         parse_command(7) = 'ANNOTATE'
         parse_command(8) = 'GLOBAL'
c        This call resets Postmini's color naming scheme.
         call pm_reset_colornames
      else
         current_command = ANNOTATE_COMMAND
c        Define parser commands
         num_parse_commands = 1
c        NOTE WELL: Commands *MUST* be entered in array in upper case
         parse_command(1) = 'ANNOTATE'
      endif
c
      current_axis = 1
      num_boxes = 0
      num_lines = 0
      num_text  = 0
      num_markers  = 0
      num_ellipses = 0
c
c     Set up parse of initial line
      feof = .FALSE.
      call next_line
c
c     Main parser loop:
c     Is the next keyword a command?
2000  if( feof ) goto 3000
      if( check_command() ) then
c     CURVE
      if( key .eq. 'CURVE' ) then
         current_command = CURVE_COMMAND
         if( num_curves+1 .gt. MAX_SAVE_CURVES ) then
            write(luttyo,2110) iline
2110        format(' ','Error on line ',i5,
     1                 ': Maximum number of curves exceeded')
            perr = .TRUE.
         else
            num_curves = num_curves + 1
         endif
         if( save_plot_type .ne. PLOT_1D_COMMAND .and.
     1       save_plot_type .ne. PLOT_COMPARE_COMMAND ) then
            write(luttyo,2111) iline
2111        format(' ','Error on line ',i5,
     1      ': CURVE command is only valid with 1D or COMPARE plot')
            perr = .TRUE.
         endif
         call parse_curve()
c
c     AXIS {X,Y,Z}
      else if( key .eq. 'AXIS' ) then
         current_command = AXIS_COMMAND
c        Set up a default axis in case user forgets (also for error recovery)
         current_axis = 1
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2200
         call upcase(item)
         if( item(1:1) .eq. 'X' ) then
            current_axis = 1
         elseif( item(1:1) .eq. 'Y') then
            current_axis = 2
         elseif( item(1:1) .eq. 'Z' ) then
             current_axis = 3
         else
            perr = .TRUE.
            write(luttyo,2120) iline
2120        format(' ','Error on line ',i5,
     1                 ': Unknown or invalid axis type')
         endif
c        Look for optional axis type {LEFT,RIGHT,BOTTOM,TOP}
         call get_keyword(buffer,item,ipos)
         if( ipos .ne. 0 ) then
c           Check for Z axis (special case)
            if( current_axis .eq. 3 ) then
               perr = .TRUE.
               write(luttyo,2120) iline
            else
               call upcase(item)
               if( current_axis .eq. 1 ) then
                  if( item(1:1) .eq. 'B' ) then
c                    No action, current_axis is already set correctly
                  else if( item(1:1) .eq. 'T' ) then
                     current_axis = 4
                  else
                     perr = .TRUE.
                     write(luttyo,2120) iline
                  endif
               else
                  if( item(1:1) .eq. 'L') then
c                    No action, current_axis is already set correctly
                  else if( item(1:1) .eq. 'R' ) then
                      current_axis = 5
                  else
                     perr = .TRUE.
                     write(luttyo,2120) iline
                  endif
               endif
            endif
         endif
         call parse_axis(current_axis)
c
c     PLOT {1D,2D,3D,COMPARE,OVERLAY}
      else if( key .eq. 'PLOT' ) then
         current_command = PLOT_COMMAND
c        Set up a default type in case user forgets (also for error recovery)
         save_plot_type    = PLOT_COMPARE_COMMAND
         save_plot_subtype = PLOT_COMPARE_XY_MODE
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2200
         call upcase(item)
         if( item(1:1) .eq. '1' ) then
            save_plot_type = PLOT_1D_COMMAND
            call pm_set_xy_colornames
         elseif( item(1:1) .eq. '2') then
            save_plot_type = PLOT_2D_COMMAND
            call pm_set_contour_colornames
         elseif( item(1:1) .eq. 'O') then
            save_plot_type = PLOT_OVERLAY_COMMAND
            call pm_set_contour_colornames
         elseif( item(1:1) .eq. '3' ) then
            save_plot_type = PLOT_3D_COMMAND
            call pm_set_contour_colornames
         elseif( item(1:1) .eq. 'C' ) then
            save_plot_type = PLOT_COMPARE_COMMAND
            save_plot_subtype = PLOT_COMPARE_XY_MODE
            call pm_set_xy_colornames
         elseif( item(1:1) .eq. 'B' ) then
c           This is the bar chart subtype of a comparison plot
            save_plot_type = PLOT_COMPARE_COMMAND
            save_plot_subtype = PLOT_COMPARE_BARCHART_MODE
            call pm_set_xy_colornames
         else
            perr = .TRUE.
            write(luttyo,2130) iline
2130        format(' ','Error on line ',i5,': Unknown plot type')
         endif
         call next_line
c
c     TITLE = {string}
      else if( key .eq. 'TITLE' ) then
         current_command = TITLE_COMMAND
         call get_str_start(buffer,ipos)
         if( num_titles+1 .GT. MAX_SAVE_TITLES ) then
            perr = .TRUE.
            write(luttyo,2140) iline
2140        format(' ','Error on line ',i5,': Too many titles')
         else
            num_titles = num_titles + 1
            if( ipos .eq. 0 ) then
               title_dat(num_titles) = ' '
            else
               title_dat(num_titles) = buffer(ipos:ibuf)
            endif
         endif
         call next_line
c
c     ANNOTATE {BOX,LINE,TEXT,MARKER,ELLIPSE}
      else if( key .eq. 'ANNOTATE' ) then
         current_command = ANNOTATE_COMMAND
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2200
         call upcase(item)
         if( item .eq. 'BOX' ) then
            if( num_boxes + 1 .gt. MAX_BOX_NOTES ) then
               write(luttyo,2150) iline, 'box'
2150           format(' ','Error on line ',i5,': too many ',a,' notes')
               perr = .TRUE.
            else
               num_boxes = num_boxes + 1
            endif
            box_notes_dat(num_boxes)%segment = iline
            call parse_box_note
         elseif( item .eq. 'LINE') then
            if( num_lines + 1 .gt. MAX_LINE_NOTES ) then
               write(luttyo,2150) iline, 'line'
               perr = .TRUE.
            else
               num_lines = num_lines + 1
            endif
            line_notes_dat(num_lines)%segment = iline
            call parse_line_note
         elseif( item .eq. 'TEXT' ) then
            if( num_text + 1 .gt. MAX_TEXT_NOTES ) then
               write(luttyo,2150) iline, 'text'
               perr = .TRUE.
            else
               num_text = num_text + 1
            endif
            text_notes_dat(num_text)%segment = iline
            call parse_text_note
         elseif( item .eq. 'MARKER' ) then
            if( num_markers + 1 .gt. MAX_MARKER_NOTES ) then
               write(luttyo,2150) iline, 'marker'
               perr = .TRUE.
            else
               num_markers = num_markers + 1
            endif
            marker_notes_dat(num_markers)%segment = iline
            call parse_marker_note
         elseif( item .eq. 'ELLIPSE' ) then
            if( num_ellipses + 1 .gt. MAX_LINE_NOTES ) then
               write(luttyo,2150) iline, 'ellipse'
               perr = .TRUE.
            else
               num_ellipses = num_ellipses + 1
            endif
            ellipse_notes_dat(num_ellipses)%segment = iline
            call parse_ellipse_note
         else
            write(luttyo,2151) iline, item
2151        format(' ','Error on line ',i5,
     1                 ': Unknown annotation type: ',a)
            perr = .TRUE.
            call next_line
         endif
c     CONTOUR
      else if( key .eq. 'CONTOUR' ) then
         current_command = CONTOUR_COMMAND
c        Store datafile elements in first position of curve data structure
         if( num_curves+1 .gt. MAX_SAVE_CURVES ) then
            write(luttyo,2110) iline
            perr = .TRUE.
         else
            num_curves = num_curves + 1
         endif
         if( save_plot_type .ne. PLOT_2D_COMMAND .and.
     1       save_plot_type .ne. PLOT_OVERLAY_COMMAND ) then
            write(luttyo,2160) iline
2160        format(' ','Error on line ',i5,
     1      ': CONTOUR command is only valid with 2D plot')
            perr = .TRUE.
         endif
         call parse_contour
c
c     SURFACE
      else if( key .eq. 'SURFACE' ) then
c        Store datafile elements in first position of curve data structure
         current_command = SURFACE_COMMAND
         num_curves = 1
         if( save_plot_type .ne. PLOT_3D_COMMAND ) then
            write(luttyo,2170) iline
2170        format(' ','Error on line ',i5,
     1      ': SURFACE command is only valid with 3D plot')
            perr = .TRUE.
         endif
         call parse_surface
c
c     GLOBAL
      else if( key .eq. 'GLOBAL' ) then
         call parse_global
      else
c        This shouldn't happen, unless we define a command and don't
c        put in a case for it above...
         write(luttyo,2180) iline, key(1:klen)
2180     format(' ','Error on line ',i5,
     1              ': Unknown command "',a,'"')
         perr = .TRUE.
         call next_line
      endif
      else
         write(luttyo,2180) iline, key(1:klen)
         perr = .TRUE.
         call next_line
      endif
c
c     Parse next line
      goto 2000
c
c     Error on read of values
2200  call perror_write(2, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 2000
c
3000  close(unit=savefil)
      err = perr
c
      goto 5000
c
4000  continue
      ilen = string_len(savefile)
      write(luttyo,4001) savefile(1:ilen)
4001  format(' ','Error: could not open command file: '/' ',a)
      err = .TRUE.
c
5000  continue
c     Reset color name scheme if restore failed...
      if( err .and. annotations_only ) call pm_reset_colornames
      return
      end
c
      subroutine write_savefile(savefile,annotate_window_id,overwrite,
     1                          err)
      implicit none
c
c     Write parameters to POSTMINI save file
c
      include 'sysdep.cmn'
      include 'const.h'
      include 'io.cmn'
      include 'plot.cmn'
      include 'units.cmn'
      include 'defaults.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'title.cmn'
c
      integer annotate_window_id
      character*(*) savefile
      logical overwrite, err
c
      logical axis_used
      integer i, j, ilen, ilen2, ilen3, string_len, icolor, iline,
     1        itype, ioerr, ierr, nrecl
      integer istat, pm_put_error_msg, pm_put_info_msg
      character*10 axis_type
      character*16 ch_tmp
      character*32 tmp_color, fontname
      character*8 anal_type(3)
      data anal_type /'F(X)', 'F(X,P)', 'F(X,Y)'/
c
      err = .FALSE.
      call pm_clear_error_msg
c
c     Check input window id
      if( annotate_window_id .ne. -1 ) then
         call copy_annotations_to_save(annotate_window_id)
      endif
c
c     Try to open file
c
      if( overwrite ) then
         nrecl=0
         call pm_open_file(savefil, savefile,
     1                     'UNKNOWN','FORMATTED','READWRITE','LIST',
     2                     'NONSHARED',nrecl, ioerr, ierr)
         if( ierr .ne. 0 ) goto 6000
         rewind(unit=savefil)
      else
         nrecl=0
         call pm_open_file(savefil, savefile,
     1                     'NEW','FORMATTED','READWRITE','LIST',
     2                     'NONSHARED',nrecl, ioerr, ierr)
            if( ierr .ne. 0 ) goto 6000
      endif
c
c     OK, file is opened, tell user we're reading it...
      ilen = string_len(savefile)
      istat = pm_put_info_msg('Writing Postmini command file:')
      istat = pm_put_info_msg(savefile(1:ilen))
c
c     Header
      write(savefil,1003,err=6100)
1003  format('!!'/
     1       '!!   Postmini command file'/
     2       '!!')
c
      if( save_plot_type .eq. PLOT_1D_COMMAND ) then
         ch_tmp = 'PLOT 1D'
      else if( save_plot_type .eq. PLOT_2D_COMMAND ) then
         ch_tmp = 'PLOT 2D'
      else if( save_plot_type .eq. PLOT_OVERLAY_COMMAND ) then
         ch_tmp = 'PLOT OVERLAY'
      else if( save_plot_type .eq. PLOT_3D_COMMAND ) then
         ch_tmp = 'PLOT 3D'
      else if( save_plot_type .eq. PLOT_COMPARE_COMMAND .and.
     1         save_plot_subtype .eq. PLOT_COMPARE_XY_MODE ) then
         ch_tmp = 'PLOT COMPARE'
      else if( save_plot_type .eq. PLOT_COMPARE_COMMAND .and.
     1         save_plot_subtype .eq. PLOT_COMPARE_BARCHART_MODE ) then
         ch_tmp = 'PLOT BARCHART'
      endif
      write(savefil,1004) ch_tmp
1004  format(' ',a)
c
      write(savefil,1501)
1501  format('!!')
      do 1500 i=1,num_titles
         ilen = string_len(title_dat(i))
c        Do not write out title if it is empty (and only one title)
         if( .NOT. (ilen .eq. 0 .and. num_titles .eq. 1) )
     1   write(savefil,1502) title_dat(i)(1:ilen)
1502     format(' ','TITLE = ',a)
1500  continue
c
c     GLOBAL Command
c
      write(savefil,1601)
1601  format('!!'/
     1       ' ','GLOBAL')
      if( default_hidden_method .eq. 1 ) write(savefil,1602)
1602  format(' ','HIDDEN_LINE_METHOD = COLOR_BANDS')
      if( default_hidden_method .eq. 2 ) write(savefil,1603)
1603  format(' ','HIDDEN_LINE_METHOD = HIDDEN_LINE')
      if( default_hidden_method .eq. 3 ) write(savefil,1604)
1604  format(' ','HIDDEN_LINE_METHOD = HISTOGRAM')
      if( plot_scale_factor .ne. PM_DEF_WS_WINDOW_SIZE )
     1   write(savefil,1605) plot_scale_factor
1605  format(' ','PLOT_SCALE_FACTOR = ',1PE12.5)
      if( global_linewidth_scale .ne. 1.0 )
     1   write(savefil,1606) global_linewidth_scale
1606  format(' ','LINEWIDTH_SCALE = ',1PE12.5)
c!!
c!!   The next two items use the defaults in INIT_COMMON.FOR
c!!   If you change INIT_COMMON.FOR, you should change them here.
c!!
      if( ps_font_id .ne. -107 ) then
         call pm_lookup_psfontid(ps_font_id,fontname)
         write(savefil,1608) fontname
1608     format(' ','PS_FONT_ID = ',a)
      endif
      if( default_font_id .ne. -9 ) write(savefil,1609) default_font_id
1609  format(' ','FONT_ID = ',I10)
c
      do 1610 i=0,MAX_RGB_VALUES
         if( l_rgb(i) ) then
           if( color_names(i)(1:11) .eq. 'userdefined' ) then
              if( i .le. 9 ) then
                 write(savefil,1611) i, rgb(i,1),rgb(i,2),rgb(i,3)
1611             format(' ','COLOR_',i1,' = ',3f10.2)
              else
                 write(savefil,1612) i, rgb(i,1),rgb(i,2),rgb(i,3)
1612             format(' ','COLOR_',i2,' = ',3f10.2)
              endif
           else
              if( i .le. 9 ) then
                 write(savefil,1613) i, color_names(i)
1613             format(' ','COLOR_',i1,' = ',a32)
              else
                 write(savefil,1614) i, color_names(i)
1614             format(' ','COLOR_',i2,' = ',a32)
              endif
           endif
         endif
1610  continue
      if( pm_scale_plot2cm .ne. 1.0E-4 .or.
     1    pm_length_unit   .ne. 'microns')
     1   write(savefil,1615) pm_length_unit, pm_scale_plot2cm
1615  format(' ','LENGTH_UNIT_NAME_AND_SCALE = ',a,1PE12.5)
      if( global_text_scale .ne. 1.0 )
     1   write(savefil,1616) global_text_scale
1616  format(' ','TEXT_SCALE = ',1PE12.5)
      if( comp_nolabels )
     1   write(savefil,1617)
1617  format(' ','SUPPRESS_LABELS')
      if( l_curv )
     1   write(savefil,1618)
1618  format(' ','CURV_MODE')
c
      if( .NOT. hc_is_landscape ) write(savefil,1619)
1619  format(' ','HC_ORIENTATION = PORTRAIT')
      if( hc_scale .ne. 1.0 ) write(savefil,1620) hc_scale
1620  format(' ','HC_SCALE_FACTOR = ',1PE12.5)
      if( hc_aspect_ratio .ne. 0.77 ) write(savefil,1621)
     1                                hc_aspect_ratio
1621  format(' ','HC_ASPECT_RATIO = ',1PE12.5)
      if( hc_xoffset .ne. 0.0 ) write(savefil,1622) hc_xoffset
1622  format(' ','HC_XOFFSET = ',1PE12.5)
      if( hc_yoffset .ne. 0.0 ) write(savefil,1623) hc_yoffset
1623  format(' ','HC_YOFFSET = ',1PE12.5)
      if( left_unit_delim .ne. '(' .or. right_unit_delim .ne. ')' )
     1   write(savefil,1624) left_unit_delim, right_unit_delim
1624  format(' ','UNIT_DELIMITERS = ',2a1)
c
c     AXIS Commands
c
      do 2000 i=1,MAX_AXES
         axis_used = .FALSE.
         if( i .eq. 1 .and. axis_dat(i)%used ) then
            axis_type = 'X'
            axis_used = .TRUE.
         else if( i .eq. 2 .and. axis_dat(i)%used ) then
            axis_type = 'Y'
            axis_used = .TRUE.
         else if( i .eq. 3 .and. axis_dat(i)%used ) then
            axis_type = 'Z'
            axis_used = .TRUE.
         else if( i .eq. 4 .and. axis_dat(i)%used ) then
            axis_type = 'X TOP'
            axis_used = .TRUE.
         else if( i .eq. 5 .and. axis_dat(i)%used ) then
            axis_type = 'Y RIGHT'
            axis_used = .TRUE.
         endif
c        If axis is not used, then skip to next axis
         if( .NOT. axis_used ) goto 2000
c
         write(savefil,2001) axis_type
2001     format('!!'/' ','AXIS ',a)
         write(savefil,2002) axis_dat(i)%min, axis_dat(i)%max
2002     format(' ','MIN = ',1PE12.5/
     1          ' ','MAX = ',1PE12.5)
         ilen  = string_len(axis_dat(i)%label)
         if( ilen .gt. 0 ) then
            write(savefil,2003) axis_dat(i)%label(1:ilen)
2003        format(' ','LABEL = ',a)
         endif
         ilen = string_len(axis_dat(i)%units)
         if( ilen .gt. 0 ) then
            write(savefil,2004) axis_dat(i)%units(1:ilen)
2004        format(' ','UNITS = ',a)
         endif
         if( axis_dat(i)%log ) then
            write(savefil,2005)
2005        format(' ','LOG')
            if( save_plot_type .eq. PLOT_3D_COMMAND .and.
     1          i .eq. 3 ) then
               write(savefil,2006) axis_dat(i)%minor_tic_freq
2006        format(' ','LOG_TIC_FREQ = ',I10)
            endif
         else
            write(savefil,2007) axis_dat(i)%major_tic,
     1                          axis_dat(i)%minor_tic_freq,
     2                          axis_dat(i)%exp
2007        format(' ','MAJOR_TIC = ',1PE12.5/
     3             ' ','MINOR_TIC_FREQ = ',I10/
     4             ' ','EXPONENT = ',I10)
         endif
         if( axis_dat(i)%abs ) then
            write(savefil,2008)
2008        format(' ','ABS')
         endif
         if( axis_dat(i)%major_grid ) then
            write(savefil,2009) axis_dat(i)%major_grid_linetype
2009        format(' ','MAJOR_GRID'/
     1             ' ','MAJOR_GRID_LINETYPE = ',i5)
         endif
         if( axis_dat(i)%minor_grid ) then
            write(savefil,2010) axis_dat(i)%minor_grid_linetype
2010        format(' ','MINOR_GRID'/
     1             ' ','MINOR_GRID_LINETYPE = ',i5)
         endif
         if( axis_dat(i)%thickness .ne. 1.0 ) then
            write(savefil,2011) axis_dat(i)%thickness
2011        format(' ','THICKNESS = ',1PE12.5)
         endif
         if( string_len(axis_dat(i)%format) .ne. 0 ) then
            write(savefil,2012) axis_dat(i)%format
2012        format(' ','FORMAT = ',a)
         endif
         if( axis_dat(i)%nonumbering ) then
            write(savefil,2013)
2013        format(' ','NONUMBERING')
         endif
         if( axis_dat(i)%omit ) then
            write(savefil,2014)
2014        format(' ','OMIT')
         endif
         if( axis_dat(i)%color .ne. 1 ) then
            icolor = MIN(MAX(axis_dat(i)%color,MAX_RGB_VALUES),0)
            write(savefil,2015) color_names(icolor)
2015        format(' ','COLOR = ',a32)
         endif
         if( axis_dat(i)%minor_tic_size .ne. 0.025 ) then
            write(savefil,2016) 100.0*axis_dat(i)%minor_tic_size
2016        format(' ','MINOR_TIC_SIZE = ',1PE12.5)
         endif
         if( axis_dat(i)%major_tic_factor .ne. 2.0 ) then
            write(savefil,2017) axis_dat(i)%major_tic_factor
2017        format(' ','MAJOR_TIC_FACTOR = ',1PE12.5)
         endif
         if( axis_dat(i)%invert ) then
            write(savefil,2018)
2018        format(' ','INVERT')
         endif
2000  continue
c
c     CURVE commands
c
      if( save_plot_type .eq. PLOT_COMPARE_COMMAND .OR.
     1    save_plot_type .eq. PLOT_1D_COMMAND ) then
c        Curve data
         do 3000 i=1,num_curves
            write(savefil,3001)
3001        format('!!'/' ','CURVE')
            ilen  = string_len(curve_dat(i)%datafile)
            ilen2 = MAX(1,string_len(curve_dat(i)%label))
            ilen3 = string_len(curve_dat(i)%datafile_type)
            icolor = MAX(MIN(curve_dat(i)%color,MAX_RGB_VALUES),0)
            tmp_color = color_names(icolor)
            if( icolor .eq. 0 ) tmp_color = 'none'
            iline=MAX(MIN(curve_dat(i)%linetype,MAX_LINETYPE_VALUES),0)
            if(curve_dat(i)%datafile_type.ne.SAVE_DATATYPE_CALLABLE
     1         .and.
     1         curve_dat(i)%datafile_type.ne.SAVE_DATATYPE_CALLABLE_XY
     1         .and.
     1         curve_dat(i)%datafile_type.ne.SAVE_DATATYPE_ANALYTICAL )
     1      then
               write(savefil,3002) curve_dat(i)%datafile(1:ilen)
3002           format(' ','DATAFILE = ',a)
            endif
            write(savefil,3003) curve_dat(i)%datafile_type(1:ilen3),
     1                          curve_dat(i)%label(1:ilen2),
     2                          tmp_color,
     3                          line_names(iline),
     4                          curve_dat(i)%linewidth
3003        format(' ','DATAFILE_TYPE = ',a/
     1             ' ','LABEL = ',a/
     2             ' ','COLOR = ',a32/
     3             ' ','LINETYPE  = ',a32/
     4             ' ','LINEWIDTH = ',1pe12.5)
            if( curve_dat(i)%markercolor .ne. 0 .and.
     1          curve_dat(i)%markertype .ne. 0 ) then
               icolor = MAX(MIN(curve_dat(i)%markercolor,
     1                          MAX_RGB_VALUES),0)
               itype  = MAX(MIN(curve_dat(i)%markertype,
     1                          MAX_SYMBOL_VALUES),0)
               write(savefil,3004) symbol_names(itype),
     2                             color_names(icolor),
     3                             curve_dat(i)%markersize
3004           format(' ','MARKER_TYPE = ',a32/
     1                ' ','MARKER_COLOR = ',a32/
     2                ' ','MARKER_SIZE = ',1PE12.5)
            endif
c
            if( curve_dat(i)%xaxis_tag .eq. 2 ) then
               write(savefil,3005)
3005           format(' ','XAXIS_TAG = TOP')
            endif
            if( curve_dat(i)%yaxis_tag .eq. 2 ) then
               write(savefil,3006)
3006           format(' ','YAXIS_TAG = RIGHT')
            endif
c           We always write AX/AY/MX/MY now that we allow all data
c           to be scaled.
            ilen = string_len(curve_dat(i)%x_expression)
            if( ilen .ne. 0 ) then
               write(savefil,3007) curve_dat(i)%x_expression(1:ilen)
3007           format(' ','X_EXPRESSION = ',a)
            else
               write(savefil,3008) curve_dat(i)%ax, curve_dat(i)%mx
3008           format(' ','AX = ',1PE12.5/,' ','MX = ',1PE12.5)
            endif
            ilen = string_len(curve_dat(i)%y_expression)
            if( ilen .ne. 0 ) then
               write(savefil,3009) curve_dat(i)%y_expression(1:ilen)
3009           format(' ','Y_EXPRESSION = ',a)
            else
               write(savefil,3010) curve_dat(i)%ay, curve_dat(i)%my
3010           format(' ','AY = ',1PE12.5/,' ','MY = ',1PE12.5)
            endif
            if( curve_dat(i)%bin_datatype .eq.
     1          BINFILE_TYPE_BIG_ENDIAN_IEEE) then
               write(savefil,3011)
3011           format(' ','BINARY_TYPE = BIG_ENDIAN')
            endif
c       
         if( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_ASCII .and.
     1       curve_dat(i)%datafile_dimension .eq. 1 ) then
            write(savefil,3012) curve_dat(i)%datafile_dimension,
     1                          curve_dat(i)%colx
3012        format(' ','DATAFILE_DIMENSION = ',i5/
     1             ' ','COL_X = ',i10)
            if( curve_dat(i)%coly(1) .eq. -1 ) then
c              Special case for "ALL" columns
               write(savefil,3013)
3013           format(' ','ALL')
            else
               write(savefil,3014)
     1            (curve_dat(i)%coly(j),j=1,curve_dat(i)%n_ycols)
3014           format(' ','COL_Y = ',100i4)
            endif
            write(savefil,3015) curve_dat(i)%skip
3015        format(' ','SKIP_LINES = ',i10)
            if( curve_dat(i)%lines_to_read .gt. 0 ) then
               write(savefil,3016) curve_dat(i)%lines_to_read
3016           format(' ','READ_LINES = ',i10)
            endif
            if( curve_dat(i)%sweep ) write(savefil,3017)
3017        format(' ','SWEEP')
            if( curve_dat(i)%xabs ) write(savefil,3018)
3018        format(' ','XABS')
            if( curve_dat(i)%yabs ) write(savefil,3019)
3019        format(' ','YABS')
            if( curve_dat(i)%sort ) write(savefil,3020)
3020        format(' ','SORT')
            if( curve_dat(i)%x_char_data ) write(savefil,3021)
3021        format(' ','CHARACTER_DATA_IN_X_COL')
            if( curve_dat(i)%sample_freq .gt. 1 )
     1         write(savefil,3022) curve_dat(i)%sample_freq
3022        format(' ','SAMPLE_FREQ = ',i10)
            if( curve_dat(i)%datafile_record .gt. 1 )
     1         write(savefil,3023) curve_dat(i)%datafile_record
3023        format(' ','DATAFILE_RECORD = ',i10)
            if( curve_dat(i)%merge_ycols)
     1         write(savefil,3024)
3024        format(' ','MERGE_Y_COLUMN_DATA')
            if( curve_dat(i)%contour ) then
               write(savefil,3025) curve_dat(i)%colz,
     1             curve_dat(i)%az, curve_dat(i)%mz
3025           format(' ','ZSORT'/
     1                ' ','COL_Z = ',I10/
     2                ' ','AZ = ',1PE12.5/
     3                ' ','MZ = ',1PE12.5)
               if( curve_dat(i)%zabs ) write(savefil,3026)
3026           format(' ','ZABS')
            else if( curve_dat(i)%errorbars ) then
               write(savefil,3027) curve_dat(i)%colz,
     1             curve_dat(i)%az, curve_dat(i)%mz
3027           format(' ','ERRORBARS'/
     1                ' ','COL_Z = ',I10/
     2                ' ','AZ = ',1PE12.5/
     3                ' ','MZ = ',1PE12.5)
               if( curve_dat(i)%zabs ) write(savefil,3026)
            endif
         elseif( curve_dat(i)%datafile_type .eq.
     1           SAVE_DATATYPE_CALLABLE     .or.
     2           curve_dat(i)%datafile_type .eq. 
     3           SAVE_DATATYPE_CALLABLE_XY ) then
            if( curve_dat(i)%sweep ) then
               write(savefil,3017)
            endif
         elseif( curve_dat(i)%datafile_type .eq.
     1           SAVE_DATATYPE_GRAPES ) then
            ilen = string_len(curve_dat(i)%datafile_quantity)
            write(savefil,3028) curve_dat(i)%datafile_quantity(1:ilen),
     1                          curve_dat(i)%datafile_record
3028        format(' ','DATAFILE_QUANTITY = ',a/
     1             ' ','DATAFILE_RECORD = ',i5)
            ilen = string_len(curve_dat(i)%misc_ch(1))
            write(savefil,3029) curve_dat(i)%misc_ch(1)(1:ilen)
3029           format(' ','GRAPES_XAXIS_QUANTITY = ',a)
            if( curve_dat(i)%use_grapes_dict ) then
               write(savefil,3030)
3030           format(' ','USE_GRAPES_DICTIONARY')
            endif
         elseif( curve_dat(i)%datafile_type .eq.
     1           SAVE_DATATYPE_SPICE3 ) then
            ilen = string_len(curve_dat(i)%datafile_quantity)
            write(savefil,3031) curve_dat(i)%datafile_quantity(1:ilen),
     1                          curve_dat(i)%datafile_record
3031        format(' ','DATAFILE_QUANTITY = ',a/
     1             ' ','DATAFILE_RECORD = ',i5)
            ilen = string_len(curve_dat(i)%misc_ch(1))
            write(savefil,3032) curve_dat(i)%misc_ch(1)(1:ilen)
3032           format(' ','SPICE3_XAXIS_QUANTITY = ',a)
         elseif( curve_dat(i)%datafile_type .eq.
     1           SAVE_DATATYPE_ANALYTICAL   .and.
     1           curve_dat(i)%datafile_dimension .eq. 1 ) then
            ilen  = string_len(curve_dat(i)%analytical_expression)
            ilen2 = string_len(curve_dat(i)%datafile_quantity)
            write(savefil,3050)
     1         curve_dat(i)%analytical_expression(1:ilen),
     1         anal_type(curve_dat(i)%analytical_type),
     1         curve_dat(i)%datafile_quantity(1:ilen2),
     1         curve_dat(i)%datafile_dimension,
     1         curve_dat(i)%analytical_xstart,
     1         curve_dat(i)%analytical_xend,
     1         curve_dat(i)%analytical_xstep
3050        format(' ','ANALYTICAL_EXPRESSION = ',a/
     1             ' ','ANALYTICAL_FUNCTION_TYPE = ',a/
     1             ' ','DATAFILE_QUANTITY = ',a/
     1             ' ','DATAFILE_DIMENSION = ',i3/
     1             ' ','ANALYTICAL_XSTART  = ',1pe12.5/
     1             ' ','ANALYTICAL_XEND    = ',1pe12.5/
     1             ' ','ANALYTICAL_XSTEP   = ',1pe12.5)
            if(curve_dat(i)%analytical_type .eq. 2 )then
               write(savefil,3051)
     1            curve_dat(i)%analytical_pstart,
     1            curve_dat(i)%analytical_pend,
     1            curve_dat(i)%analytical_pstep
3051           format(' ','ANALYTICAL_PSTART  = ',1pe12.5/
     1                ' ','ANALYTICAL_PEND    = ',1pe12.5/
     1                ' ','ANALYTICAL_PSTEP   = ',1pe12.5)
            endif
            if( curve_dat(i)%sweep ) write(savefil,3017)
         elseif( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_TIF .and.
     1           curve_dat(i)%datafile_dimension .eq. 1 ) then
            write(savefil,3045) curve_dat(i)%colx,
     1                          curve_dat(i)%coly(1)
3045        format(' ','DATAFILE_DIMENSION = 1'/
     1             ' ','COL_X = ',i10/
     1             ' ','COL_Y = ',i10)
         else
c
c           This section for 1D cuts of 2D datasets
            ilen = string_len(curve_dat(i)%datafile_quantity)
            write(savefil,3033) curve_dat(i)%datafile_quantity(1:ilen),
     1                          curve_dat(i)%datafile_record
3033        format(' ','DATAFILE_QUANTITY = ',a/
     1             ' ','DATAFILE_RECORD = ',i5)
            if( curve_dat(i)%int ) then
               write(savefil,3034) curve_dat(i)%cut_line_axis,
     1            pm_scale_cm2plot*curve_dat(i)%int_limits(1),
     2            pm_scale_cm2plot*curve_dat(i)%int_limits(2)
3034           format(' ','INTEGRATED'/
     1                ' ','INTEGRATION_DIRECTION = ',a/
     2                ' ','INTEGRATION_LIMITS = ',1pe12.5,3x,1pe12.5)
            elseif( curve_dat(i)%oxide ) then
               write(savefil,3035)
     1            pm_scale_cm2plot*curve_dat(i)%cut_line_coord
3035           format(' ','ALONG_OXIDE'/
     1                ' ','OXIDE_OFFSET = ',1PE12.5)
            else
               write(savefil,3036) curve_dat(i)%cut_line_axis,
     1            pm_scale_cm2plot*curve_dat(i)%cut_line_coord
3036           format(' ','CUT_LINE_AXIS = ',a/
     1                ' ','CUT_LINE_COORD = ',1PE12.5)
            endif
            if( (curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_MINIMOS
     1      .or. curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_2DOP)
     2         .and. curve_dat(i)%datafile_dimension .eq. 3 ) then
            write(savefil,3037) curve_dat(i)%cut_plane_axis,
     2         pm_scale_cm2plot*curve_dat(i)%cut_plane_coord
3037        format(' ','DATAFILE_DIMENSION = 3'/
     1             ' ','CUT_PLANE_AXIS = ',a/
     2             ' ','CUT_PLANE_COORD = ',1PE12.5)
            endif
            if( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_2DOP) then
               write(savefil,3038) curve_dat(i)%misc(1)*CM2MU
3038           format(' ','DOPFILE_GATE_LENGTH = ',1PE12.5)
               ilen = string_len(curve_dat(i)%misc_ch(1))
               if( ilen .ne. 0 ) then
                  write(savefil,3039) curve_dat(i)%misc_ch(1)(1:ilen)
3039              format(' ','DOPFILE_INTERFACE_FILE = ',a)
               endif
            endif
            if( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_VLSICAP)
     1         then
               write(savefil,3040) curve_dat(i)%misc(1),
     1                             curve_dat(i)%misc(2)
3040           format(' ','VLSICAP_GATE_EDGE = ',1PE12.5/
     1                ' ','VLSICAP_SI_SIO2_INTERFACE = ',1PE12.5)
            endif
            if( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_MEDICI)
     1         then
               ilen = string_len(curve_dat(i)%misc_ch(1))
               if( ilen .ne. 0 ) then
                  write(savefil,3041) curve_dat(i)%misc_ch(1)(1:ilen)
3041              format(' ','MEDICI_SOLUTION_FILE = ',a)
               endif
            endif
            if( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_PISCES)
     1         then
               ilen = string_len(curve_dat(i)%misc_ch(1))
               if( ilen .ne. 0 ) then
                  write(savefil,3042) curve_dat(i)%misc_ch(1)(1:ilen)
3042              format(' ','PISCES_SOLUTION_FILE = ',a)
               endif
            endif
            if( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_ASCII )
     1         then
               write(savefil,3043) curve_dat(i)%az, curve_dat(i)%mz,
     1                          curve_dat(i)%colx,
     1                          curve_dat(i)%coly(1),
     1                          curve_dat(i)%colz,
     1                          curve_dat(i)%skip
3043           format(' ','DATAFILE_DIMENSION = 2'/
     1                ' ','AZ = ',1PE12.5/,' ','MZ = ',1PE12.5/
     1                ' ','COL_X = ',i10/
     1                ' ','COL_Y = ',i10/
     1                ' ','COL_Z = ',i10/
     1                ' ','SKIP_LINES = ',i10)
               if( curve_dat(i)%lines_to_read .gt. 0 ) then
                  write(savefil,3016) curve_dat(i)%lines_to_read
               endif
               if( curve_dat(i)%data_is_trigrid ) then
                  write(savefil,3044)
3044              format(' ','UNSTRUCTURED_DATA')
               endif
            endif
            if( curve_dat(i)%datafile_type .eq.
     1           SAVE_DATATYPE_ANALYTICAL   ) then
               ilen = string_len(curve_dat(i)%analytical_expression)
               ilen2 = string_len(curve_dat(i)%datafile_quantity)
               write(savefil,3050)
     1            curve_dat(i)%analytical_expression(1:ilen),
     1            anal_type(curve_dat(i)%analytical_type),
     1            curve_dat(i)%datafile_quantity,
     1            curve_dat(i)%datafile_dimension,
     1            curve_dat(i)%analytical_xstart,
     1            curve_dat(i)%analytical_xend,
     1            curve_dat(i)%analytical_xstep
               write(savefil,3052)
     1               curve_dat(i)%analytical_ystart,
     1               curve_dat(i)%analytical_yend,
     1               curve_dat(i)%analytical_ystep
3052           format(' ','ANALYTICAL_YSTART  = ',1pe12.5/
     1                ' ','ANALYTICAL_YEND    = ',1pe12.5/
     1                ' ','ANALYTICAL_YSTEP   = ',1pe12.5)
            endif
         endif
c
3000     continue
c
      else if( save_plot_type .eq. PLOT_2D_COMMAND .or.
     1         save_plot_type .eq. PLOT_OVERLAY_COMMAND ) then
         do i=1,num_curves
         write(savefil,4001) 'CONTOUR'
4001     format('!!'/' ',a)
         if( curve_dat(i)%datafile_type .eq.
     1        SAVE_DATATYPE_ANALYTICAL   ) then
            ilen = string_len(curve_dat(i)%datafile_type)
            write(savefil,4054) curve_dat(i)%datafile_type(1:ilen)
4054        format(' ','DATAFILE_TYPE = ',a)
         else
c           File definition data
            ilen  = string_len(curve_dat(i)%datafile)
            ilen2 = string_len(curve_dat(i)%datafile_type)
            ilen3 = string_len(curve_dat(i)%datafile_quantity)
            write(savefil,4002) curve_dat(i)%datafile(1:ilen),
     1                          curve_dat(i)%datafile_type(1:ilen2),
     1                          curve_dat(i)%datafile_quantity(1:ilen3),
     1                          curve_dat(i)%datafile_record
4002        format(' ','DATAFILE = ',a/
     1             ' ','DATAFILE_TYPE = ',a/
     1             ' ','DATAFILE_QUANTITY = ',a/
     1             ' ','DATAFILE_RECORD = ',i5)
         endif
         ilen = string_len(curve_dat(i)%x_expression)
         if( ilen .gt. 0 ) then
            write(savefil,4003) curve_dat(i)%x_expression(1:ilen)
4003           format(' ','X_EXPRESSION = ',a)
         else
            write(savefil,4004) curve_dat(i)%ax, curve_dat(i)%mx
4004           format(' ','AX = ',1PE12.5/,' ','MX = ',1PE12.5)
         endif
         ilen = string_len(curve_dat(i)%y_expression)
         if( ilen .gt. 0 ) then
            write(savefil,4005) curve_dat(i)%y_expression(1:ilen)
4005           format(' ','Y_EXPRESSION = ',a)
         else
            write(savefil,4006) curve_dat(i)%ay, curve_dat(i)%my
4006           format(' ','AY = ',1PE12.5/,' ','MY = ',1PE12.5)
         endif
         ilen = string_len(curve_dat(i)%z_expression)
         if( ilen .gt. 0 ) then
            write(savefil,4007) curve_dat(i)%z_expression(1:ilen)
4007        format(' ','Z_EXPRESSION = ',A)
         else
            write(savefil,4008) curve_dat(i)%az, curve_dat(i)%mz
4008        format(' ','AZ = ',1PE12.5/' ','MZ = ',1PE12.5)
         endif
c
         if( (curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_MINIMOS
     1   .or. curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_2DOP)
     2   .and. curve_dat(i)%datafile_dimension .eq. 3 ) then
         write(savefil,4009) curve_dat(i)%cut_plane_axis,
     1      pm_scale_cm2plot*curve_dat(i)%cut_plane_coord
4009     format(' ','DATAFILE_DIMENSION = 3'/
     1          ' ','CUT_PLANE_AXIS = ',a/
     2          ' ','CUT_PLANE_COORD = ',1PE12.5)
         endif
         if( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_2DOP) then
            write(savefil,4010) curve_dat(i)%misc(1)*CM2MU
4010        format(' ','DOPFILE_GATE_LENGTH = ',1PE12.5)
            ilen = string_len(curve_dat(i)%misc_ch(1))
            if( ilen .ne. 0 ) then
               write(savefil,4011) curve_dat(i)%misc_ch(1)(1:ilen)
4011           format(' ','DOPFILE_INTERFACE_FILE = ',a)
            endif
         endif
         if( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_VLSICAP)
     1      then
            write(savefil,4012) curve_dat(i)%misc(1),
     1                          curve_dat(i)%misc(2)
4012        format(' ','VLSICAP_GATE_EDGE = ',1PE12.5/
     1             ' ','VLSICAP_SI_SIO2_INTERFACE = ',1PE12.5)
         endif
         if( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_MEDICI)
     1      then
            ilen = string_len(curve_dat(i)%misc_ch(1))
            if( ilen .ne. 0 ) then
               write(savefil,4013) curve_dat(i)%misc_ch(1)(1:ilen)
4013           format(' ','MEDICI_SOLUTION_FILE = ',a)
            endif
         endif
         if( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_PISCES)
     1      then
            ilen = string_len(curve_dat(i)%misc_ch(1))
            if( ilen .ne. 0 ) then
               write(savefil,4014) curve_dat(i)%misc_ch(1)(1:ilen)
4014           format(' ','PISCES_SOLUTION_FILE = ',a)
            endif
         endif
         if( curve_dat(i)%datafile_type .eq. SAVE_DATATYPE_ASCII )
     1      then
            write(savefil,4015) curve_dat(i)%datafile_dimension,
     1                          curve_dat(i)%colx,
     2                          curve_dat(i)%coly(1),
     3                          curve_dat(i)%colz,
     7                          curve_dat(i)%skip
4015        format(' ','DATAFILE_DIMENSION = ',i5/
     1             ' ','COL_X = ',i10/
     1             ' ','COL_Y = ',i10/
     1             ' ','COL_Z = ',i10/
     1             ' ','SKIP_LINES = ',i10)
            if( curve_dat(i)%lines_to_read .gt. 0 ) then
               write(savefil,4016) curve_dat(i)%lines_to_read
4016           format(' ','READ_LINES = ',i10)
            endif
            if( curve_dat(i)%data_is_trigrid ) then
               write(savefil,4017)
4017              format(' ','UNSTRUCTURED_DATA')
            endif
         endif
         if( curve_dat(i)%datafile_type .eq.
     1        SAVE_DATATYPE_ANALYTICAL   ) then
            ilen = string_len(curve_dat(i)%analytical_expression)
            ilen2 = string_len(curve_dat(i)%datafile_quantity)
            write(savefil,3050)
     1         curve_dat(i)%analytical_expression(1:ilen),
     1         anal_type(curve_dat(i)%analytical_type),
     1         curve_dat(i)%datafile_quantity,
     1         curve_dat(i)%datafile_dimension,
     1         curve_dat(i)%analytical_xstart,
     1         curve_dat(i)%analytical_xend,
     1         curve_dat(i)%analytical_xstep
            write(savefil,3052)
     1         curve_dat(i)%analytical_ystart,
     1         curve_dat(i)%analytical_yend,
     1         curve_dat(i)%analytical_ystep
         endif
c
         if( contour_uniform_contours ) then
c           Write out global contours
            write(savefil,4018)
     1         (contour_values(j),j=1,num_contours)
4018        format(' ','VALUES = ',1p10e10.2)
         else
            write(savefil,4018) (curve_dat(i)%contours(j),
     1                           j=1,curve_dat(i)%num_contours)
         endif
         if( curve_dat(i)%contour_grid ) write(savefil,4019)
4019     format(' ','GRID')
         if( curve_dat(i)%contour_junctions ) write(savefil,4020)
4020     format(' ','JUNCTIONS')
         if( curve_dat(i)%contour_color ) write(savefil,4021)
4021     format(' ','COLOR')
c        Retained for compatibility with simple contour plot
         if( contour_negate ) write(savefil,4022)
4022     format(' ','NEGATE')
         if( curve_dat(i)%contour_clabel ) write(savefil,4023)
4023     format(' ','LABELS')
         if( curve_dat(i)%contour_solid ) write(savefil,4024)
4024     format(' ','SOLID_LINES')
c        Retained for compatibility with simple contour plot
         if( contour_log ) write(savefil,4025)
4025     format(' ','LOG_INTERPOLATION')
         if( curve_dat(i)%contour_colormat ) write(savefil,4026)
4026     format(' ','COLOR_MATERIALS')
         end do
c
      else if( save_plot_type .eq. PLOT_3D_COMMAND ) then
         write(savefil,5001) 'SURFACE'
5001     format('!!'/' ',a)
         if( curve_dat(i)%datafile_type .eq.
     1        SAVE_DATATYPE_ANALYTICAL   ) then
            ilen = string_len(curve_dat(i)%datafile_type)
            write(savefil,4054) curve_dat(i)%datafile_type(1:ilen)
         else
c           File definition data
            ilen  = string_len(curve_dat(1)%datafile)
            ilen2 = string_len(curve_dat(1)%datafile_type)
            ilen3 = string_len(curve_dat(1)%datafile_quantity)
            write(savefil,5002) curve_dat(1)%datafile(1:ilen),
     1                          curve_dat(1)%datafile_type(1:ilen2),
     1                          curve_dat(1)%datafile_quantity(1:ilen3),
     1                          curve_dat(1)%datafile_record
5002        format(' ','DATAFILE = ',a/
     1             ' ','DATAFILE_TYPE = ',a/
     1             ' ','DATAFILE_QUANTITY = ',a/
     1             ' ','DATAFILE_RECORD = ',i5)
         endif
         if( (curve_dat(1)%datafile_type .eq. SAVE_DATATYPE_MINIMOS
     1   .or. curve_dat(1)%datafile_type .eq. SAVE_DATATYPE_2DOP)
     2   .and. curve_dat(1)%datafile_dimension .eq. 3 ) then
         write(savefil,5003) curve_dat(1)%cut_plane_axis,
     1      pm_scale_cm2plot*curve_dat(1)%cut_plane_coord
5003     format(' ','CUT_PLANE_AXIS = ',a/
     1          ' ','CUT_PLANE_COORD = ',1PE12.5)
         endif
         if( curve_dat(1)%datafile_type .eq. SAVE_DATATYPE_2DOP) then
            write(savefil,5004) curve_dat(1)%misc(1)*CM2MU
5004        format(' ','DOPFILE_GATE_LENGTH = ',1PE12.5)
            ilen = string_len(curve_dat(1)%misc_ch(1))
            if( ilen .ne. 0 ) then
               write(savefil,5005) curve_dat(1)%misc_ch(1)(1:ilen)
5005           format(' ','DOPFILE_INTERFACE_FILE = ',a)
            endif
         endif
         if( curve_dat(1)%datafile_type .eq. SAVE_DATATYPE_VLSICAP)
     1      then
            write(savefil,5006) curve_dat(1)%misc(1),
     1                          curve_dat(1)%misc(2)
5006        format(' ','VLSICAP_GATE_EDGE = ',1PE12.5/
     1             ' ','VLSICAP_SI_SIO2_INTERFACE = ',1PE12.5)
         endif
         if( curve_dat(1)%datafile_type .eq. SAVE_DATATYPE_MEDICI)
     1      then
            ilen = string_len(curve_dat(1)%misc_ch(1))
            if( ilen .ne. 0 ) then
               write(savefil,5007) curve_dat(1)%misc_ch(1)(1:ilen)
5007           format(' ','MEDICI_SOLUTION_FILE = ',a)
            endif
         endif
         if( curve_dat(1)%datafile_type .eq. SAVE_DATATYPE_PISCES)
     1      then
            ilen = string_len(curve_dat(1)%misc_ch(1))
            if( ilen .ne. 0 ) then
               write(savefil,5008) curve_dat(1)%misc_ch(1)(1:ilen)
5008           format(' ','PISCES_SOLUTION_FILE = ',a)
            endif
         endif
         if( curve_dat(1)%datafile_type .eq. SAVE_DATATYPE_ASCII )
     1      then
            write(savefil,5009) curve_dat(1)%datafile_dimension,
     1                          curve_dat(1)%colx,
     2                          curve_dat(1)%coly(1),
     3                          curve_dat(1)%colz,
     4                          curve_dat(1)%ax, curve_dat(1)%mx,
     5                          curve_dat(1)%ay, curve_dat(1)%my,
     6                          curve_dat(1)%az, curve_dat(1)%mz,
     7                          curve_dat(1)%skip
5009        format(' ','DATAFILE_DIMENSION = ',i5/
     1             ' ','COL_X = ',i10/
     1             ' ','COL_Y = ',i10/
     1             ' ','COL_Z = ',i10/
     1             ' ','AX = ',1PE12.5/,' ','MX = ',1PE12.5/
     1             ' ','AY = ',1PE12.5/,' ','MY = ',1PE12.5/
     1             ' ','AZ = ',1PE12.5/,' ','MZ = ',1PE12.5/
     1             ' ','SKIP_LINES = ',i10)
            if( curve_dat(1)%lines_to_read .gt. 0 ) then
               write(savefil,5010) curve_dat(1)%lines_to_read
5010           format(' ','READ_LINES = ',i10)
            endif
            if( curve_dat(1)%data_is_trigrid ) then
               write(savefil,5011)
5011              format(' ','UNSTRUCTURED_DATA')
            endif
         endif
c
         if( curve_dat(1)%datafile_type .eq.
     1       SAVE_DATATYPE_ANALYTICAL   ) then
            ilen  = string_len(curve_dat(1)%analytical_expression)
            ilen2 = string_len(curve_dat(1)%datafile_quantity)
            write(savefil,3050)
     1         curve_dat(1)%analytical_expression(1:ilen),
     1         anal_type(curve_dat(1)%analytical_type),
     1         curve_dat(1)%datafile_quantity,
     1         curve_dat(1)%datafile_dimension,
     1         curve_dat(1)%analytical_xstart,
     1         curve_dat(1)%analytical_xend,
     1         curve_dat(1)%analytical_xstep
            write(savefil,3052)
     1         curve_dat(1)%analytical_ystart,
     1         curve_dat(1)%analytical_yend,
     1         curve_dat(1)%analytical_ystep
         endif
c
         write(savefil,5012) surface_eye_position
5012     format(' ','EYE_POSITION = ',1p3e11.3)
         if( surface_swapxy ) then
            write(savefil,5013)
5013        format(' ','SWAP_XY_AXES = YES')
         else
            write(savefil,5014)
5014        format(' ','SWAP_XY_AXES = NO')
         ilen = string_len(surface_expression)
         if( ilen .gt. 0 ) write(savefil,5015)
     1                     surface_expression(1:ilen)
5015     format(' ','EXPRESSION = ',A)
         endif
      endif
c
c     Annotate data
c
      call write_save_annotations(savefil)
c
      close(unit=savefil)
      goto 10000
c
6000  err = .TRUE.
      ilen = string_len(savefile)
      istat = pm_put_error_msg('Error: could not open command file: ')
      istat = pm_put_error_msg(savefile(1:ilen))
      if( .NOT. lgui ) then
         write(luttyo,6002)
6002     format(' ','Hit return to continue...')
         read(luttyi,*)
      endif
      goto 10000
c
6100  err = .TRUE.
      ilen = string_len(savefile)
      istat = pm_put_error_msg('Error: during write to command file: ')
      istat = pm_put_error_msg(savefile(1:ilen))
      if( .NOT. lgui ) then
         write(luttyo,6002)
         read(luttyi,*)
      endif
      goto 10000
c
10000 continue
      return
      end
c
      subroutine write_save_annotations(lusave)
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'defaults.cmn'
c
      integer lusave
c
c     locals
      integer i, ilen, string_len, icolor, icolori, iline, itype
      character*6 ch
      character*10 ch2
c
c     Box notes
      do i=1, num_boxes
         icolor =MAX(MIN(box_notes_dat(i)%color,MAX_RGB_VALUES),0)
         icolori=MAX(MIN(box_notes_dat(i)%fill_color,MAX_RGB_VALUES),0)
         write(lusave,1000) color_names(icolor),
     1                     color_names(icolori),
     2                     box_notes_dat(i)%x1, box_notes_dat(i)%y1,
     3                     box_notes_dat(i)%x2, box_notes_dat(i)%y2
1000     format('!!'/' ','ANNOTATE BOX'/
     1          ' ','COLOR = ',a32/
     2          ' ','INTERIOR_COLOR = ',a32/
     3          ' ','X_LOC  = ',1PE12.5/' ','Y_LOC  = ',1PE12.5/
     4          ' ','X_LOC2 = ',1PE12.5/' ','Y_LOC2 = ',1PE12.5)
         if( box_notes_dat(i)%filled ) then
            write(lusave,1001)
1001        format(' ','FILLED')
         endif
         if( box_notes_dat(i)%use_graph_coords ) then
            write(lusave,1002)
1002        format(' ','USE_GRAPH_COORDINATES')
         endif
      end do
c
c     Line notes
      do i=1, num_lines
         icolor = MAX(MIN(line_notes_dat(i)%color,MAX_RGB_VALUES),0)
         iline  = MAX(MIN(line_notes_dat(i)%type,MAX_LINETYPE_VALUES),1)
         write(lusave,2000) color_names(icolor),
     1      line_names(iline),
     2      line_notes_dat(i)%x1, line_notes_dat(i)%y1,
     3      line_notes_dat(i)%x2, line_notes_dat(i)%y2
2000     format('!!'/' ','ANNOTATE LINE'/
     1          ' ','COLOR = ',a32/
     2          ' ','LINETYPE = ',a32/
     3          ' ','X_LOC  = ',1PE12.5/' ','Y_LOC  = ',1PE12.5/
     4          ' ','X_LOC2 = ',1PE12.5/' ','Y_LOC2 = ',1PE12.5)
         if( line_notes_dat(i)%arrow .eq. 1 ) then
            write(lusave,2001)
2001        format(' ','ARROW')
         else if( line_notes_dat(i)%arrow .eq. 2 ) then
            write(lusave,2002)
2002        format(' ','DOUBLE_ARROW')
         endif
         if( line_notes_dat(i)%thickness .ne. 1.0 ) then
            write(lusave,2003) line_notes_dat(i)%thickness
2003        format(' ','THICKNESS = ',1PE12.5)
         endif
         if( line_notes_dat(i)%use_graph_coords ) then
            write(lusave,2004)
2004        format(' ','USE_GRAPH_COORDINATES')
         endif
      end do
c
c     Text notes
      do i=1, num_text
         ilen = MAX(1,string_len(text_notes_dat(i)%text))
         if( text_notes_dat(i)%just .eq.
     1       GKS$K_TEXT_HALIGN_RIGHT ) then
            ch = 'RIGHT'
         else if(text_notes_dat(i)%just .eq.
     1           GKS$K_TEXT_HALIGN_CENTER) then
            ch = 'CENTER'
         else
            ch = 'LEFT'
         endif
         if( text_notes_dat(i)%orient .eq. 0 ) then
            ch2 = 'HORIZONTAL'
         else
            ch2 = 'VERTICAL'
         endif
         icolor = MAX(MIN(text_notes_dat(i)%color,MAX_RGB_VALUES),0)
         write(lusave,3000) text_notes_dat(i)%text(1:ilen),
     1      ch, ch2,
     2      text_notes_dat(i)%xloc, text_notes_dat(i)%yloc,
     3      text_notes_dat(i)%scale, color_names(icolor)
3000     format('!!'/' ','ANNOTATE TEXT'/
     1          ' ','LABEL = ',a/
     2          ' ','JUSTIFICATION = ',a/
     3          ' ','ORIENTATION = ',a/
     4          ' ','X_LOC = ',1PE12.5/' ','Y_LOC = ', 1PE12.5/
     5          ' ','SCALE = ',1PE12.5/' ','COLOR = ',a32)
         if( text_notes_dat(i)%use_x_graph_coords .and.
     1       text_notes_dat(i)%use_y_graph_coords ) then
            write(lusave,3001)
3001        format(' ','USE_GRAPH_COORDINATES')
         else if( text_notes_dat(i)%use_x_graph_coords ) then
            write(lusave,3002)
3002        format(' ','USE_X_GRAPH_COORDINATES')
         else if( text_notes_dat(i)%use_y_graph_coords ) then
            write(lusave,3003)
3003        format(' ','USE_Y_GRAPH_COORDINATES')
         endif
      end do
c
c     Marker notes
      do i=1, num_markers
         icolor=MAX(MIN(marker_notes_dat(i)%color,MAX_RGB_VALUES),0)
         itype =MAX(MIN(marker_notes_dat(i)%type,MAX_SYMBOL_VALUES),1)
         write(lusave,4000) symbol_names(itype),
     1      color_names(icolor), marker_notes_dat(i)%size,
     2      marker_notes_dat(i)%xloc,  marker_notes_dat(i)%yloc
4000     format('!!'/' ','ANNOTATE MARKER'/
     1          ' ','MARKER_TYPE = ',a32/
     2          ' ','MARKER_COLOR = ',a32/
     3          ' ','MARKER_SIZE = ',1PE12.5/
     4          ' ','X_LOC = ',1PE12.5/ ' ','Y_LOC = ', 1PE12.5)
         if( marker_notes_dat(i)%use_graph_coords ) then
            write(lusave,4001)
4001        format(' ','USE_GRAPH_COORDINATES')
         endif
      end do
c
c     Ellipse notes
      do i=1, num_ellipses
         icolor = MAX(MIN(ellipse_notes_dat(i)%color,MAX_RGB_VALUES),0)
         write(lusave,5000) color_names(icolor),
     1      ellipse_notes_dat(i)%x1,  ellipse_notes_dat(i)%y1,
     1      ellipse_notes_dat(i)%x2,  ellipse_notes_dat(i)%y2,
     1      ellipse_notes_dat(i)%x3,  ellipse_notes_dat(i)%y3
5000     format('!!'/' ','ANNOTATE ELLIPSE'/
     1          ' ','COLOR = ',a32/
     2          ' ','X_LOC  = ',1PE12.5/ ' ','Y_LOC  = ', 1PE12.5/
     2          ' ','X_LOC2 = ',1PE12.5/ ' ','Y_LOC2 = ', 1PE12.5/
     3          ' ','X_LOC3 = ',1PE12.5/ ' ','Y_LOC3 = ', 1PE12.5)
         if( ellipse_notes_dat(i)%use_graph_coords ) then
            write(lusave,5001)
5001        format(' ','USE_GRAPH_COORDINATES')
         endif
      end do
c
      return
      end
c
      subroutine copy_annotations_to_save(annotate_window_id)
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
      integer annotate_window_id
c
      integer i, work_id, lookup_ws_id
c
      work_id = lookup_ws_id(annotate_window_id)
      if( work_id .EQ. PLT$EMPTY_WINDOW_SLOT ) then
         call plt$error_message('copy_annotations_to_save',
     1        'source window_id is bad')
         return
      endif
c
c     Box notes
      num_boxes = 0
      do i=1, MAX_BOX_NOTES
         if( box_notes(i)%window .eq. annotate_window_id ) then
            num_boxes = num_boxes + 1
            box_notes_dat(num_boxes)%color = box_notes(i)%color
            box_notes_dat(num_boxes)%fill_color =
     1                  box_notes(i)%fill_color
            box_notes_dat(num_boxes)%thickness = box_notes(i)%thickness
            box_notes_dat(num_boxes)%x1 = box_notes(i)%x1
            box_notes_dat(num_boxes)%y1 = box_notes(i)%y1
            box_notes_dat(num_boxes)%x2 = box_notes(i)%x2
            box_notes_dat(num_boxes)%y2 = box_notes(i)%y2
            box_notes_dat(num_boxes)%filled = box_notes(i)%filled
            box_notes_dat(num_boxes)%use_graph_coords =
     1                  box_notes(i)%use_graph_coords
         endif
      end do
c
c     Line notes
      num_lines = 0
      do i=1, MAX_LINE_NOTES
         if( line_notes(i)%window .eq. annotate_window_id ) then
            num_lines = num_lines + 1
            line_notes_dat(num_lines)%color = line_notes(i)%color
            line_notes_dat(num_lines)%type  = line_notes(i)%type
            line_notes_dat(num_lines)%arrow = line_notes(i)%arrow
            line_notes_dat(num_lines)%thickness =
     1                  line_notes(i)%thickness
            line_notes_dat(num_lines)%x1 = line_notes(i)%x1
            line_notes_dat(num_lines)%y1 = line_notes(i)%y1
            line_notes_dat(num_lines)%x2 = line_notes(i)%x2
            line_notes_dat(num_lines)%y2 = line_notes(i)%y2
            line_notes_dat(num_lines)%use_graph_coords =
     1                 line_notes(i)%use_graph_coords
         endif
      end do
c
c     Text notes
      num_text = 0
      do i=1, MAX_TEXT_NOTES
         if( text_notes(i)%window .eq. annotate_window_id ) then
            num_text = num_text + 1
            text_notes_dat(num_text)%text = text_notes(i)%text
            text_notes_dat(num_text)%just = text_notes(i)%just
            text_notes_dat(num_text)%orient = text_notes(i)%orient
            text_notes_dat(num_text)%color = text_notes(i)%color
            text_notes_dat(num_text)%scale = text_notes(i)%scale
            text_notes_dat(num_text)%xloc = text_notes(i)%xloc
            text_notes_dat(num_text)%yloc = text_notes(i)%yloc
            text_notes_dat(num_text)%use_x_graph_coords =
     1                 text_notes(i)%use_x_graph_coords
            text_notes_dat(num_text)%use_y_graph_coords =
     1                 text_notes(i)%use_y_graph_coords
         endif
      end do
c
c     Marker notes
      num_markers = 0
      do i=1, MAX_MARKER_NOTES
         if( marker_notes(i)%window .eq. annotate_window_id ) then
            num_markers = num_markers + 1
            marker_notes_dat(num_markers)%type = marker_notes(i)%type
            marker_notes_dat(num_markers)%color = marker_notes(i)%color
            marker_notes_dat(num_markers)%xloc = marker_notes(i)%xloc
            marker_notes_dat(num_markers)%yloc = marker_notes(i)%yloc
            marker_notes_dat(num_markers)%size = marker_notes(i)%size
            marker_notes_dat(num_markers)%use_graph_coords =
     1                    marker_notes(i)%use_graph_coords
         endif
      end do
c
c     Ellipse notes
      num_ellipses = 0
      do i=1, MAX_ELLIPSE_NOTES
         if( ellipse_notes(i)%window .eq. annotate_window_id ) then
            num_ellipses = num_ellipses + 1
            ellipse_notes_dat(num_ellipses)%color =
     1                     ellipse_notes(i)%color
            ellipse_notes_dat(num_ellipses)%thickness =
     1                     ellipse_notes(i)%thickness
            ellipse_notes_dat(num_ellipses)%x1 = ellipse_notes(i)%x1
            ellipse_notes_dat(num_ellipses)%y1 = ellipse_notes(i)%y1
            ellipse_notes_dat(num_ellipses)%x2 = ellipse_notes(i)%x2
            ellipse_notes_dat(num_ellipses)%y2 = ellipse_notes(i)%y2
            ellipse_notes_dat(num_ellipses)%x3 = ellipse_notes(i)%x3
            ellipse_notes_dat(num_ellipses)%y3 = ellipse_notes(i)%y3
            ellipse_notes_dat(num_ellipses)%use_graph_coords =
     1                     ellipse_notes(i)%use_graph_coords
         endif
      end do
c
      return
      end
c
      subroutine copy_axis_to_save(command,
     1     h_min_bound, h_max_bound,
     2     h_exponent, h_tic_major, h_minor_tic_freq, hunits,
     3     horiz_axis_title, h_log, h_abs, h_used,
     4     v_min_bound, v_max_bound,
     5     v_exponent, v_tic_major, v_minor_tic_freq, vunits,
     6     vert_axis_title, v_log, v_abs, v_used,
     7     z_min_bound, z_max_bound,
     8     z_exponent, z_tic_major, z_minor_tic_freq, zunits,
     9     z_axis_title, z_log, z_abs, z_used)
c
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
CC      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
      real h_min_bound, h_max_bound, h_tic_major,
     1     v_min_bound, v_max_bound, v_tic_major,
     2     z_min_bound, z_max_bound, z_tic_major
      integer command
      integer h_exponent, h_minor_tic_freq,
     1        v_exponent, v_minor_tic_freq,
     2        z_exponent, z_minor_tic_freq
      logical h_abs, h_log, h_used, v_abs, v_log, v_used,
     1        z_abs, z_log, z_used
      character*(*) hunits, vunits, zunits
      character*(*) horiz_axis_title, vert_axis_title,
     1              z_axis_title
c
      save_plot_type = command
c
c     Initialize axis structure to default values
      call copy_init_axis_to_save
c
      axis_dat(1)%min = h_min_bound
      axis_dat(1)%max = h_max_bound
      axis_dat(1)%major_tic = h_tic_major
      axis_dat(1)%minor_tic_freq = h_minor_tic_freq
      axis_dat(1)%exp   = h_exponent
      axis_dat(1)%label = horiz_axis_title
      axis_dat(1)%units = hunits
      axis_dat(1)%abs = h_abs
      axis_dat(1)%log = h_log
      axis_dat(1)%used = h_used
      axis_dat(1)%autoscale_min = .FALSE.
      axis_dat(1)%autoscale_max = .FALSE.
      axis_dat(1)%invert = .FALSE.
      if( command .eq. PLOT_COMPARE_COMMAND )
     1    call copy_curv_axis_parms_to_save(1)
c
      axis_dat(2)%min = v_min_bound
      axis_dat(2)%max = v_max_bound
      axis_dat(2)%major_tic = v_tic_major
      axis_dat(2)%minor_tic_freq = v_minor_tic_freq
      axis_dat(2)%exp   = v_exponent
      axis_dat(2)%label = vert_axis_title
      axis_dat(2)%units = vunits
      axis_dat(2)%abs = v_abs
      axis_dat(2)%log = v_log
      axis_dat(2)%used = v_used
      axis_dat(2)%autoscale_min = .FALSE.
      axis_dat(2)%autoscale_max = .FALSE.
c     Note: this is set by the routines that save contour plot information
      axis_dat(2)%invert = .FALSE.
      if( command .eq. PLOT_COMPARE_COMMAND )
     1    call copy_curv_axis_parms_to_save(2)
c
      if( command .eq. PLOT_3D_COMMAND ) then
         axis_dat(3)%min = z_min_bound
         axis_dat(3)%max = z_max_bound
         axis_dat(3)%major_tic = z_tic_major
         axis_dat(3)%minor_tic_freq = z_minor_tic_freq
         axis_dat(3)%exp   = z_exponent
         axis_dat(3)%label = z_axis_title
         axis_dat(3)%units = zunits
         axis_dat(3)%abs = z_abs
         axis_dat(3)%log = z_log
         axis_dat(3)%used = z_used
         axis_dat(3)%autoscale_min = .FALSE.
         axis_dat(3)%autoscale_max = .FALSE.
         axis_dat(3)%invert = .FALSE.
c        We don't support curv axis parameters on 3D plots, so no call to
c        copy_curv_axis_parms_to_save
      endif
c
      return
      end
c
      subroutine copy_axis2_to_save(
     1     h_min_bound, h_max_bound,
     2     h_exponent, h_tic_major, h_minor_tic_freq, hunits,
     3     horiz_axis_title, h_log, h_abs, h_used,
     4     v_min_bound, v_max_bound,
     5     v_exponent, v_tic_major, v_minor_tic_freq, vunits,
     6     vert_axis_title, v_log, v_abs, v_used)
c
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
c     Saves second axis information (for compare plot only)
c     This subroutine was created to avoid changes rippling through
c     plot1d/plot2d/plot3d.for
c
      real h_min_bound, h_max_bound, h_tic_major,
     1     v_min_bound, v_max_bound, v_tic_major
      integer h_exponent, h_minor_tic_freq,
     1        v_exponent, v_minor_tic_freq
      logical h_abs, h_log, v_abs, v_log,
     1        h_used, v_used
      character*(*) hunits, vunits
      character*(*) horiz_axis_title, vert_axis_title
c
      axis_dat(4)%min = h_min_bound
      axis_dat(4)%max = h_max_bound
      axis_dat(4)%major_tic = h_tic_major
      axis_dat(4)%minor_tic_freq = h_minor_tic_freq
      axis_dat(4)%exp   = h_exponent
      axis_dat(4)%label = horiz_axis_title
      axis_dat(4)%units = hunits
      axis_dat(4)%abs = h_abs
      axis_dat(4)%log = h_log
      axis_dat(4)%used = h_used
      axis_dat(4)%autoscale_min = .FALSE.
      axis_dat(4)%autoscale_max = .FALSE.
      axis_dat(4)%invert        = .FALSE.
      call copy_curv_axis_parms_to_save(4)
c
      axis_dat(5)%min = v_min_bound
      axis_dat(5)%max = v_max_bound
      axis_dat(5)%major_tic = v_tic_major
      axis_dat(5)%minor_tic_freq = v_minor_tic_freq
      axis_dat(5)%exp   = v_exponent
      axis_dat(5)%label = vert_axis_title
      axis_dat(5)%units = vunits
      axis_dat(5)%abs = v_abs
      axis_dat(5)%log = v_log
      axis_dat(5)%used = v_used
      axis_dat(5)%autoscale_min = .FALSE.
      axis_dat(5)%autoscale_max = .FALSE.
      axis_dat(5)%invert        = .FALSE.
      call copy_curv_axis_parms_to_save(5)
c
      return
      end
c
      subroutine copy_2d_to_save(values, nvalues,
     1     do_junctions, do_grid, do_color, do_negate, do_clabel,
     2     do_invert, do_solid, do_log, do_colormat,
     3     nickname, label, units)
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'plot.cmn'
      include 'data.cmn'
      include 'annotations.cmn'
      include 'user.cmn'
      include 'analytical.cmn'
      include 'save.cmn'
      include 'title.cmn'
c
      integer nvalues
      real    values(nvalues)
      logical do_junctions, do_grid, do_color, do_negate, do_clabel,
     1        do_invert, do_solid, do_log, do_colormat
      character*(*) nickname, label, units
c
      integer i
      character*40 chtmp
c
      call copy_init_curve_to_save
c
      curve_dat(1)%contour_grid      = do_grid
      curve_dat(1)%contour_color     = do_color
      contour_negate                 = do_negate
      curve_dat(1)%contour_clabel    = do_clabel
      curve_dat(1)%contour_junctions = do_junctions
c     Invert is now part of the Y axis information
      axis_dat(2)%invert             = .NOT. do_invert
      curve_dat(1)%contour_solid     = do_solid
      curve_dat(1)%contour_log       = do_log
      curve_dat(1)%contour_colormat  = do_colormat
c
      curve_dat(1)%z_expression = twod_expression
c
c     Set both global and local contour values
      contour_uniform_contours = .FALSE.
      curve_dat(1)%num_contours = nvalues
      num_contours = nvalues
      do 100 i=1,nvalues
         curve_dat(1)%contours(i) = values(i)
         contour_values(i)          = values(i)
100   continue
c
      curve_dat(1)%datafile = binfilename
      curve_dat(1)%datafile_record = datafile_record
      if( three_d ) then
         curve_dat(1)%datafile_dimension = 3
         curve_dat(1)%cut_plane_coord = plane_actual_value
         curve_dat(1)%cut_plane_axis  = cut_plane_axis
      else
         curve_dat(1)%datafile_dimension = 2
      endif
      call datatype_to_name(binfiletype,chtmp)
      curve_dat(1)%datafile_type = chtmp
      curve_dat(1)%datafile_quantity = nickname
      curve_dat(1)%label = label
      curve_dat(1)%units = units
c
      if( binfiletype .eq. DT_2DOP ) then
         curve_dat(1)%misc(1) = tdop_gate_length
         curve_dat(1)%misc_ch(1) = tdop_interface_file
      else if( binfiletype .eq. DT_MEDICI .or.
     1         binfiletype .eq. DT_PISCES ) then
         curve_dat(1)%misc_ch(1) = medici_solution_file
      else if( binfiletype .eq. DT_VLSICAP ) then
         curve_dat(1)%misc(1) = vlsi_edge
         curve_dat(1)%misc(2) = vlsi_yint
      else if( binfiletype .eq. DT_ASCII ) then
         curve_dat(1)%colx = user_1d_col_x
         curve_dat(1)%coly(1) = user_1d_col_y(1)
         curve_dat(1)%colz = user_1d_col_z
         curve_dat(1)%ax = user_1d_ax
         curve_dat(1)%mx = user_1d_mx
         curve_dat(1)%ay = user_1d_ay
         curve_dat(1)%my = user_1d_my
         curve_dat(1)%az = user_1d_az
         curve_dat(1)%mz = user_1d_mz
         curve_dat(1)%sample_freq = user_1d_sample_freq
         curve_dat(1)%skip = user_1d_skip
         curve_dat(1)%n_ycols = user_1d_n_ycols
         curve_dat(1)%lines_to_read = user_1d_nlines
         curve_dat(1)%data_is_trigrid = data_is_trigrid
         curve_dat(1)%merge_ycols = user_1d_merge_ycols
      else if( binfiletype .eq. DT_ANALYTICAL ) then
         curve_dat(1)%analytical_expression = analytical_expression
         curve_dat(1)%analytical_xstart = analytical_xstart
         curve_dat(1)%analytical_xend   = analytical_xend
         curve_dat(1)%analytical_xstep  = analytical_xstep
         curve_dat(1)%analytical_ystart = analytical_ystart
         curve_dat(1)%analytical_yend   = analytical_yend
         curve_dat(1)%analytical_ystep  = analytical_ystep
         curve_dat(1)%analytical_type   = analytical_type
      endif
c
c     Store plot title
      title_dat(1) = plot_title
      num_titles = 1
c
      num_curves = 1
c
      return
      end
c      
      subroutine copy_3d_to_save(nickname)
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'data.cmn'
      include 'plot.cmn'
      include 'annotations.cmn'
      include 'user.cmn'
      include 'analytical.cmn'
      include 'save.cmn'
      include 'title.cmn'
c
      character*(*) nickname
c
      character*40 chtmp
c
      call copy_init_curve_to_save
c
      surface_eye_position(1) = threed_eye_position(1)
      surface_eye_position(2) = threed_eye_position(2)
      surface_eye_position(3) = threed_eye_position(3)
c
      surface_swapxy = threed_swapxy
c
      surface_expression = threed_expression
c
      curve_dat(1)%datafile = binfilename
      curve_dat(1)%datafile_record = datafile_record
      if( three_d ) then
         curve_dat(1)%datafile_dimension = 3
         curve_dat(1)%cut_plane_coord = plane_actual_value
         curve_dat(1)%cut_plane_axis  = cut_plane_axis
      else
         curve_dat(1)%datafile_dimension = 2
      endif
      call datatype_to_name(binfiletype,chtmp)
      curve_dat(1)%datafile_type = chtmp
      curve_dat(1)%datafile_quantity = nickname
c
      if( binfiletype .eq. DT_2DOP ) then
         curve_dat(1)%misc(1) = tdop_gate_length
         curve_dat(1)%misc_ch(1) = tdop_interface_file
      else if( binfiletype .eq. DT_MEDICI .or.
     1         binfiletype .eq. DT_PISCES ) then
         curve_dat(1)%misc_ch(1) = medici_solution_file
      else if( binfiletype .eq. DT_VLSICAP ) then
         curve_dat(1)%misc(1) = vlsi_edge
         curve_dat(1)%misc(2) = vlsi_yint
      else if( binfiletype .eq. DT_ASCII ) then
         curve_dat(1)%colx = user_1d_col_x
         curve_dat(1)%coly(1) = user_1d_col_y(1)
         curve_dat(1)%colz = user_1d_col_z
         curve_dat(1)%ax = user_1d_ax
         curve_dat(1)%mx = user_1d_mx
         curve_dat(1)%ay = user_1d_ay
         curve_dat(1)%my = user_1d_my
         curve_dat(1)%az = user_1d_az
         curve_dat(1)%mz = user_1d_mz
         curve_dat(1)%skip = user_1d_skip
         curve_dat(1)%sample_freq = user_1d_sample_freq
         curve_dat(1)%n_ycols = user_1d_n_ycols
         curve_dat(1)%lines_to_read = user_1d_nlines
         curve_dat(1)%data_is_trigrid = data_is_trigrid
         curve_dat(1)%merge_ycols = user_1d_merge_ycols
      else if( binfiletype .eq. DT_ANALYTICAL ) then
         curve_dat(1)%analytical_expression = analytical_expression
         curve_dat(1)%analytical_xstart = analytical_xstart
         curve_dat(1)%analytical_xend   = analytical_xend
         curve_dat(1)%analytical_xstep  = analytical_xstep
         curve_dat(1)%analytical_ystart = analytical_ystart
         curve_dat(1)%analytical_yend   = analytical_yend
         curve_dat(1)%analytical_ystep  = analytical_ystep
         curve_dat(1)%analytical_type   = analytical_type
      endif
c
c     Store plot title
      title_dat(1) = plot_title
      num_titles = 1
c
      num_curves = 1
c
      return
      end
c
      subroutine copy_compare_to_save(mode)
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'title.cmn'
c
      integer mode
c
      integer i, j, k, slot
c
      call copy_init_curve_to_save
c
      save_plot_subtype = mode
c
c     Store curve information
      j = 0
      do 1000 i=1,n_cuts
         slot = slot_index(i)
         if( multi_1d(slot)%selected .eq. 1 ) then
            j = j + 1
            curve_dat(j)%datafile = multi_1d(slot)%binfilename
            call datatype_to_name(multi_1d(slot)%datatype,
     1                            curve_dat(j)%datafile_type)
            curve_dat(j)%datafile_quantity = multi_1d(slot)%nickname
            if( multi_1d(slot)%type .eq. COMP_INT_TYPE ) then
               curve_dat(j)%int = .TRUE.
            else if( multi_1d(slot)%type .eq. COMP_INTERFACE_TYPE ) then
               curve_dat(j)%oxide = .TRUE.
            endif
            curve_dat(j)%datafile_record    = multi_1d(slot)%record
            curve_dat(j)%datafile_dimension = multi_1d(slot)%dimension
            curve_dat(j)%colx = multi_1d(slot)%col_x
            curve_dat(j)%ax   = multi_1d(slot)%ax
            curve_dat(j)%mx   = multi_1d(slot)%mx
            do k=1,multi_1d(slot)%n_ycols
               curve_dat(j)%coly(k) = multi_1d(slot)%col_y(k)
            end do
            curve_dat(j)%ay   = multi_1d(slot)%ay
            curve_dat(j)%my   = multi_1d(slot)%my
            curve_dat(j)%colz = multi_1d(slot)%col_z
            curve_dat(j)%az   = multi_1d(slot)%az
            curve_dat(j)%mz   = multi_1d(slot)%mz
            curve_dat(j)%xabs = multi_1d(slot)%xabs
            curve_dat(j)%yabs = multi_1d(slot)%yabs
            curve_dat(j)%zabs = multi_1d(slot)%zabs
            curve_dat(j)%skip = multi_1d(slot)%skip
            curve_dat(j)%n_ycols = multi_1d(slot)%n_ycols
            curve_dat(j)%sample_freq = multi_1d(slot)%sample_freq
            curve_dat(j)%xaxis_tag = multi_1d(slot)%xaxis_tag
            curve_dat(j)%yaxis_tag = multi_1d(slot)%yaxis_tag
            curve_dat(j)%lines_to_read = multi_1d(slot)%lines_to_read
            curve_dat(j)%label = multi_1d(slot)%label
            curve_dat(j)%x_expression = multi_1d(slot)%x_expression
            curve_dat(j)%y_expression = multi_1d(slot)%y_expression
            curve_dat(j)%color = multi_1d(slot)%color
            curve_dat(j)%sweep = multi_1d(slot)%sweep
            curve_dat(j)%contour  = multi_1d(slot)%contour
            curve_dat(j)%errorbars  = multi_1d(slot)%errorbars
            curve_dat(j)%suppress = multi_1d(slot)%suppress
            curve_dat(j)%sort = multi_1d(slot)%sort
            curve_dat(j)%x_char_data = multi_1d(slot)%x_char_data
            curve_dat(j)%data_is_trigrid =
     1         multi_1d(slot)%data_is_trigrid
            curve_dat(j)%use_grapes_dict=multi_1d(slot)%use_grapes_dict
            curve_dat(j)%bin_datatype = 
     1         multi_1d(slot)%bin_datatype
            curve_dat(j)%merge_ycols = multi_1d(slot)%merge_ycols
            curve_dat(j)%linetype    = multi_1d(slot)%linestyle
            curve_dat(j)%markertype  = multi_1d(slot)%marker_type
            curve_dat(j)%markercolor = multi_1d(slot)%marker_color
            curve_dat(j)%linewidth   = multi_1d(slot)%linewidth
            curve_dat(j)%markersize  = multi_1d(slot)%marker_scale
            curve_dat(j)%cut_line_coord = multi_1d(slot)%cut_line_coord
            curve_dat(j)%cut_plane_coord= multi_1d(slot)%cut_plane_coord
            curve_dat(j)%cut_line_axis  = multi_1d(slot)%cut_line_axis
            curve_dat(j)%cut_plane_axis = multi_1d(slot)%cut_plane_axis
            curve_dat(j)%int_limits(1) = multi_1d(slot)%int_limits(1)
            curve_dat(j)%int_limits(2) = multi_1d(slot)%int_limits(2)
c           Analytical function stuff
            curve_dat(j)%analytical_expression  =
     1                   multi_1d(slot)%analytical_expression
            curve_dat(j)%analytical_xstart  =
     1                   multi_1d(slot)%analytical_xstart
            curve_dat(j)%analytical_xend    =
     1                   multi_1d(slot)%analytical_xend
            curve_dat(j)%analytical_xstep   =
     1                   multi_1d(slot)%analytical_xstep
            curve_dat(j)%analytical_pstart  =
     1                   multi_1d(slot)%analytical_pstart
            curve_dat(j)%analytical_pend    =
     1                   multi_1d(slot)%analytical_pend
            curve_dat(j)%analytical_pstep   =
     1                   multi_1d(slot)%analytical_pstep
            curve_dat(j)%analytical_ystart  =
     1                   multi_1d(slot)%analytical_ystart
            curve_dat(j)%analytical_yend    =
     1                   multi_1d(slot)%analytical_yend
            curve_dat(j)%analytical_ystep   =
     1                   multi_1d(slot)%analytical_ystep
            curve_dat(j)%analytical_type    =
     1                   multi_1d(slot)%analytical_type
c
            do 1001 k=1,MAX_MISC_DATA
               curve_dat(j)%misc(k) = multi_1d(slot)%misc(k)
1001        continue
            do 1002 k=1,MAX_MISC_CH_DATA
               curve_dat(j)%misc_ch(k) = multi_1d(slot)%misc_ch(k)
1002        continue
         endif
1000  continue
      num_curves = j
c
c     Comparison plot uses title_dat array directly, so there is no need
c     to set it here...
c
      return
      end
c
      subroutine copy_multi_2d_to_save(values, nvalues,
     1                                 linvert, uniform_contours)
      implicit none
c
      integer nvalues
      real    values(nvalues)
      logical linvert, uniform_contours
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'plot.cmn'
      include 'compare_2d.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'title.cmn'
c
c     Locals
      integer i, j, k, slot
c
      call copy_init_curve_to_save
c
      axis_dat(2)%invert = .NOT. linvert
c
c     Set global contour values
      contour_uniform_contours = uniform_contours
      num_contours = nvalues
      do i=1,num_contours
         contour_values(i) = values(i)
      end do
c
c     Store contour plot information for each active dataset
      j = 0
      do i=1,n_data_2d
         slot = slot_index_2d(i)
         if( multi_2d(slot)%selected ) then
            j = j + 1
            curve_dat(j)%datafile = multi_2d(slot)%binfilename
            call datatype_to_name(multi_2d(slot)%datatype,
     1                            curve_dat(j)%datafile_type)
            curve_dat(j)%datafile_quantity = multi_2d(slot)%nickname
            curve_dat(j)%datafile_record    = multi_2d(slot)%record
            curve_dat(j)%datafile_dimension = multi_2d(slot)%dimension
            curve_dat(j)%colx = multi_2d(slot)%col_x
            curve_dat(j)%ax   = multi_2d(slot)%ax
            curve_dat(j)%mx   = multi_2d(slot)%mx
            do k=1,multi_2d(slot)%n_ycols
               curve_dat(j)%coly(k) = multi_2d(slot)%col_y(k)
            end do
            curve_dat(j)%ay   = multi_2d(slot)%ay
            curve_dat(j)%my   = multi_2d(slot)%my
            curve_dat(j)%colz = multi_2d(slot)%col_z
            curve_dat(j)%az   = multi_2d(slot)%az
            curve_dat(j)%mz   = multi_2d(slot)%mz
            curve_dat(j)%skip = multi_2d(slot)%skip
            curve_dat(j)%n_ycols = multi_2d(slot)%n_ycols
            curve_dat(j)%lines_to_read = multi_2d(slot)%lines_to_read
            curve_dat(j)%label = multi_2d(slot)%label
            curve_dat(j)%x_expression = multi_2d(slot)%x_expression
            curve_dat(j)%y_expression = multi_2d(slot)%y_expression
            curve_dat(j)%z_expression = multi_2d(slot)%z_expression
            curve_dat(j)%contour_color = multi_2d(slot)%color
            curve_dat(j)%contour_junctions = multi_2d(slot)%junctions
            curve_dat(j)%contour_grid = multi_2d(slot)%grid
            curve_dat(j)%contour_clabel = multi_2d(slot)%clabel
            curve_dat(j)%contour_solid = multi_2d(slot)%solid
            curve_dat(j)%contour_colormat = multi_2d(slot)%colormat
            curve_dat(j)%data_is_trigrid =
     1         multi_2d(slot)%data_is_trigrid
            curve_dat(j)%bin_datatype = 
     1         multi_2d(slot)%bin_datatype
            curve_dat(j)%cut_plane_coord =
     1          multi_2d(slot)%cut_plane_coord
            curve_dat(j)%cut_plane_axis =
     1          multi_2d(slot)%cut_plane_axis
            curve_dat(j)%num_contours = multi_2d(slot)%num_contours
c           Analytical function stuff
            curve_dat(j)%analytical_expression  =
     1                   multi_2d(slot)%analytical_expression
            curve_dat(j)%analytical_xstart  =
     1                   multi_2d(slot)%analytical_xstart
            curve_dat(j)%analytical_xend    =
     1                   multi_2d(slot)%analytical_xend
            curve_dat(j)%analytical_xstep   =
     1                   multi_2d(slot)%analytical_xstep
            curve_dat(j)%analytical_pstart  =
     1                   multi_2d(slot)%analytical_pstart
            curve_dat(j)%analytical_pend    =
     1                   multi_2d(slot)%analytical_pend
            curve_dat(j)%analytical_pstep   =
     1                   multi_2d(slot)%analytical_pstep
            curve_dat(j)%analytical_ystart  =
     1                   multi_2d(slot)%analytical_ystart
            curve_dat(j)%analytical_yend    =
     1                   multi_2d(slot)%analytical_yend
            curve_dat(j)%analytical_ystep   =
     1                   multi_2d(slot)%analytical_ystep
            curve_dat(j)%analytical_type    =
     1                   multi_2d(slot)%analytical_type
            do k=1,num_contours
               curve_dat(j)%contours(k) = multi_2d(slot)%contours(k)
            end do
            do k=1,MAX_MISC_DATA
               curve_dat(j)%misc(k) = multi_2d(slot)%misc_real(k)
            end do
            do k=1,MAX_MISC_CH_DATA
               curve_dat(j)%misc_ch(k) = multi_2d(slot)%misc_ch(k)
            end do
         endif
      end do
      num_curves = j
c
c     Overlay plot routine uses title_dat, so no need to store it again
c
      return
      end
c
      subroutine copy_init_axis_to_save
c
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
      integer i
c
      do 1000 i=1,MAX_AXES
         axis_dat(i)%min = 0.0
         axis_dat(i)%max = 1.0
         axis_dat(i)%major_tic = 0.0
         axis_dat(i)%minor_tic_size = 0.025
         axis_dat(i)%major_tic_factor = 2.0
         axis_dat(i)%thickness = 1.0
         axis_dat(i)%minor_tic_freq = 5
         axis_dat(i)%exp   = 0
         axis_dat(i)%color = 1
         axis_dat(i)%major_grid_linetype = GKS$K_LINETYPE_SOLID
         axis_dat(i)%minor_grid_linetype = GKS$K_LINETYPE_DOTTED
         axis_dat(i)%label = ' '
         axis_dat(i)%units = ' '
         axis_dat(i)%format = ' '
         axis_dat(i)%abs  = .FALSE.
         axis_dat(i)%log  = .FALSE.
         axis_dat(i)%used = .FALSE.
         axis_dat(i)%autoscale_min = .FALSE.
         axis_dat(i)%autoscale_max = .FALSE.
         axis_dat(i)%nonumbering = .FALSE.
         axis_dat(i)%omit = .FALSE.
         axis_dat(i)%major_grid = .FALSE.
         axis_dat(i)%minor_grid = .FALSE.
         axis_dat(i)%invert     = .FALSE.
1000  continue
c
      return
      end
c
      subroutine copy_init_params_to_save
c
      implicit none
c
c     Initialize various save variables in common
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
c     CONTOUR defaults or placeholders
      num_contours      = 1
      contour_values(1) = 1.0
      contour_junctions = .FALSE.
      contour_color     = .FALSE.
      contour_negate    = .FALSE.
      contour_grid      = .FALSE.
      contour_clabel    = .FALSE.
      contour_invert    = .FALSE.
      contour_solid     = .FALSE.
      contour_log       = .FALSE.
      contour_colormat  = .FALSE.
      contour_expression = ' '
      contour_uniform_contours = .FALSE.
c
c     SURFACE defaults or placeholders
      surface_eye_position(1) =   8.0
      surface_eye_position(2) =  45.0
      surface_eye_position(3) = -45.0
c     Default is to swap X and Y axes
      surface_swapxy = .TRUE.
      surface_expression = ' '
c
      return
      end
c
      subroutine copy_init_curve_to_save
c
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'io.cmn'
c
      integer i, j
c
      do i=1,MAX_SAVE_CURVES
         curve_dat(i)%ax  = 0.0
         curve_dat(i)%mx  = 1.0
         curve_dat(i)%ay  = 0.0
         curve_dat(i)%my  = 1.0
         curve_dat(i)%az  = 0.0
         curve_dat(i)%mz  = 1.0
         curve_dat(i)%linewidth  = 1.0
         curve_dat(i)%markersize = 1.0
         curve_dat(i)%skip  = 0
         curve_dat(i)%lines_to_read  = 0
         curve_dat(i)%xaxis_tag  = 1
         curve_dat(i)%yaxis_tag  = 1
         curve_dat(i)%colx = 1
         curve_dat(i)%coly(1) = 2
         curve_dat(i)%n_ycols = 1
         curve_dat(i)%sample_freq = 1
         curve_dat(i)%colz = 3
         curve_dat(i)%color = 1
         curve_dat(i)%linetype = 1
         curve_dat(i)%markertype = 0
         curve_dat(i)%markercolor = 1
         curve_dat(i)%label = ' '
         curve_dat(i)%x_expression = ' '
         curve_dat(i)%y_expression = ' '
         curve_dat(i)%z_expression = ' '
         curve_dat(i)%datafile = ' '
         curve_dat(i)%datafile_type = SAVE_DATATYPE_ASCII
         curve_dat(i)%datafile_quantity = 'ASCII'
         curve_dat(i)%datafile_record    = 1
         curve_dat(i)%datafile_dimension = 1
         curve_dat(i)%oxide = .FALSE.
         curve_dat(i)%int   = .FALSE.
         curve_dat(i)%sweep = .FALSE.
         curve_dat(i)%xabs  = .FALSE.
         curve_dat(i)%yabs  = .FALSE.
         curve_dat(i)%zabs  = .FALSE.
         curve_dat(i)%contour  = .FALSE.
         curve_dat(i)%errorbars  = .FALSE.
         curve_dat(i)%suppress = .FALSE.
         curve_dat(i)%sort = .FALSE.
         curve_dat(i)%x_char_data = .FALSE.
         curve_dat(i)%data_is_trigrid = .FALSE.
         curve_dat(i)%use_grapes_dict = .FALSE.
         curve_dat(i)%bin_datatype = BINFILE_TYPE_DEFAULT
         curve_dat(i)%merge_ycols  = .FALSE.
         curve_dat(i)%cut_line_axis = 'X'
         curve_dat(i)%cut_line_coord = 0.0
         curve_dat(i)%cut_plane_axis = 'Z'
         curve_dat(i)%cut_plane_coord = 0.0
         curve_dat(i)%int_limits(1) = 0.0
         curve_dat(i)%int_limits(2) = 0.0
         curve_dat(i)%num_contours = 0
c        Analytical function stuff
         curve_dat(i)%analytical_expression  = ' '
         curve_dat(i)%analytical_xstart  = 0.0
         curve_dat(i)%analytical_xend    = 1.0
         curve_dat(i)%analytical_xstep   = 0.1
         curve_dat(i)%analytical_pstart  = 0.0
         curve_dat(i)%analytical_pend    = 1.0
         curve_dat(i)%analytical_pstep   = 0.5
         curve_dat(i)%analytical_ystart  = 0.0
         curve_dat(i)%analytical_yend    = 1.0
         curve_dat(i)%analytical_ystep   = 0.1
         curve_dat(i)%analytical_type    = 1
c
         do j=1,MAX_CONTOURS
            curve_dat(i)%contours(j) = 0.0
         end do
         curve_dat(i)%contour_color     = .FALSE.
         curve_dat(i)%contour_grid      = .FALSE.
         curve_dat(i)%contour_junctions = .FALSE.
         curve_dat(i)%contour_clabel    = .FALSE.
         curve_dat(i)%contour_solid     = .FALSE.
         curve_dat(i)%contour_colormat  = .FALSE.
         curve_dat(i)%contour_log       = .FALSE.
         do j=1,MAX_MISC_DATA
            curve_dat(i)%misc(j) = 0.0
         end do
         do j=1,MAX_MISC_CH_DATA
            curve_dat(i)%misc_ch(j) = ' '
         end do
      end do
c
      return
      end
c
      subroutine copy_init_notes_to_save
c
c     Initialize notes structures in save area
c
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
      integer i
c
      do 100 i=1,MAX_TEXT_NOTES
         text_notes_dat(i)%text = ' '
         text_notes_dat(i)%just = GKS$K_TEXT_HALIGN_LEFT
         text_notes_dat(i)%orient = 0
         text_notes_dat(i)%xloc = 0.0
         text_notes_dat(i)%yloc = 0.0
         text_notes_dat(i)%scale = 1.0
         text_notes_dat(i)%color = 1
         text_notes_dat(i)%use_x_graph_coords = .FALSE.
         text_notes_dat(i)%use_y_graph_coords = .FALSE.
100   continue
c
      do 200 i=1,MAX_BOX_NOTES
         box_notes_dat(i)%color = 1
         box_notes_dat(i)%thickness = 1.0
         box_notes_dat(i)%x1 = 0.0
         box_notes_dat(i)%y1 = 0.0
         box_notes_dat(i)%x2 = 0.0
         box_notes_dat(i)%y2 = 0.0
         box_notes_dat(i)%use_graph_coords = .FALSE.
200   continue
c
      do 300 i=1,MAX_LINE_NOTES
         line_notes_dat(i)%type  = 1
         line_notes_dat(i)%color = 1
         line_notes_dat(i)%thickness = 1.0
         line_notes_dat(i)%arrow = 0
         line_notes_dat(i)%x1 = 0.0
         line_notes_dat(i)%y1 = 0.0
         line_notes_dat(i)%x2 = 0.0
         line_notes_dat(i)%y2 = 0.0
         line_notes_dat(i)%use_graph_coords = .FALSE.
300   continue
c
      do 400 i=1,MAX_ELLIPSE_NOTES
         ellipse_notes_dat(i)%color = 1
         ellipse_notes_dat(i)%thickness = 1.0
         ellipse_notes_dat(i)%x1 = 0.0
         ellipse_notes_dat(i)%y1 = 0.0
         ellipse_notes_dat(i)%x2 = 0.0
         ellipse_notes_dat(i)%y2 = 0.0
         ellipse_notes_dat(i)%x3 = 0.0
         ellipse_notes_dat(i)%x3 = 0.0
         ellipse_notes_dat(i)%use_graph_coords = .FALSE.
400   continue
c
      do 500 i=1,MAX_MARKER_NOTES
         marker_notes_dat(i)%type = 1
         marker_notes_dat(i)%color = 1
         marker_notes_dat(i)%xloc = 0.0
         marker_notes_dat(i)%yloc = 0.0
         marker_notes_dat(i)%size = 1.0
         marker_notes_dat(i)%use_graph_coords = .FALSE.
500   continue
c
      return
      end
c
      subroutine datatype_to_name(type_id,name)
      implicit none
c 
      include 'const.h'
      include 'sysdep.cmn'
      include 'data.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
      integer type_id
      character*(*) name
c
      if( type_id .eq. DT_MINIMOS ) then
         name = SAVE_DATATYPE_MINIMOS
      else if( type_id .eq. DT_PROMIS ) then
         name = SAVE_DATATYPE_PROMIS
      else if( type_id .eq. DT_VLSICAP ) then
         name = SAVE_DATATYPE_VLSICAP
      else if( type_id .eq. DT_BAMBI ) then
         name = SAVE_DATATYPE_BAMBI
      else if( type_id .eq. DT_USEOUT ) then
         name = SAVE_DATATYPE_USEOUT
      else if( type_id .eq. DT_SEDAN ) then
         name = SAVE_DATATYPE_SEDAN
      else if( type_id .eq. DT_2DOP ) then
         name = SAVE_DATATYPE_2DOP
      else if( type_id .eq. DT_SUPREM3S ) then
         name = SAVE_DATATYPE_SUPREM3S
      else if( type_id .eq. DT_SUPREM3P ) then
         name = SAVE_DATATYPE_SUPREM3P
      else if( type_id .eq. DT_ASCII ) then
         name = SAVE_DATATYPE_ASCII
      else if( type_id .eq. DT_PISCES ) then
         name = SAVE_DATATYPE_PISCES
      else if( type_id .eq. DT_SUPREM4 ) then
         name = SAVE_DATATYPE_SUPREM4
      else if( type_id .eq. DT_CALLABLE ) then
         name = SAVE_DATATYPE_CALLABLE
      else if( type_id .eq. DT_CALLABLE_XY ) then
         name = SAVE_DATATYPE_CALLABLE_XY
      else if( type_id .eq. DT_TIF ) then
         name = SAVE_DATATYPE_TIF
      else if( type_id .eq. DT_FAIM ) then
         name = SAVE_DATATYPE_FAIM
      else if( type_id .eq. DT_MCP2D ) then
         name = SAVE_DATATYPE_MCP2D
      else if( type_id .eq. DT_MEDICI ) then
         name = SAVE_DATATYPE_MEDICI
      else if( type_id .eq. DT_GRAPES ) then
         name = SAVE_DATATYPE_GRAPES
      else if( type_id .eq. DT_SPICE3 ) then
         name = SAVE_DATATYPE_SPICE3
      else if( type_id .eq. DT_ANALYTICAL ) then
         name = SAVE_DATATYPE_ANALYTICAL
      else
         name = 'UNKNOWN'
      endif
c
      return
      end
c
      subroutine copy_1d_to_save(cut_line_axis, cut_line_coord,
     1                           nickname, do_markers)
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'data.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'user.cmn'
      include 'analytical.cmn'
      include 'title.cmn'
c
      real cut_line_coord
      character*(*) cut_line_axis, nickname
      logical do_markers
c
      integer i
c
      call copy_init_curve_to_save
c
c     Store curve information in first entry
      curve_dat(1)%datafile = binfilename
      call datatype_to_name(binfiletype,
     1                      curve_dat(1)%datafile_type)
      curve_dat(1)%datafile_quantity = nickname
      curve_dat(1)%datafile_record = datafile_record
      if( three_d ) then
         curve_dat(1)%datafile_dimension = 3
         curve_dat(1)%cut_plane_coord = plane_actual_value
         curve_dat(1)%cut_plane_axis  = cut_plane_axis
      else if( binfiletype .eq. DT_ASCII ) then
         curve_dat(1)%datafile_dimension = user_1d_dim
      else if( binfiletype .eq. DT_SUPREM3S .or.
     1         binfiletype .eq. DT_SUPREM3P .or.
     1         (binfiletype .eq. DT_TIF .and. tif_1d_data) .or.
     1         (binfiletype .eq. DT_ANALYTICAL .and.
     1          analytical_type .le. 2) ) then
c        Any new 1D datatypes should be added to this test...
         curve_dat(1)%datafile_dimension = 1
      else
         curve_dat(1)%datafile_dimension = 2
      endif
      curve_dat(1)%cut_line_coord = cut_line_coord
      curve_dat(1)%cut_line_axis  = cut_line_axis
      curve_dat(1)%int  = .FALSE.
      curve_dat(1)%bin_datatype = binfile_convert_type
      if( binfiletype .eq. DT_2DOP ) then
         curve_dat(1)%misc(1) = tdop_gate_length
         curve_dat(1)%misc_ch(1) = tdop_interface_file
      else if( binfiletype .eq. DT_VLSICAP ) then
         curve_dat(1)%misc(1) = vlsi_edge
         curve_dat(1)%misc(2) = vlsi_yint
      else if( binfiletype .eq. DT_MEDICI .or.
     1         binfiletype .eq. DT_PISCES ) then
         curve_dat(1)%misc_ch(1) = medici_solution_file
      else if( binfiletype .eq. DT_TIF ) then
         if( tif_1d_data ) then
            curve_dat(1)%colx = tif_ixcol
            curve_dat(1)%coly(1) = tif_iycol
         endif
      else if( binfiletype .eq. DT_GRAPES ) then
         curve_dat(1)%misc_ch(1) = grapes_x_quantity
         curve_dat(1)%use_grapes_dict = grapes_use_dictionary
      else if( binfiletype .eq. DT_SPICE3 ) then
         curve_dat(1)%misc_ch(1) = spice3_x_quantity
      else if( binfiletype .eq. DT_ASCII ) then
         curve_dat(1)%colx = user_1d_col_x
         do i=1,user_1d_n_ycols
            curve_dat(1)%coly(i) = user_1d_col_y(i)
         end do
         curve_dat(1)%n_ycols = user_1d_n_ycols
         curve_dat(1)%skip = user_1d_skip
         curve_dat(1)%sweep = user_1d_sweep
         curve_dat(1)%errorbars = user_1d_errorbars
         curve_dat(1)%lines_to_read = user_1d_nlines
         curve_dat(1)%x_char_data = user_1d_x_char_data
         curve_dat(1)%sample_freq = user_1d_sample_freq
         curve_dat(1)%merge_ycols = user_1d_merge_ycols
         curve_dat(1)%ax = user_1d_ax
         curve_dat(1)%ay = user_1d_ay
         curve_dat(1)%mx = user_1d_mx
         curve_dat(1)%my = user_1d_my
         curve_dat(1)%x_expression = user_1d_x_expression
         curve_dat(1)%y_expression = user_1d_y_expression
         if( user_1d_dim .eq. 2 ) then
            curve_dat(1)%colz = user_1d_col_z
            curve_dat(1)%az = user_1d_az
            curve_dat(1)%mz = user_1d_mz
            curve_dat(1)%data_is_trigrid = data_is_trigrid
         endif
      else if( binfiletype .eq. DT_ANALYTICAL ) then
c        Analytical function stuff
         curve_dat(1)%analytical_expression  = analytical_expression
         curve_dat(1)%analytical_xstart  = analytical_xstart
         curve_dat(1)%analytical_xend    = analytical_xend
         curve_dat(1)%analytical_xstep   = analytical_xstep
         curve_dat(1)%analytical_pstart  = analytical_pstart
         curve_dat(1)%analytical_pend    = analytical_pend
         curve_dat(1)%analytical_pstep   = analytical_pstep
         curve_dat(1)%analytical_ystart  = analytical_ystart
         curve_dat(1)%analytical_yend    = analytical_yend
         curve_dat(1)%analytical_ystep   = analytical_ystep
         curve_dat(1)%analytical_type    = analytical_type
      endif
c
      curve_dat(1)%label = ' '
      curve_dat(1)%color = 1
      curve_dat(1)%linetype    = 1
      curve_dat(1)%linewidth   = 1.0
      if( do_markers ) then
         curve_dat(1)%markertype  = 1
         curve_dat(1)%markercolor = 1
         curve_dat(1)%markersize  = 1.0
      else
         curve_dat(1)%markercolor  = 0
      endif
      num_curves = 1
c
c     Store plot title
      title_dat(1) = plot_title
      num_titles = 1
c
      return
      end
c
      subroutine parse_axis(current_axis)
      implicit none
c
c     Parse AXIS command lines
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'units.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'parser.cmn'
c
      integer current_axis
c
      logical check_command
      integer pm_color_to_index, pm_linetype_to_index
      integer ierr, itype
      character*8 axis_type
c
      axis_dat(current_axis)%autoscale_min = .TRUE.
      axis_dat(current_axis)%autoscale_max = .TRUE.
c
c     Set axis used tag
      if( axis_dat(current_axis)%used ) then
         if( current_axis .eq. 1 ) then
            axis_type = 'X'
         else if( current_axis .eq. 2 ) then
            axis_type = 'Y'
         else if( current_axis .eq. 3 ) then
            axis_type = 'Z'
         else if( current_axis .eq. 4 ) then
            axis_type = 'X TOP'
         else if( current_axis .eq. 5 ) then
            axis_type = 'Y RIGHT'
         else
         endif
         write(luttyo,100) iline, axis_type
100      format(' ','Error on line ',i5,
     1          ': ',a,' axis has already been defined')
         perr = .TRUE.
      else
         axis_dat(current_axis)%used = .TRUE.
      endif
c
1000  call next_line
c     End of file?
      if( feof ) then
         goto 4000
c     Next line is a command  line?
      else if( check_command() ) then
         goto 4000
c
c     Parse AXIS commands
c     LOG
      else if( key .eq. 'LOG' ) then
         axis_dat(current_axis)%log = .TRUE.
c     AUTOSCALE
      else if( key .eq. 'AUTOSCALE' ) then
         axis_dat(current_axis)%autoscale_min = .TRUE.
         axis_dat(current_axis)%autoscale_max = .TRUE.
c     LOG_TIC_FREQ = {integer}
      else if( key .eq. 'LOG_TIC_FREQ' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1         axis_dat(current_axis)%minor_tic_freq
         axis_dat(current_axis)%major_tic = 
     1      FLOAT(axis_dat(current_axis)%minor_tic_freq)
c     ABS
      else if( key .eq. 'ABS' ) then
         axis_dat(current_axis)%abs = .TRUE.
c     EXPONENT
      else if( key .eq. 'EXPONENT' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) axis_dat(current_axis)%exp
c     MIN = {real}
      else if( key .eq. 'MIN' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) axis_dat(current_axis)%min
         axis_dat(current_axis)%autoscale_min = .FALSE.
c     MAX = {real}
      else if( key .eq. 'MAX' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) axis_dat(current_axis)%max
         axis_dat(current_axis)%autoscale_max = .FALSE.
c     MAJOR_TIC = {real}
      else if( key .eq. 'MAJOR_TIC' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) axis_dat(current_axis)%major_tic
c     MINOR_TIC_FREQ = {integer}
      else if( key .eq. 'MINOR_TIC_FREQ' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1         axis_dat(current_axis)%minor_tic_freq
c
c     UNITS = {string}
      else if( key .eq. 'UNITS' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            axis_dat(current_axis)%units = ' '
         else
            axis_dat(current_axis)%units = buffer(ipos:ibuf)
            call dequote_string(axis_dat(current_axis)%units,ierr)
            if( ierr .ne. 0 ) goto 3000
         endif
c     LABEL = {string}
      else if( key .eq. 'LABEL' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            axis_dat(current_axis)%label = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            axis_dat(current_axis)%label = item
         endif
c
c     The next keys are valid for compare plot axes only
c     (enhancements to support CURV mode)
c
c     NONUMBERING
      else if( key .eq. 'NONUMBERING' ) then
         axis_dat(current_axis)%nonumbering = .TRUE.
c     OMIT
      else if( key .eq. 'OMIT' ) then
         axis_dat(current_axis)%omit = .TRUE.
c     COLOR = {integer}
      else if( key .eq. 'COLOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode color
         itype = pm_color_to_index(item)
         if( itype .eq. -1 ) goto 2000
         axis_dat(current_axis)%color = itype
c     MINOR_TIC_SIZE = {real}
      else if( key .eq. 'MINOR_TIC_SIZE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        axis_dat(current_axis)%minor_tic_size
         axis_dat(current_axis)%minor_tic_size = 0.01*
     1        axis_dat(current_axis)%minor_tic_size
c     MAJOR_TIC_FACTOR = {real}
      else if( key .eq. 'MAJOR_TIC_FACTOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        axis_dat(current_axis)%major_tic_factor
c     THICKNESS = {real}
      else if( key .eq. 'THICKNESS' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        axis_dat(current_axis)%thickness
c     FORMAT = {string}
      else if( key .eq. 'FORMAT' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            axis_dat(current_axis)%format = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            axis_dat(current_axis)%format = item
         endif
c     MAJOR_GRID
      else if( key .eq. 'MAJOR_GRID' ) then
         axis_dat(current_axis)%major_grid = .TRUE.
c     MINOR_GRID
      else if( key .eq. 'MINOR_GRID' ) then
         axis_dat(current_axis)%minor_grid = .TRUE.
c     MAJOR_GRID_LINETYPE = {integer} or {linetype}
      else if( key .eq. 'MAJOR_GRID_LINETYPE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode linetype
         itype = pm_linetype_to_index(item)
         if( itype .eq. -1 ) goto 2000 
         axis_dat(current_axis)%major_grid_linetype = itype
c     MINOR_GRID_LINETYPE = {integer} or {linetype}
      else if( key .eq. 'MINOR_GRID_LINETYPE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode linetype
         itype = pm_linetype_to_index(item)
         if( itype .eq. -1 ) goto 2000
         axis_dat(current_axis)%minor_grid_linetype = itype
c     INVERT
      else if( key .eq. 'INVERT' ) then
         axis_dat(current_axis)%invert = .TRUE.
c
c     Unknown key
      else
         call perror_write(1, iline, ipos, key, item, buffer)
         perr = .TRUE.
      endif
      goto 1000
c
c     Error on read of values from buffer
2000  call perror_write(2, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
c     Error in string quoting 
3000  call perror_write(3, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
4000  continue
c
      return
      end
c
      subroutine parse_curve
      implicit none
c
c     Parse CURVE command lines
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'units.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'parser.cmn'
c
      logical check_command
      integer ierr, itype, ncols
      integer pm_linetype_to_index, pm_color_to_index,
     1        pm_symbol_to_index, string_len
c
      character*1 TAB
      parameter (TAB = CHAR(9))
c
      character*3 delim
      parameter (delim = ' =' // TAB)
c
1000  call next_line
c     End of file?
      if( feof ) then
         goto 6000
c     Next line is a command  line?
      else if( check_command() ) then
         goto 6000
c     Parse CURVE commands
c     COLOR = {num}
      else if( key .eq. 'COLOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode color
         itype = pm_color_to_index(item)
         if( itype .eq. -1 ) goto 2000
         curve_dat(num_curves)%color = itype
c     LINETYPE = {num}
      else if( key .eq. 'LINETYPE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode linetype
         itype = pm_linetype_to_index(item)
         if( itype .eq. -1 ) goto 2000
         curve_dat(num_curves)%linetype = itype
c     LINEWIDTH = {num}
      else if( key .eq. 'LINEWIDTH' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%linewidth
c     DATAFILE = {string}
      else if( key .eq. 'DATAFILE' ) then
c        We use the get_str_start variant in case filename has a '=' in it
c        Thanks for finding that one, Phil! ;-)
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) goto 2000
         item = buffer(ipos:ibuf)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%datafile = item
c     DATAFILE_DIMENSION = {integer}
      else if( key .eq. 'DATAFILE_DIMENSION' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%datafile_dimension
c     DATAFILE_TYPE = {string}
      else if( key .eq. 'DATAFILE_TYPE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%datafile_type = item
c     DATAFILE_RECORD = {integer}
      else if( key .eq. 'DATAFILE_RECORD' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%datafile_record
c     DATAFILE_QUANTITY = {string}
      else if( key .eq. 'DATAFILE_QUANTITY' ) then
         call get_keyword_2(buffer,delim,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%datafile_quantity = item
c     DOPFILE_GATE_LENGTH = {real}
      else if( key .eq. 'DOPFILE_GATE_LENGTH' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%misc(1)
         curve_dat(num_curves)%misc(1) = pm_scale_plot2cm *
     1                                   curve_dat(num_curves)%misc(1)
c     MEDICI_SOLUTION_FILE = {string}
      else if( key .eq. 'MEDICI_SOLUTION_FILE' ) then
c        We use the get_str_start variant in case filename has a '=' in it
c        Thanks for finding that one, Phil! ;-)
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) goto 2000
         item = buffer(ipos:ibuf)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%misc_ch(1) = item
c     PISCES_SOLUTION_FILE = {string}
      else if( key .eq. 'PISCES_SOLUTION_FILE' ) then
c        We use the get_str_start variant in case filename has a '=' in it
c        Thanks for finding that one, Phil! ;-)
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) goto 2000
         item = buffer(ipos:ibuf)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%misc_ch(1) = item
c     DOPFILE_INTERFACE_FILE = {string}
      else if( key .eq. 'DOPFILE_INTERFACE_FILE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%misc_ch(1) = item
c     GRAPES_XAXIS_QUANTITY = {string}
c     SPICE3_XAXIS_QUANTITY = {string}
      else if( key .eq. 'GRAPES_XAXIS_QUANTITY' .or.
     1         key .eq. 'SPICE3_XAXIS_QUANTITY' ) then
c        We use the get_str_start variant in case filename has a '=' in it
c        Thanks for finding that one, Phil! ;-)
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) goto 2000
         item = buffer(ipos:ibuf)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%misc_ch(1) = item
c     VLSICAP_GATE_EDGE = {real}
      else if( key .eq. 'VLSICAP_GATE_EDGE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%misc(1)
c     VLSICAP_SI_SIO2_INTERFACE = {real}
      else if( key .eq. 'VLSICAP_SI_SIO2_INTERFACE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%misc(2)
c     MARKER_COLOR = {num}
      else if( key .eq. 'MARKER_COLOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode color
         itype = pm_color_to_index(item)
         if( itype .eq. -1 ) goto 2000
         curve_dat(num_curves)%markercolor = itype
c     MARKER_TYPE = {num}
      else if( key .eq. 'MARKER_TYPE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode symbol name
         itype = pm_symbol_to_index(item)
         if( itype .eq. -1 ) goto 2000
         curve_dat(num_curves)%markertype = itype
c     MARKER_SIZE = {num}
      else if( key .eq. 'MARKER_SIZE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%markersize
c     AX = {num}
      else if( key .eq. 'AX' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%ax
c     AY = {num}
      else if( key .eq. 'AY' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%ay
c     MX = {num}
      else if( key .eq. 'MX' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%mx
c     MY = {num}
      else if( key .eq. 'MY' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%my
c     COL_X = {num}
      else if( key .eq. 'COL_X' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%colx
c     COL_Y = {num}
      else if( key .eq. 'COL_Y' ) then
         ncols = 0
c        Loop until we read all the values on the line
1010     call get_keyword(buffer,item,ipos)
            if( ipos .eq. 0 ) goto 1020
            if( ncols .ge. MAXCOLS ) goto 4000
            if( item(1:3) .eq. 'ALL' ) then
               curve_dat(num_curves)%coly(1) = -1
               ncols = 1
               goto 1020
            else
               ncols = ncols + 1
               read(item,*,end=2000,err=2000)
     1            curve_dat(num_curves)%coly(ncols)
            endif
         goto 1010
1020     continue
         curve_dat(num_curves)%n_ycols = ncols
c     SKIP_LINES = {num}
      else if( key .eq. 'SKIP_LINES' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%skip
c     READ_LINES = {num}
      else if( key .eq. 'READ_LINES' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%lines_to_read
c     CUT_LINE_AXIS = {string}
      else if( key .eq. 'CUT_LINE_AXIS' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%cut_line_axis = item(1:1)
c     CUT_LINE_COORD = {num}
      else if( key .eq. 'CUT_LINE_COORD' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%cut_line_coord
         curve_dat(num_curves)%cut_line_coord = pm_scale_plot2cm *
     1   curve_dat(num_curves)%cut_line_coord
c     CUT_PLANE_AXIS = {string}
      else if( key .eq. 'CUT_PLANE_AXIS' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%cut_plane_axis = item(1:1)
c     CUT_PLANE_COORD = {num}
      else if( key .eq. 'CUT_PLANE_COORD' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%cut_plane_coord
         curve_dat(num_curves)%cut_plane_coord = pm_scale_plot2cm *
     1   curve_dat(num_curves)%cut_plane_coord
c     INTEGRATED
      else if( key .eq. 'INTEGRATED' ) then
         curve_dat(num_curves)%int = .TRUE.
c     INTEGRATION_DIRECTION = {string}
      else if( key .eq. 'INTEGRATION_DIRECTION' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%cut_line_axis = item(1:1)
c     INTEGRATION_LIMITS = {real} {real}
      else if( key .eq. 'INTEGRATION_LIMITS' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%int_limits(1)
         curve_dat(num_curves)%int_limits(1) = pm_scale_plot2cm*
     1      curve_dat(num_curves)%int_limits(1)
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%int_limits(2)
         curve_dat(num_curves)%int_limits(2) = pm_scale_plot2cm*
     1      curve_dat(num_curves)%int_limits(2)
c     ALONG_OXIDE
      else if( key .eq. 'ALONG_OXIDE' ) then
         curve_dat(num_curves)%oxide = .TRUE.
c     OXIDE_OFFSET = {num}
      else if( key .eq. 'OXIDE_OFFSET' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%cut_line_coord
         curve_dat(num_curves)%cut_line_coord = pm_scale_plot2cm *
     1   curve_dat(num_curves)%cut_line_coord
c     LABEL = {string}
      else if( key .eq. 'LABEL' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            curve_dat(num_curves)%label = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            curve_dat(num_curves)%label = item
         endif
c     X_EXPRESSION = {string}
      else if( key .eq. 'X_EXPRESSION' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            curve_dat(num_curves)%x_expression = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            if( string_len(item) .gt. PM_MAX_EXPRLEN ) then
               goto 5000
            else
               curve_dat(num_curves)%x_expression = item
            endif
         endif
c     Y_EXPRESSION = {string}
      else if( key .eq. 'Y_EXPRESSION' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            curve_dat(num_curves)%y_expression = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            if( string_len(item) .gt. PM_MAX_EXPRLEN ) then
               goto 5000
            else
               curve_dat(num_curves)%y_expression = item
            endif
         endif
c     XAXIS_TAG = {BOTTOM,TOP}
      else if( key .eq. 'XAXIS_TAG' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         if( item(1:1) .EQ. 'B' ) then
            curve_dat(num_curves)%xaxis_tag = 1
         else if( item (1:1) .EQ. 'T' ) then
            curve_dat(num_curves)%xaxis_tag = 2
         else
            goto 2000
         endif
c     YAXIS_TAG = {LEFT,RIGHT}
      else if( key .eq. 'YAXIS_TAG' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         if( item(1:1) .EQ. 'L' ) then
            curve_dat(num_curves)%yaxis_tag = 1
         else if( item (1:1) .EQ. 'R' ) then
            curve_dat(num_curves)%yaxis_tag = 2
         else
            goto 2000
         endif
c     SWEEP
      else if( key .eq. 'SWEEP' ) then
         curve_dat(num_curves)%sweep = .TRUE.
c     ERRORBARS
      else if( key .eq. 'ERRORBARS' ) then
         curve_dat(num_curves)%errorbars = .TRUE.
c     CHARACTER_DATA_IN_X_COL
      else if( key .eq. 'CHARACTER_DATA_IN_X_COL' ) then
         curve_dat(num_curves)%x_char_data = .TRUE.
c     SAMPLE_FREQ = {num}
      else if( key .eq. 'SAMPLE_FREQ' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%sample_freq
c     MERGE_Y_COLUMN_DATA
      else if( key .eq. 'MERGE_Y_COLUMN_DATA' ) then
         curve_dat(num_curves)%merge_ycols = .TRUE.
c
c     Keys for analytical function datatype
c
c     ANALTYICAL_EXPRESSION = {string}
      else if( key .eq. 'ANALYTICAL_EXPRESSION' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            curve_dat(num_curves)%analytical_expression = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            if( string_len(item) .gt. PM_MAX_EXPRLEN ) then
               goto 5000
            else
               curve_dat(num_curves)%analytical_expression = item
            endif
         endif
c
c     ANALTYICAL_FUNCTION_TYPE = {string} {f(x), f(x,y), f(x,p)}
      else if( key .eq. 'ANALYTICAL_FUNCTION_TYPE' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            curve_dat(num_curves)%analytical_type = 1
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            call upcase(item)
            if( item .eq. 'F(X)' ) then
               curve_dat(num_curves)%analytical_type    = 1
               curve_dat(num_curves)%datafile_dimension = 1
            else if( item .eq. 'F(X,P)' ) then
               curve_dat(num_curves)%analytical_type    = 2
               curve_dat(num_curves)%datafile_dimension = 1
            else if( item .eq. 'F(X,Y)' ) then
               curve_dat(num_curves)%analytical_type    = 3
               curve_dat(num_curves)%datafile_dimension = 2
            else
               goto 2000
            endif
         endif
c
c     ANALYTICAL_XSTART = {num}
      else if( key .eq. 'ANALYTICAL_XSTART' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_xstart
c
c     ANALYTICAL_XEND = {num}
      else if( key .eq. 'ANALYTICAL_XEND' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_xend
c
c     ANALYTICAL_XSTEP = {num}
      else if( key .eq. 'ANALYTICAL_XSTEP' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_xstep
c
c     ANALYTICAL_PSTART = {num}
      else if( key .eq. 'ANALYTICAL_PSTART' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_pstart
c
c     ANALYTICAL_PEND = {num}
      else if( key .eq. 'ANALYTICAL_PEND' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_pend
c
c     ANALYTICAL_PSTEP = {num}
      else if( key .eq. 'ANALYTICAL_PSTEP' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_pstep
c
c     ANALYTICAL_YSTART = {num}
      else if( key .eq. 'ANALYTICAL_YSTART' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_ystart
c
c     ANALYTICAL_YEND = {num}
      else if( key .eq. 'ANALYTICAL_YEND' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_yend
c
c     ANALYTICAL_YSTEP = {num}
      else if( key .eq. 'ANALYTICAL_YSTEP' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_ystep
c
c     Keys for CURV compatibility features
c     AZ = {num}
      else if( key .eq. 'AZ' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%az
c     MZ = {num}
      else if( key .eq. 'MZ' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%mz
c     COL_Z = {num}
      else if( key .eq. 'COL_Z' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%colz
c     XABS
      else if( key .eq. 'XABS' ) then
         curve_dat(num_curves)%xabs = .TRUE.
c     YABS
      else if( key .eq. 'YABS' ) then
         curve_dat(num_curves)%yabs = .TRUE.
c     ZABS
      else if( key .eq. 'ZABS' ) then
         curve_dat(num_curves)%zabs = .TRUE.
c     SORT
      else if( key .eq. 'SORT' ) then
         curve_dat(num_curves)%sort = .TRUE.
c     ZSORT (like CURV "contour")
      else if( key .eq. 'ZSORT' ) then
         curve_dat(num_curves)%contour = .TRUE.
c     UNSTRUCTURED_DATA
      else if( key .eq. 'UNSTRUCTURED_DATA' ) then
         curve_dat(num_curves)%data_is_trigrid = .TRUE.
c     USE_GRAPES_DICTIONARY
      else if( key .eq. 'USE_GRAPES_DICTIONARY' ) then
         curve_dat(num_curves)%use_grapes_dict = .TRUE.
c     BINARY_TYPE
      else if( key .eq. 'BINARY_TYPE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         if( item .eq. 'BIG_ENDIAN' ) then
            curve_dat(num_curves)%bin_datatype =
     1         BINFILE_TYPE_BIG_ENDIAN_IEEE
         else
            curve_dat(num_curves)%bin_datatype = BINFILE_TYPE_DEFAULT
         endif
c
c     Unknown key
      else
         call perror_write(1, iline, ipos, key, item, buffer)
         perr = .TRUE.
      endif
      goto 1000
c
c     Error on read of values from buffer
2000  call perror_write(2, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
c     Error in string quoting
3000  call perror_write(3, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
c     Too many values on line
4000  call perror_write(4, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
c     String too long
5000  call perror_write(5, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
6000  continue
c
      return
      end
c
      subroutine parse_contour
      implicit none
c
c     Parse CONTOUR command lines
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'units.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'parser.cmn'
c
      logical check_command
      integer ierr, string_len, ncontours, i
c
1000  call next_line
c     End of file?
      if( feof ) then
         goto 6000
c     Next line is a command  line?
      else if( check_command() ) then
         goto 6000
c     Parse CONTOUR commands
c
c     COLOR
      else if( key .eq. 'COLOR' ) then
         curve_dat(num_curves)%contour_color = .TRUE.
         contour_color = .TRUE.
c     DATAFILE = {string}
      else if( key .eq. 'DATAFILE' ) then
c        We use the get_str_start variant in case filename has a '=' in it
c        Thanks for finding that one, Phil! ;-)
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) goto 2000
         item = buffer(ipos:ibuf)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%datafile = item
c     DATAFILE_DIMENSION = {integer}
      else if( key .eq. 'DATAFILE_DIMENSION' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%datafile_dimension
c     DATAFILE_TYPE = {string}
      else if( key .eq. 'DATAFILE_TYPE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%datafile_type = item
c     DATAFILE_RECORD = {integer}
      else if( key .eq. 'DATAFILE_RECORD' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%datafile_record
c     DATAFILE_QUANTITY = {string}
      else if( key .eq. 'DATAFILE_QUANTITY' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%datafile_quantity = item
c     CUT_PLANE_AXIS = {string}
      else if( key .eq. 'CUT_PLANE_AXIS' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%cut_plane_axis = item(1:1)
c     CUT_PLANE_COORD = {num}
      else if( key .eq. 'CUT_PLANE_COORD' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%cut_plane_coord
         curve_dat(num_curves)%cut_plane_coord = pm_scale_plot2cm *
     1   curve_dat(num_curves)%cut_plane_coord
c     DOPFILE_GATE_LENGTH = {real}
      else if( key .eq. 'DOPFILE_GATE_LENGTH' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%misc(1)
         curve_dat(num_curves)%misc(1) = pm_scale_plot2cm *
     1                           curve_dat(num_curves)%misc(1)
c     DOPFILE_INTERFACE_FILE = {string}
      else if( key .eq. 'DOPFILE_INTERFACE_FILE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%misc_ch(1) = item
c     MEDICI_SOLUTION_FILE = {string}
      else if( key .eq. 'MEDICI_SOLUTION_FILE' ) then
c        We use the get_str_start variant in case filename has a '=' in it
c        Thanks for finding that one, Phil! ;-)
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) goto 2000
         item = buffer(ipos:ibuf)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%misc_ch(1) = item
c     PISCES_SOLUTION_FILE = {string}
      else if( key .eq. 'PISCES_SOLUTION_FILE' ) then
c        We use the get_str_start variant in case filename has a '=' in it
c        Thanks for finding that one, Phil! ;-)
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) goto 2000
         item = buffer(ipos:ibuf)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%misc_ch(1) = item
c     VLSICAP_GATE_EDGE = {real}
      else if( key .eq. 'VLSICAP_GATE_EDGE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%misc(1)
c     VLSICAP_SI_SIO2_INTERFACE = {real}
      else if( key .eq. 'VLSICAP_SI_SIO2_INTERFACE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%misc(2)
c     AX = {num}
      else if( key .eq. 'AX' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%ax
c     AY = {num}
      else if( key .eq. 'AY' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%ay
c     AZ = {num}
      else if( key .eq. 'AZ' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%az
c     MX = {num}
      else if( key .eq. 'MX' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%mx
c     MY = {num}
      else if( key .eq. 'MY' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%my
c     MZ = {num}
      else if( key .eq. 'MZ' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%mz
c     COL_X = {num}
      else if( key .eq. 'COL_X' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%colx
c     COL_Y = {num}
      else if( key .eq. 'COL_Y' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%coly(1)
         curve_dat(num_curves)%n_ycols = 1
c     COL_Z = {num}
      else if( key .eq. 'COL_Z' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%colz
c     SKIP_LINES = {num}
      else if( key .eq. 'SKIP_LINES' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%skip
c     READ_LINES = {num}
      else if( key .eq. 'READ_LINES' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%lines_to_read
c     UNSTRUCTURED_DATA
      else if( key .eq. 'UNSTRUCTURED_DATA' ) then
         curve_dat(num_curves)%data_is_trigrid = .TRUE.
c     VALUES
      else if( key .eq. 'VALUES' ) then
         ncontours = 0
c        Loop until we read all the values on the line
1010     call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 1020
         if( ncontours .gt. MAX_CONTOURS ) goto 4000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%contours(ncontours+1)
         ncontours = ncontours + 1
         goto 1010
1020     continue
         curve_dat(num_curves)%num_contours = ncontours
c        For backward compatibility with 2D contour plot routine
         num_contours = ncontours
         do i=1,ncontours
            contour_values(i) = curve_dat(num_curves)%contours(i)
         end do
c
c     NEGATE
      else if( key .eq. 'NEGATE' ) then
c        Note: we don't support negate on multiple contour plots
c        since we have z expressions
         contour_negate = .TRUE.
c
c     JUNCTIONS
      else if( key .eq. 'JUNCTIONS' ) then
         curve_dat(num_curves)%contour_junctions = .TRUE.
         contour_junctions = .TRUE.
c
c     LABELS
      else if( key .eq. 'LABELS' ) then
         curve_dat(num_curves)%contour_clabel = .TRUE.
         contour_clabel = .TRUE.
c
c     GRID
      else if( key .eq. 'GRID' ) then
         curve_dat(num_curves)%contour_grid = .TRUE.
         contour_grid = .TRUE.
c
c     INVERT
      else if( key .eq. 'INVERT' ) then
c        This should really have been put on the Y axis
         axis_dat(2)%invert = .FALSE.
         contour_invert = .TRUE.
c
c     SOLID_LINES
      else if( key .eq. 'SOLID_LINES' ) then
         curve_dat(num_curves)%contour_solid = .TRUE.
         contour_solid = .TRUE.
c
c     LOG_INTERPOLATION
      else if( key .eq. 'LOG_INTERPOLATION' ) then
c        Note: we don't support negate on multiple contour plots
         contour_log = .TRUE.
c
c     X_EXPRESSION = {string}
      else if(key .eq. 'X_EXPRESSION') then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            curve_dat(num_curves)%x_expression = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            if( string_len(item) .gt. PM_MAX_EXPRLEN ) then
               goto 5000
            else
            curve_dat(num_curves)%x_expression = item
            endif
         endif
c
c     Y_EXPRESSION = {string}
      else if(key .eq. 'Y_EXPRESSION') then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            curve_dat(num_curves)%y_expression = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            if( string_len(item) .gt. PM_MAX_EXPRLEN ) then
               goto 5000
            else
            curve_dat(num_curves)%y_expression = item
            endif
         endif
c
c     EXPRESSION (or) Z_EXPRESSION = {string}
      else if(key .eq. 'EXPRESSION' .or. key .eq. 'Z_EXPRESSION') then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            contour_expression = ' '
            curve_dat(num_curves)%z_expression = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            if( string_len(item) .gt. PM_MAX_EXPRLEN ) then
               goto 5000
            else
               contour_expression = item
            curve_dat(num_curves)%z_expression = item
            endif
         endif
c
c     COLOR_MATERIALS
      else if( key .eq. 'COLOR_MATERIALS' ) then
         contour_colormat = .TRUE.
         curve_dat(num_curves)%contour_colormat = .TRUE.
c
c     Keys for analytical function datatype (keys for 2D datasets only)
c
c     ANALTYICAL_EXPRESSION = {string}
      else if( key .eq. 'ANALYTICAL_EXPRESSION' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            curve_dat(num_curves)%analytical_expression = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            if( string_len(item) .gt. PM_MAX_EXPRLEN ) then
               goto 5000
            else
               curve_dat(num_curves)%analytical_expression = item
            endif
         endif
c
c     ANALTYICAL_FUNCTION_TYPE = {string} {f(x,y)}
      else if( key .eq. 'ANALYTICAL_FUNCTION_TYPE' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            curve_dat(num_curves)%analytical_type = 1
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            call upcase(item)
            if( item .eq. 'F(X,Y)' ) then
               curve_dat(num_curves)%analytical_type    = 3
               curve_dat(num_curves)%datafile_dimension = 2
            else
               goto 2000
            endif
         endif
c
c     ANALYTICAL_XSTART = {num}
      else if( key .eq. 'ANALYTICAL_XSTART' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_xstart
c
c     ANALYTICAL_XEND = {num}
      else if( key .eq. 'ANALYTICAL_XEND' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_xend
c
c     ANALYTICAL_XSTEP = {num}
      else if( key .eq. 'ANALYTICAL_XSTEP' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_xstep
c
c     ANALYTICAL_YSTART = {num}
      else if( key .eq. 'ANALYTICAL_YSTART' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_ystart
c
c     ANALYTICAL_YEND = {num}
      else if( key .eq. 'ANALYTICAL_YEND' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_yend
c
c     ANALYTICAL_YSTEP = {num}
      else if( key .eq. 'ANALYTICAL_YSTEP' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_ystep
c
c     Unknown key
      else
         call perror_write(1, iline, ipos, key, item, buffer)
         perr = .TRUE.
      endif
      goto 1000
c
c     Error on read of values from buffer
2000  call perror_write(2, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
c     Error in string quoting
3000  call perror_write(3, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
c     Too many values on line
4000  call perror_write(4, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
c     String too long
5000  call perror_write(5, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
6000  continue
c
      return
      end
c
      subroutine parse_surface
      implicit none
c
c     Parse SURFACE command lines
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'units.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'parser.cmn'
c
      integer i, ierr, string_len
      logical check_command
c
1000  call next_line
c     End of file?
      if( feof ) then
         goto 5000
c     Next line is a command  line?
      else if( check_command() ) then
         goto 5000
c
c     Parse SURFACE commands
c
c     DATAFILE = {string}
      else if( key .eq. 'DATAFILE' ) then
c        We use the get_str_start variant in case filename has a '=' in it
c        Thanks for finding that one, Phil! ;-)
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) goto 2000
         item = buffer(ipos:ibuf)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%datafile = item
c     DATAFILE_DIMENSION = {integer}
      else if( key .eq. 'DATAFILE_DIMENSION' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%datafile_dimension
c     DATAFILE_TYPE = {string}
      else if( key .eq. 'DATAFILE_TYPE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%datafile_type = item
c     DATAFILE_RECORD = {integer}
      else if( key .eq. 'DATAFILE_RECORD' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%datafile_record
c     DATAFILE_QUANTITY = {string}
      else if( key .eq. 'DATAFILE_QUANTITY' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%datafile_quantity = item
c     CUT_PLANE_AXIS = {string}
      else if( key .eq. 'CUT_PLANE_AXIS' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%cut_plane_axis = item(1:1)
c     CUT_PLANE_COORD = {num}
      else if( key .eq. 'CUT_PLANE_COORD' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%cut_plane_coord
         curve_dat(num_curves)%cut_plane_coord = pm_scale_plot2cm *
     1   curve_dat(num_curves)%cut_plane_coord
c     DOPFILE_GATE_LENGTH = {real}
      else if( key .eq. 'DOPFILE_GATE_LENGTH' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%misc(1)
         curve_dat(num_curves)%misc(1) = pm_scale_plot2cm *
     1                                   curve_dat(num_curves)%misc(1)
c     DOPFILE_INTERFACE_FILE = {string}
      else if( key .eq. 'DOPFILE_INTERFACE_FILE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%misc_ch(1) = item
c     MEDICI_SOLUTION_FILE = {string}
      else if( key .eq. 'MEDICI_SOLUTION_FILE' ) then
c        We use the get_str_start variant in case filename has a '=' in it
c        Thanks for finding that one, Phil! ;-)
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) goto 2000
         item = buffer(ipos:ibuf)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%misc_ch(1) = item
c     PISCES_SOLUTION_FILE = {string}
      else if( key .eq. 'PISCES_SOLUTION_FILE' ) then
c        We use the get_str_start variant in case filename has a '=' in it
c        Thanks for finding that one, Phil! ;-)
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) goto 2000
         item = buffer(ipos:ibuf)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         curve_dat(num_curves)%misc_ch(1) = item
c     VLSICAP_GATE_EDGE = {real}
      else if( key .eq. 'VLSICAP_GATE_EDGE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%misc(1)
c     VLSICAP_SI_SIO2_INTERFACE = {real}
      else if( key .eq. 'VLSICAP_SI_SIO2_INTERFACE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%misc(2)
c     AX = {num}
      else if( key .eq. 'AX' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%ax
c     AY = {num}
      else if( key .eq. 'AY' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%ay
c     AZ = {num}
      else if( key .eq. 'AZ' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%az
c     MX = {num}
      else if( key .eq. 'MX' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%mx
c     MY = {num}
      else if( key .eq. 'MY' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%my
c     MZ = {num}
      else if( key .eq. 'MZ' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%mz
c     COL_X = {num}
      else if( key .eq. 'COL_X' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%colx
c     COL_Y = {num}
      else if( key .eq. 'COL_Y' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%coly(1)
         curve_dat(num_curves)%n_ycols = 1
c     COL_Z = {num}
      else if( key .eq. 'COL_Z' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%colz
c     SKIP_LINES = {num}
      else if( key .eq. 'SKIP_LINES' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) curve_dat(num_curves)%skip
c     READ_LINES = {num}
      else if( key .eq. 'READ_LINES' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1        curve_dat(num_curves)%lines_to_read
c     UNSTRUCTURED_DATA
      else if( key .eq. 'UNSTRUCTURED_DATA' ) then
         curve_dat(num_curves)%data_is_trigrid = .TRUE.
c     EYE_POSITION
      else if( key .eq. 'EYE_POSITION' ) then
         do 1010 i=1,3
            call get_keyword(buffer,item,ipos)
            if( ipos .eq. 0 ) goto 2000
            read(item,*,end=2000,err=2000)
     1         surface_eye_position(i)
1010     continue
c     SWAP_XY_AXES = {YES,NO} or {TRUE,FALSE}
      else if( key .eq. 'SWAP_XY_AXES' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         if( item(1:1) .eq. 'Y' .or. item(1:1) .eq. 'T' ) then
            surface_swapxy = .TRUE.
         else
            surface_swapxy = .FALSE.
         endif
c
c     EXPRESSION = {string}
      else if( key .eq. 'EXPRESSION' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            surface_expression = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            if( string_len(item) .gt. PM_MAX_EXPRLEN ) then
               goto 4000
            else
               surface_expression = item
            endif
         endif
c
c     Keys for analytical function datatype (keys for 2D datasets only)
c
c     ANALTYICAL_EXPRESSION = {string}
      else if( key .eq. 'ANALYTICAL_EXPRESSION' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            curve_dat(num_curves)%analytical_expression = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            if( string_len(item) .gt. PM_MAX_EXPRLEN ) then
               goto 5000
            else
               curve_dat(num_curves)%analytical_expression = item
            endif
         endif
c
c     ANALTYICAL_FUNCTION_TYPE = {string} {f(x,y)}
      else if( key .eq. 'ANALYTICAL_FUNCTION_TYPE' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            curve_dat(num_curves)%analytical_type = 1
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            call upcase(item)
            if( item .eq. 'F(X,Y)' ) then
               curve_dat(num_curves)%analytical_type    = 3
               curve_dat(num_curves)%datafile_dimension = 2
            else
               goto 2000
            endif
         endif
c
c     ANALYTICAL_XSTART = {num}
      else if( key .eq. 'ANALYTICAL_XSTART' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_xstart
c
c     ANALYTICAL_XEND = {num}
      else if( key .eq. 'ANALYTICAL_XEND' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_xend
c
c     ANALYTICAL_XSTEP = {num}
      else if( key .eq. 'ANALYTICAL_XSTEP' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_xstep
c
c     ANALYTICAL_YSTART = {num}
      else if( key .eq. 'ANALYTICAL_YSTART' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_ystart
c
c     ANALYTICAL_YEND = {num}
      else if( key .eq. 'ANALYTICAL_YEND' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_yend
c
c     ANALYTICAL_YSTEP = {num}
      else if( key .eq. 'ANALYTICAL_YSTEP' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      curve_dat(num_curves)%analytical_ystep
c
c     Unknown key
      else
         call perror_write(1, iline, ipos, key, item, buffer)
         perr = .TRUE.
      endif
      goto 1000
c
c     Error on read of values from buffer
2000  call perror_write(2, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
c     Error in string quoting
3000  call perror_write(3, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
c     String too long
4000  call perror_write(5, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
5000  continue
c
      return
      end
c
      subroutine parse_box_note
      implicit none
c
c     Parse box annotation lines
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'units.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'parser.cmn'
c
      integer itype, pm_color_to_index
      logical check_command
c
1000  call next_line
c     End of file?
      if( feof ) then
         goto 4000
c     Next line is a command  line?
      else if( check_command() ) then
         goto 4000
c     Parse box annotations commands
c
c     FILLED
      else if( key .eq. 'FILLED' ) then
          box_notes_dat(num_boxes)%filled = .TRUE.
c     INTERIOR_COLOR
      else if( key .eq. 'INTERIOR_COLOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode color
         itype = pm_color_to_index(item)
         if( itype .eq. -1 ) goto 2000
          box_notes_dat(num_boxes)%fill_color = itype
c     X_LOC = {real}
      else if( key .eq. 'X_LOC' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      box_notes_dat(num_boxes)%x1
c     Y_LOC = {real}
      else if( key .eq. 'Y_LOC' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      box_notes_dat(num_boxes)%y1
c     X_LOC2 = {real}
      else if( key .eq. 'X_LOC2' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      box_notes_dat(num_boxes)%x2
c     Y_LOC2 = {real}
      else if( key .eq. 'Y_LOC2' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      box_notes_dat(num_boxes)%y2
c     COLOR = {num}
      else if( key .eq. 'COLOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode color
         itype = pm_color_to_index(item)
         if( itype .eq. -1 ) goto 2000
         box_notes_dat(num_boxes)%color = itype
c     USE_GRAPH_COORDINATES 
      else if( key .eq. 'USE_GRAPH_COORDINATES' ) then
         box_notes_dat(num_boxes)%use_graph_coords = .TRUE.
c
c     Unknown key
      else
         call perror_write(1, iline, ipos, key, item, buffer)
         perr = .TRUE.
      endif
      goto 1000
c
c     Error on read of values from buffer
2000  call perror_write(2, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
4000  continue
c
      return
      end
c
      subroutine parse_text_note
      implicit none
c
c     Parse text annotation lines
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'plot.cmn'
      include 'units.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'parser.cmn'
c
      integer itmp, ierr, itype, pm_color_to_index
      logical check_command
c
1000  call next_line
c     End of file?
      if( feof ) then
         goto 4000
c     Next line is a command  line?
      else if( check_command() ) then
         goto 4000
c     Parse text annotations commands
c
c     LABEL = {string}
      else if( key .eq. 'LABEL' ) then
         call get_str_start(buffer,ipos)
         if( ipos .eq. 0 ) then
            text_notes_dat(num_text)%text = ' '
         else
            item = buffer(ipos:ibuf)
            call dequote_string(item,ierr)
            if( ierr .ne. 0 ) goto 3000
            text_notes_dat(num_text)%text = item
         endif
c     JUSTIFICATION
      else if( key .eq. 'JUSTIFICATION' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         if( item(1:1) .eq. 'C' ) then
            itmp = GKS$K_TEXT_HALIGN_CENTER
         else if( item(1:1) .eq. 'R' ) then
            itmp = GKS$K_TEXT_HALIGN_RIGHT
         else
            itmp = GKS$K_TEXT_HALIGN_LEFT
         endif
         text_notes_dat(num_text)%just = itmp
c     ORIENTATION
      else if( key .eq. 'ORIENTATION' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         if( item(1:1) .eq. 'H' ) then
            itmp = 0
         else if( item(1:1) .eq. 'V' ) then
            itmp = 1
         else
            goto 2000
         endif
         text_notes_dat(num_text)%orient = itmp
c     SCALE
      else if( key .eq. 'SCALE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      text_notes_dat(num_text)%scale
c     X_LOC = {real}
      else if( key .eq. 'X_LOC' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      text_notes_dat(num_text)%xloc
c     Y_LOC = {real}
      else if( key .eq. 'Y_LOC' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      text_notes_dat(num_text)%yloc
c     COLOR
      else if( key .eq. 'COLOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode color
         itype = pm_color_to_index(item)
         if( itype .eq. -1 ) goto 2000
         text_notes_dat(num_text)%color = itype
c     USE_GRAPH_COORDINATES 
      else if( key .eq. 'USE_GRAPH_COORDINATES' ) then
         text_notes_dat(num_text)%use_x_graph_coords = .TRUE.
         text_notes_dat(num_text)%use_y_graph_coords = .TRUE.
c
c     USE_X_GRAPH_COORDINATES
      else if( key .eq. 'USE_X_GRAPH_COORDINATES' ) then
         text_notes_dat(num_text)%use_x_graph_coords = .TRUE.
c
c     USE_Y_GRAPH_COORDINATES 
      else if( key .eq. 'USE_Y_GRAPH_COORDINATES' ) then
         text_notes_dat(num_text)%use_y_graph_coords = .TRUE.
c
c     Unknown key
      else
         call perror_write(1, iline, ipos, key, item, buffer)
         perr = .TRUE.
      endif
      goto 1000
c
c     Error on read of values from buffer
2000  call perror_write(2, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
c     Error in string quoting
3000  call perror_write(3, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
4000  continue
c
      return
      end
c
      subroutine parse_line_note
      implicit none
c
c     Parse line annotation lines
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'units.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'parser.cmn'
c
      integer itype, pm_color_to_index, pm_linetype_to_index
      logical check_command
c
1000  call next_line
c     End of file?
      if( feof ) then
         goto 4000
c     Next line is a command  line?
      else if( check_command() ) then
         goto 4000
c     Parse line annotations commands
c
c     ARROW
      else if( key .eq. 'ARROW' ) then
         line_notes_dat(num_lines)%arrow = 1
c     DOUBLE_ARROW
      else if( key .eq. 'DOUBLE_ARROW' ) then
         line_notes_dat(num_lines)%arrow = 2
c     LINETYPE = {num}
      else if( key .eq. 'LINETYPE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode linetype
         itype = pm_linetype_to_index(item)
         if( itype .eq. -1 ) goto 2000
         line_notes_dat(num_lines)%type = itype
c     X_LOC = {real}
      else if( key .eq. 'X_LOC' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      line_notes_dat(num_lines)%x1
c     Y_LOC = {real}
      else if( key .eq. 'Y_LOC' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      line_notes_dat(num_lines)%y1
c
c     X_LOC2 = {real}
      else if( key .eq. 'X_LOC2' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      line_notes_dat(num_lines)%x2
c     Y_LOC2 = {real}
      else if( key .eq. 'Y_LOC2' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      line_notes_dat(num_lines)%y2
c     THICKNESS = {real}
      else if( key .eq. 'THICKNESS' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      line_notes_dat(num_lines)%thickness
c     COLOR = {num}
      else if( key .eq. 'COLOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode color
         itype = pm_color_to_index(item)
         if( itype .eq. -1 ) goto 2000
         line_notes_dat(num_lines)%color = itype
c     USE_GRAPH_COORDINATES 
      else if( key .eq. 'USE_GRAPH_COORDINATES' ) then
         line_notes_dat(num_lines)%use_graph_coords = .TRUE.
c
c     Unknown key
      else
         call perror_write(1, iline, ipos, key, item, buffer)
         perr = .TRUE.
      endif
      goto 1000
c
c     Error on read of values from buffer
2000  call perror_write(2, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
4000  continue
c
      return
      end
c
      subroutine parse_marker_note
      implicit none
c
c     Parse marker annotation lines
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'units.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'parser.cmn'
c
      integer itype, pm_color_to_index, pm_symbol_to_index
      logical check_command
c
1000  call next_line
c     End of file?
      if( feof ) then
         goto 4000
c     Next line is a command  line?
      else if( check_command() ) then
         goto 4000
c     Parse marker annotations commands
c     X_LOC = {real}
      else if( key .eq. 'X_LOC' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      marker_notes_dat(num_markers)%xloc
c     Y_LOC = {real}
      else if( key .eq. 'Y_LOC' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      marker_notes_dat(num_markers)%yloc
c     MARKER_TYPE = {num}
      else if( key .eq. 'MARKER_TYPE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode marker type
         itype = pm_symbol_to_index(item)
         if( itype .eq. -1 ) goto 2000
         marker_notes_dat(num_markers)%type = itype
c     MARKER_COLOR = {num}
      else if( key .eq. 'MARKER_COLOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode marker type
         itype = pm_color_to_index(item)
         if( itype .eq. -1 ) goto 2000
         marker_notes_dat(num_markers)%color = itype
c     MARKER_SIZE = {num}
      else if( key .eq. 'MARKER_SIZE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      marker_notes_dat(num_markers)%size
c     USE_GRAPH_COORDINATES 
      else if( key .eq. 'USE_GRAPH_COORDINATES' ) then
         marker_notes_dat(num_markers)%use_graph_coords = .TRUE.
c
c     Unknown key
      else
         call perror_write(1, iline, ipos, key, item, buffer)
         perr = .TRUE.
      endif
      goto 1000
c
c     Error on read of values from buffer
2000  call perror_write(2, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
4000  continue
c
      return
      end
c
      subroutine parse_ellipse_note
      implicit none
c
c     Parse ellipse annotation lines
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'units.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'parser.cmn'
c
      integer itype, pm_color_to_index
      logical check_command
c
1000  call next_line
c     End of file?
      if( feof ) then
         goto 4000
c     Next line is a command  line?
      else if( check_command() ) then
         goto 4000
c     Parse ellipse annotations commands
c
c     X_LOC = {real}
      else if( key .eq. 'X_LOC' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      ellipse_notes_dat(num_ellipses)%x1
c     Y_LOC = {real}
      else if( key .eq. 'Y_LOC' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      ellipse_notes_dat(num_ellipses)%y1
c
c     X_LOC2 = {real}
      else if( key .eq. 'X_LOC2' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      ellipse_notes_dat(num_ellipses)%x2
c     Y_LOC2 = {real}
      else if( key .eq. 'Y_LOC2' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      ellipse_notes_dat(num_ellipses)%y2
c
c     X_LOC3 = {real}
      else if( key .eq. 'X_LOC3' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      ellipse_notes_dat(num_ellipses)%x3
c     Y_LOC3 = {real}
      else if( key .eq. 'Y_LOC3' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000)
     1      ellipse_notes_dat(num_ellipses)%y3
c     COLOR = {num}
      else if( key .eq. 'COLOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
c        Try to decode marker type
         itype = pm_color_to_index(item)
         if( itype .eq. -1 ) goto 2000
         ellipse_notes_dat(num_ellipses)%color = itype
c     USE_GRAPH_COORDINATES 
      else if( key .eq. 'USE_GRAPH_COORDINATES' ) then
         ellipse_notes_dat(num_ellipses)%use_graph_coords = .TRUE.
c
c     Unknown key
      else
         call perror_write(1, iline, ipos, key, item, buffer)
         perr = .TRUE.
      endif
      goto 1000
c
c     Error on read of values from buffer
2000  call perror_write(2, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
4000  continue
c
      return
      end
c
      subroutine parse_global
      implicit none
c
c     Parse global defaults
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'units.cmn'
      include 'defaults.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'parser.cmn'
c
      logical check_command
      real rtmp
      integer i, color_index, itmp, ierr, pm_decode_psfont,
     1        pm_color_to_rgb
c
1000  call next_line
c     End of file?
      if( feof ) then
         goto 4000
c     Next line is a command  line?
      else if( check_command() ) then
         goto 4000
c     Parse global commands
c     HIDDEN_LINE_METHOD = {device, painter, horizon}
      else if( key .eq. 'HIDDEN_LINE_METHOD' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         if( item(1:1) .eq. 'C' ) then
            default_hidden_method = HIDDEN_LINES_WITH_FILL_AREA
         else if( item(1:3) .eq. 'HID' ) then
            default_hidden_method = HIDDEN_LINES_WITH_HORIZON_FCN
         else if( item(1:3) .eq. 'HIS' ) then
            default_hidden_method = HIDDEN_LINES_HISTOGRAM
         else
            default_hidden_method = 0
         endif
c     PLOT_SCALE_FACTOR = {real}
      else if( key .eq. 'PLOT_SCALE_FACTOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) rtmp
         plot_scale_factor = MAX(MIN(rtmp,1.0),0.1)
c     LENGTH_UNIT_NAME_AND_SCALE = {nonblank_string,  real}
      else if( key .eq. 'LENGTH_UNIT_NAME_AND_SCALE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         pm_length_unit = item
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) rtmp
         if( rtmp .le. 0.0 ) goto 2000
         pm_scale_plot2cm = rtmp
         pm_scale_cm2plot = 1.0/pm_scale_plot2cm
c     LINEWIDTH_SCALE = {real}
      else if( key .eq. 'LINEWIDTH_SCALE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) rtmp
         global_linewidth_scale = MAX(MIN(rtmp,5.0),0.1)
c     COLOR_nn = {real real real} or {color-string}
      else if( key(1:6) .eq. 'COLOR_' .and.
     1         (klen .eq. 7 .or. klen .eq. 8) ) then
         read(key(7:klen),2100,end=2000,err=2000) color_index
2100     format(i2)
         if( color_index .gt. MAX_RGB_VALUES .or.
     1       color_index .lt. 0 ) goto 2000
c        First, look for named color
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call lowercase(item)
         ierr = pm_color_to_rgb(item,
     1        rgb(color_index,1),rgb(color_index,2),rgb(color_index,3))
c        If error, look for RGB numeric values
         if( ierr .eq. 0 ) then
c           Known color, store name so we can reference it later
            color_names(color_index) = item
         else
            read(item,*,end=2000,err=2000) rgb(color_index,1)
            do 2200 i=2,3
               call get_keyword(buffer,item,ipos)
               if( ipos .eq. 0 ) goto 2000
               read(item,*,end=2000,err=2000) rgb(color_index,i)
2200        continue
c           Unknown color, store name so we can reference it later
            if( color_index .lt. 10 ) then
               write(color_names(color_index),100) color_index
100            format('userdefined',i1)
            else
               write(color_names(color_index),101) color_index
101            format('userdefined',i2)
            endif
         endif
         l_rgb(color_index) = .TRUE.
c     PS_FONT_ID = {int}
c     Changes font used by GKS for all PostScript devices
      else if( key .eq. 'PS_FONT_ID' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         itmp = pm_decode_psfont(item)
         if( itmp .eq. 0 )
     1      read(item,*,end=2000,err=2000) itmp
         ps_font_id = itmp
c     FONT_ID = {int}
c     Changes font used by GKS for all devices except VTxxx and PostScript
c     VTxxx use hardware fonts for speed and legibility.
      else if( key .eq. 'FONT_ID' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) itmp
         default_font_id = itmp
c     TEXT_SCALE = {real}
      else if( key .eq. 'TEXT_SCALE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) rtmp
         if( rtmp .le. 0.1 ) goto 2000
         global_text_scale = rtmp
c     SUPPRESS_LABELS
      else if( key .eq. 'SUPPRESS_LABELS' ) then
         comp_nolabels = .TRUE.
c     CURV_MODE
      else if( key .eq. 'CURV_MODE' ) then
         l_curv = .TRUE.
c     GRID
      else if( key .eq. 'GRID' ) then
c        This is kinda hacky. We just turn on the grid flags in the
c        axis data structures. This is mainly a convenience
c        for CURV emulation.
         axis_dat(1)%major_grid = .TRUE.
         axis_dat(1)%minor_grid = .TRUE.
         axis_dat(2)%major_grid = .TRUE.
         axis_dat(2)%minor_grid = .TRUE.
c
c     UNIT_DELIMITERS = 2 character string, e.g. () or []
      else if( key .eq. 'UNIT_DELIMITERS' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         left_unit_delim  = item(1:1)
         right_unit_delim = item(2:2)
c
c     NOTE: the following keys HC_XXXX apply to the hardcopy device only
c           jvf 12-Oct-94
c
c     HC_ORIENTATION = {landscape, portrait}
      else if( key .eq. 'HC_ORIENTATION' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         if( item(1:1) .eq. 'P' ) then
            hc_is_landscape = .FALSE.
         else
            hc_is_landscape = .TRUE.
         endif
c     HC_SCALE_FACTOR = {real}
      else if( key .eq. 'HC_SCALE_FACTOR' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) rtmp
         hc_scale = MAX(MIN(rtmp,1.0),0.1)
c     HC_ASPECT_RATIO = {real}
      else if( key .eq. 'HC_ASPECT_RATIO' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) rtmp
         hc_aspect_ratio = MAX(MIN(rtmp,2.0),0.1)
c     HARDCOPY_DEVICE = {nonblank_string}
      else if( key .eq. 'HARDCOPY_DEVICE' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call upcase(item)
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         if( item .eq. 'COLOR_POSTSCRIPT' ) then
            hardcopy_device = GKS$K_COLOR_POSTSCRIPT
         else if( item .eq. 'POSTSCRIPT' ) then
            hardcopy_device = GKS$K_POSTSCRIPT
         else if( item .eq. 'COLOR_EPS' ) then
            hardcopy_device = GKS$K_COLOR_EPSF
         else if( item .eq. 'EPS' ) then
            hardcopy_device = GKS$K_EPSF
         else if( item .eq. 'HPGL' ) then
            hardcopy_device = GKS$K_HP7550
         else if( item .eq. 'LN03' ) then
            hardcopy_device = GKS$K_LN03_PLUS
         else if( item .eq. 'LJ250' ) then
            hardcopy_device = GKS$K_LJ250
         else if( item .eq. 'LJ250_HIGHRES' ) then
            hardcopy_device = GKS$K_LJ250_180DPI
         else if( item .eq. 'DDIF' ) then
            hardcopy_device = GKS$K_DDIF
         else
            goto 2000
         endif
c     HC_XOFFSET = {real}
      else if( key .eq. 'HC_XOFFSET' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) rtmp
         hc_xoffset = MAX(MIN(rtmp,1.0),0.0)
c     HC_YOFFSET = {real}
      else if( key .eq. 'HC_YOFFSET' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         read(item,*,end=2000,err=2000) rtmp
         hc_yoffset = MAX(MIN(rtmp,1.0),0.0)
c     The following keys: HC_FILENAME
c     are experimental and undocumented
c     HC_FILENAME = {nonblank_string}
      else if( key .eq. 'HC_FILENAME' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) goto 2000
         call dequote_string(item,ierr)
         if( ierr .ne. 0 ) goto 3000
         given_plotfilename = item
         lplotfile = .TRUE.
c
c     NOTE: the following keys BATCH are
c           experimental and not yet documented. jvf 24-Feb-92
c
c     BATCH = {yes, no}
      else if( key .eq. 'BATCH' ) then
         call get_keyword(buffer,item,ipos)
         if( ipos .eq. 0 ) then
            lbatch = .TRUE.
         else
            call upcase(item)
            if( item(1:1) .eq. 'Y' ) then
               lbatch = .TRUE.
            else if( item(1:1) .eq. 'N' ) then
               lbatch = .FALSE.
            else
               lbatch = .TRUE.
            endif
         endif
c     Unknown key
      else
         call perror_write(1, iline, ipos, key, item, buffer)
         perr = .TRUE.
      endif
      goto 1000
c
c     Error on read of values from buffer
2000  call perror_write(2, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
c     Error in string quoting
3000  call perror_write(3, iline, ipos, key, item, buffer)
      perr = .TRUE.
      goto 1000
c
4000  continue
c
      return
      end
c
      integer function pm_decode_psfont(string)
      implicit none
c
      character*(*) string
c
      call upcase(string)
c
      if ( string .eq. 'TIMES_ROMAN' ) then
         pm_decode_psfont = -101
      else if ( string .eq. 'TIMES_ITALIC' ) then
         pm_decode_psfont = -102
      else if ( string .eq. 'TIMES_BOLD' ) then
         pm_decode_psfont = -103
      else if ( string .eq. 'TIMES_BOLD_ITALIC' ) then
         pm_decode_psfont = -104
      else if ( string .eq. 'HELVETICA' ) then
         pm_decode_psfont = -105
      else if ( string .eq. 'HELVETICA_OBLIQUE' ) then
         pm_decode_psfont = -106
      else if ( string .eq. 'HELVETICA_BOLD' ) then
         pm_decode_psfont = -107
      else if ( string .eq. 'HELVETICA_BOLD_OBLIQUE' ) then
         pm_decode_psfont = -108
      else if ( string .eq. 'COURIER' ) then
         pm_decode_psfont = -109
      else if ( string .eq. 'COURIER_OBLIQUE' ) then
         pm_decode_psfont = -110
      else if ( string .eq. 'COURIER_BOLD' ) then
         pm_decode_psfont = -111
      else if ( string .eq. 'COURIER_BOLD_OBLIQUE' ) then
         pm_decode_psfont = -112
      else
         pm_decode_psfont = 0
      endif
c
      return
      end
c
      subroutine pm_lookup_psfontid(fontid,string)
      implicit none
c
      integer fontid
      character*(*) string
c
      if ( fontid .eq. -101 ) then
         string = 'times_roman'
      else if ( fontid .eq. -102 ) then
         string = 'times_italic'
      else if ( fontid .eq. -103 ) then
         string = 'times_bold' 
      else if ( fontid .eq. -104 ) then
         string = 'times_bold_italic' 
      else if ( fontid .eq. -105 ) then
         string = 'helvetica' 
      else if ( fontid .eq. -106 ) then
         string = 'helvetica_oblique' 
      else if ( fontid .eq. -107 ) then
         string = 'helvetica_bold' 
      else if ( fontid .eq. -108 ) then
         string = 'helvetica_bold_oblique' 
      else if ( fontid .eq. -109 ) then
         string = 'courier' 
      else if ( fontid .eq. -110 ) then
         string = 'courier_oblique' 
      else if ( fontid .eq. -111 ) then
         string = 'courier_bold' 
      else if ( fontid .eq. -112 ) then
         string = 'courier_bold_oblique' 
      else
         string = 'helvetica_bold'
      endif
c
      return
      end
c
      subroutine pm_encode_symbol(itype, string)
      implicit none
c
      integer itype
      character*(*) string
c
      if ( itype .eq. 1 ) then
         string = 'CIRCLE'
      else if ( itype .eq. 2 ) then
         string = 'SQUARE'
      else if ( itype .eq. 3 ) then
         string = 'TRIANGLE_UP'
      else if ( itype .eq. 4 ) then
         string = 'TRIANGLE_DOWN'
      else if ( itype .eq. 5 ) then
         string = 'SOLID_CIRCLE'
      else if ( itype .eq. 6 ) then
         string = 'SOLID_SQUARE'
      else if ( itype .eq. 7 ) then
         string = 'SOLID_TRIANGLE_UP'
      else if ( itype .eq. 8 ) then
         string = 'SOLID_TRIANGLE_DOWN'
      else if ( itype .eq. 9 ) then
         string = 'DOT'
      else if ( itype .eq. 10 ) then
         string = 'PLUS'
      else if ( itype .eq. 11 ) then
         string = 'ASTERISK'
      else if ( itype .eq. 12 ) then
         string = 'CROSS'
      else if ( itype .eq. 13 ) then
         string = 'BOWTIE'
      else if ( itype .eq. 14 ) then
         string = 'HOURGLASS'
      else if ( itype .eq. 15 ) then
         string = 'DIAMOND'
      else if ( itype .eq. 16 ) then
         string = 'FILLED_BOWTIE'
      else if ( itype .eq. 17 ) then
         string = 'FILLED_HOURGLASS'
      else if ( itype .eq. 18 ) then
         string = 'FILLED_DIAMOND'
      else
         write(string,'(I5)') itype
      endif
c
      return
      end
c
c
      subroutine pm_encode_linetype(itype, string)
      implicit none
c
      integer itype
      character*(*) string
c
      if( itype .eq. 1 ) then
         string = 'SOLID'
      else if ( itype .eq. 2 ) then
         string = 'DASHED'
      else if ( itype .eq. 3 ) then
         string = 'DOTTED'
      else if ( itype .eq. 4 ) then
         string = 'DASH_DOT'
      else if ( itype .eq. 5 ) then
         string = 'DASH_2_DOT'
      else if ( itype .eq. 6 ) then
         string = 'DASH_3_DOT'
      else if ( itype .eq. 7 ) then
         string = 'LONG_DASH'
      else if ( itype .eq. 8 ) then
         string = 'LONG_SHORT_DASH'
      else if ( itype .eq. 9 ) then
         string = 'SPACED_DASH'
      else if ( itype .eq. 10 ) then
         string = 'SPACED_DOT'
      else if ( itype .eq. 11 ) then
         string = 'DOUBLE_DOT'
      else if ( itype .eq. 12 ) then
         string = 'TRIPLE_DOT'
      else
         write(string,'(I5)') itype
      endif
c
      return
      end
c
      subroutine copy_curv_axis_parms_to_save(iaxis)
      implicit none
c
      integer iaxis
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
c     A quick and dirty solution to storing the curv axis parameters
c     from the 'sticky' area in the compare common block.
c     A cleaner alternative would have been to modify the two
c     copy_axis_to_saveN subroutines to include all these arguments,
c     but I'm getting lazy and those arg lists are long enough!
c
      integer ix
c
c     First, we don't support the curv axis parameters for 1D/2D/3D plots...
      if( iaxis .eq. 3 .or.
     1    save_plot_type .ne. PLOT_COMPARE_COMMAND ) return
c
      if( iaxis .eq. 1 .or. iaxis .eq. 4 ) then
c        Do x axes
         if( iaxis .eq. 1 ) then
            ix = 1
         else
            ix = 2
         endif
         if( comp_h_log(ix) ) then
            axis_dat(iaxis)%minor_tic_size = comp_h_lminortic_size(ix)
         else
            axis_dat(iaxis)%minor_tic_size = comp_h_minortic_size(ix)
         endif
         axis_dat(iaxis)%major_tic_factor = comp_h_majortic_factor(ix)
         axis_dat(iaxis)%thickness = comp_h_thickness(ix)
         axis_dat(iaxis)%color = comp_h_color(ix)
         axis_dat(iaxis)%nonumbering = comp_h_nonumbering(ix)
         axis_dat(iaxis)%omit = comp_h_omit(ix)
         axis_dat(iaxis)%format = comp_h_format(ix)
         axis_dat(iaxis)%major_grid = comp_h_major_grid(ix)
         axis_dat(iaxis)%minor_grid = comp_h_minor_grid(ix)
         axis_dat(iaxis)%major_grid_linetype =
     1                   comp_h_major_grid_linetype(ix)
         axis_dat(iaxis)%minor_grid_linetype =
     1                   comp_h_minor_grid_linetype(ix)
      else
c        Now y axes
         if( iaxis .eq. 2 ) then
            ix = 1
         else
            ix = 2
         endif
         if( comp_v_log(ix) ) then
            axis_dat(iaxis)%minor_tic_size = comp_v_lminortic_size(ix)
         else
            axis_dat(iaxis)%minor_tic_size = comp_v_minortic_size(ix)
         endif
         axis_dat(iaxis)%minor_tic_size = comp_v_minortic_size(ix)
         axis_dat(iaxis)%major_tic_factor = comp_v_majortic_factor(ix)
         axis_dat(iaxis)%thickness = comp_v_thickness(ix)
         axis_dat(iaxis)%color = comp_v_color(ix)
         axis_dat(iaxis)%nonumbering = comp_v_nonumbering(ix)
         axis_dat(iaxis)%omit = comp_v_omit(ix)
         axis_dat(iaxis)%format = comp_v_format(ix)
         axis_dat(iaxis)%major_grid = comp_v_major_grid(ix)
         axis_dat(iaxis)%minor_grid = comp_v_minor_grid(ix)
         axis_dat(iaxis)%major_grid_linetype =
     1                   comp_v_major_grid_linetype(ix)
         axis_dat(iaxis)%minor_grid_linetype =
     1                   comp_v_minor_grid_linetype(ix)
      endif
c
      return
      end
