# GNUPLOT+.PY
# Dominic Ford
# 12/04/2006

VERSION = "0.3.0"
DATE    = "12/04/2006"

exitting = 0

import gp_settings
import gp_eval
import gp_fit
import gp_plot
from gp_autocomplete import *

import os
import sys
import readline
from math import *
import re

# FLOATPRINT(): Prints a float in floating point or exponential format, as appropriate

def floatprint(x):
  if ((fabs(x) < 1e10) and (fabs(x) > 1e-6)): return "%f"%x
  else:                                       return "%e"%x

# READ_COORD_SYST(): Read screen, graph, first or second modifiers

def read_coord_syst(string):
  if  ((string == None) or (len(string) == 0) or
       autocomplete(string, "first", 1)          ): return 'first'
  elif autocomplete(string, "second", 1)          : return 'second'
  elif autocomplete(string, "graph", 1)           : return 'graph'
  elif autocomplete(string, "screen", 1)          : return 'screen'
  else:
    print string
    raise UserIsAFuckwitError

# Directive Show

def directive_show(line,linelist):
  if (len(linelist) > 1):
   if ((linelist[1] == "settings") or (linelist[1] == "all")):
    print "Plot Title:   '%s' at offset (%f,%f)"%(gp_settings.settings['TITLE'],gp_settings.settings['TIT_XOFF'],gp_settings.settings['TIT_YOFF'])
    print "Terminal type: %s"%gp_settings.settings['TERMTYPE']
    print "Output fname:  %s"%gp_settings.settings['OUTPUT']
    print "Output width:  %s"%gp_settings.settings['WIDTH']
    if (gp_settings.settings['AUTOASPECT'] == "ON"): print "Output aspect: <auto>"
    else                                           : print "Output aspect: %f"%gp_settings.settings['ASPECT']
    print "Colour:        %s"%gp_settings.settings['COLOUR']
    print "Key:           %s"%gp_settings.settings['KEY']
    print "Key position:  %s, with offset (%f,%f)"%(gp_settings.settings['KEYPOS'],gp_settings.settings['KEY_XOFF'],gp_settings.settings['KEY_YOFF'])
    print "Grid:          %s"%gp_settings.settings['GRID']
    print "Pointsize:     %f"%gp_settings.settings['POINTSIZE']
    print

   if ((linelist[1] == "plotting") or (linelist[1] == "all")):
    print "Data style:    %s"%gp_settings.settings['DATASTYLE']
    print "Function style:%s"%gp_settings.settings['FUNCSTYLE']
    print "Samples        %d (no of samples used when plotting functions)"%gp_settings.settings['SAMPLES']
    print

   if ((linelist[1] == "linestyle") or (linelist[1] == "all")):
    print "Linestyles:\n"
    for i,definition in gp_settings.linestyles.iteritems():
      print "  linestyle %d: %s"%(i,definition)
    print

   if ((linelist[1] == "arrow") or (linelist[1] == "all")):
    print "Arrows:\n"
    for i,definition in gp_settings.arrows.iteritems():
      print "  arrow %d: (%s %s,%s %s) to (%s %s,%s %s) %s"%(i, definition[0], floatprint(definition[1]), definition[2], floatprint(definition[3]), definition[4], floatprint(definition[5]), definition[6], floatprint(definition[7]), definition[8])
    print

   if ((linelist[1] == "label") or (linelist[1] == "all")):
    print "Text labels:\n"
    for i,definition in gp_settings.labels.iteritems():
      print "  label %d: %s at (%s %s,%s %s)"%(i, definition[0], definition[1], floatprint(definition[2]), definition[3], floatprint(definition[4]))
    print

   if ((linelist[1] == "axes") or (linelist[1] == "all")):
    for [direction , direction_axes] in gp_settings.axes.iteritems():
     for [axis_number, axis] in direction_axes.iteritems():
      print "Setting for %s%s axis:"%(direction,axis_number)
      print "  Label:     %s"%axis['LABEL']
      print "  Autoscale: %s"%axis['AUTOSCALE']
      print "  Range:    (%s --> %s)"%(floatprint(axis['MIN']), floatprint(axis['MAX']))
      print "  Log:       %s"%axis['LOG']
      print

   if ((linelist[1] == "vars") or (linelist[1] == "variables") or (linelist[1] == "all")):
    print "Variables:"
    for x,y in gp_settings.variables.iteritems():
      print "%s = %s"%(x,floatprint(y))

    print
    print "User-Defined Functions:"
    for x,y in gp_settings.functions.iteritems():
      print "%s = %s"%(x,y)
    print

   if ((linelist[1] == "arrow") or (linelist[1] == "vars") or (linelist[1] == "variables") or (linelist[1] == "all") or (linelist[1] == "axes") or (linelist[1] == "plotting") or (linelist[1] == "label") or (linelist[1] == "linestyle") or (linelist[1] == "settings")):
    return
  os.system("cat %s/txt/show.txt"%PATH)
  return

# Directive Set

def directive_set(line,linelist):
    if (len(linelist) < 2):
      os.system("cat %s/txt/set.txt"%PATH)
      return

    if autocomplete(linelist[1],"title",2): # set title
      test = re.match(r"""^set?\s*\S*\s*('|")(.*)('|")\s*([-.\d]*)\s*(,\s*([-.\d]*))?""",line)
      if (test == None):
        print "Title should be placed in quotes, and followed optionally by xoffset,yoffset. Defaulting to blank title."
        gp_settings.settings['TITLE']=""
      else:
        gp_settings.settings['TITLE']=test.group(2)
        try:
         if ((test.group(4) != "") and (test.group(4) != None)): gp_settings.settings['TIT_XOFF'] = float(test.group(4))
         if ((test.group(6) != "") and (test.group(5) != None)): gp_settings.settings['TIT_YOFF'] = float(test.group(6))
        except:
         print "Could not read positional offsets (%s,%s)"%(test.group(4),test.group(6))
      return

    if (autocomplete(linelist[1],"width",1)  # set width # EXTENDED API
        or (autocomplete(linelist[1],"size",1) and (len(linelist) == 3) and (linelist[2].strip()[0] < 'A'))): # take care not to catch set size ratio
      if autocomplete(linelist[1],"size",1):
       print "Warning: 'set size <n>' is depreciated API. Reverting to gnuplot+ extended API function 'set width', setting width in centimetres."
      test = re.match(r"""^set?\s*\S*\s*(.*)""",line)
      if (test == None):
        print "Error reading width."
      else:
        try:
          gp_settings.settings['WIDTH'] = gp_eval.gp_eval(test.group(1),gp_settings.variables,gp_settings.functions)
        except:
          print "Could not read width. Should be a floating point value"
      return

    if autocomplete(linelist[1],"size",2): # set size
     if (len(linelist) > 2):
      if autocomplete(linelist[2],"ratio",1): # set size ratio <n>
       try:
        test = re.match(r"""^set?\s*\S*\s*\S*\s*(.*)""",line)
        new_aspect = gp_eval.gp_eval(test.group(1),gp_settings.variables,gp_settings.functions)
        if (new_aspect <= 0.0):
          print "Error: aspect ratio must be a value greater than zero"
          raise ValueError
        gp_settings.settings['ASPECT'] = new_aspect
        gp_settings.settings['AUTOASPECT'] = 'OFF'
       except:
        print "Error reading aspect ratio"
       return
     if (len(linelist) == 3):
      if autocomplete(linelist[2],"noratio",1): # set size noratio
       gp_settings.settings['AUTOASPECT'] = 'ON'
       return
     if (len(linelist) == 3):
      if autocomplete(linelist[2],"square",1): # set size square
       gp_settings.settings['ASPECT'] = 1.0
       gp_settings.settings['AUTOASPECT'] = 'OFF'
       return

    if autocomplete(linelist[1],"samples",1): # set samples
      test = re.match(r"""^set?\s*\S*\s*(.*)""",line)
      if (test == None):
        print "Error reading number of samples."
      else:
        try:
          gp_settings.settings['SAMPLES']=int(test.group(1))
        except:
          print "Could not read number of samples. Should be an integer value"
      return

    if autocomplete(linelist[1],"pointsize",1): # set pointsize
      test = re.match(r"""^set?\s*\S*\s*(.*)""",line)
      if (test == None):
        print "Error reading pointsize"
      else:
        try:
          gp_settings.settings['POINTSIZE']=float(test.group(1))
        except:
          print "Could not reading pointsize. Should be a floating point value"
      return

    if autocomplete(linelist[1],"linestyle",1): # set linestyle
      test = re.match(r"""^set?\s*\S*\s*([0-9][0-9]*)\s*(.*)""",line)
      if (test == None):
        print "Error reading linestyle. Use format: set linestyle <number> <linestyle>"
      else:
        try:
          ls_number = int(test.group(1))
        except:
          print "linestyle number must be specified as an integer"
          return
        try:
          gp_settings.linestyles[ls_number] = test.group(2)
        except:
          print "Unexpected error whilst writing linestyle %d"%ls_number
      return

    if autocomplete(linelist[1],"nolinestyle",3): # set nolinestyle
      test = re.match(r"""^set?\s*\S*\s*([0-9][0-9]*)""",line)
      if (test == None):
        print "Error reading nolinestyle. Use format: set nolinestyle <number>"
      else:
        try:
          ls_number = int(test.group(1))
        except:
          print "linestyle number must be specified as an integer."
          return
        try:
          del gp_settings.linestyles[ls_number] # Delete key from linestyle dictionary
        except:
          print "Error removing linestyle %d -- no such linestyle."%ls_number
      return

    if autocomplete(linelist[1],"arrow",1): # set arrow
      try:
        gc=r"(([a-z]*)\s\s*)?([^,\s][^,\s]*)" # get coordinate -- matches, e.g. "first 7.5"
        nc=r"[,\s][,\s]*" # next coordinate -- matches commas and spaces
        test = re.match(r"^set?\s\s*\S*\s\s*([0-9][0-9]*)\s\s*from\s\s*"+gc+nc+gc+"\s\s*to\s\s*"+gc+nc+gc+"\s*(\S*)\s*$""",line)
        arrow_number = int(test.group(1))
        coord0x      = read_coord_syst(test.group(3))
        x0           = float(test.group(4))
        coord0y      = read_coord_syst(test.group(6))
        y0           = float(test.group(7))
        coord1x      = read_coord_syst(test.group(9))
        x1           = float(test.group(10))
        coord1y      = read_coord_syst(test.group(12))
        y1           = float(test.group(13))
        if ((len(test.group(14)) == 0) or
             autocomplete(test.group(14),"head",1)  ): arrow_style = "head"
        elif autocomplete(test.group(14),"nohead",1) : arrow_style = "nohead"
        elif autocomplete(test.group(14),"twoway",1) : arrow_style = "twoway"                      
      except:
        print "Error reading arrow. Use format: set arrow from (first|second|screen|graph) x y to (first|second|screen|graph) x y"
        return
      try:
        gp_settings.arrows[arrow_number] = (coord0x, x0, coord0y, y0, coord1x, x1, coord1y, y1, arrow_style)
      except:
        print "Unexpected error whilst writing arrow %d"%arrow_number
      return

    if autocomplete(linelist[1],"noarrow",2): # set noarrow
      test = re.match(r"""^set?\s*\S*\s*([0-9][0-9]*)""",line)
      if (test == None):
        print "Error reading noarrow. Use format: set noarrow <number>"
      else:
        try:
          arrow_number = int(test.group(1))
        except:
          print "arrow number must be specified as an integer."
          return
        try:
          del gp_settings.arrows[arrow_number] # Delete key from linestyle dictionary
        except:
          print "Error removing arrow %d -- no such arrow."%arrow_number
      return

    if autocomplete(linelist[1],"grid",1):   # set grid
      gp_settings.settings['GRID']='ON'
      return
    if autocomplete(linelist[1],"nogrid",3): # set nogrid
      gp_settings.settings['GRID']='OFF'
      return

    if autocomplete(linelist[1],"label",2):  # set label
      try:
        gc=r"(([a-z]*)\s\s*)?([^,\s][^,\s]*)" # get coordinate -- matches, e.g. "first 7.5"
        nc=r"[,\s][,\s]*" # next coordinate -- matches commas and spaces
        test = re.match(r"""^set?\s\s*\S*\s\s*([0-9][0-9]*)\s*('|")(.*)('|")\s\s*at\s\s*"""+gc+nc+gc+"\s*$""",line)
        label_number = int(test.group(1))
        text         =     test.group(3)
        coordx       = read_coord_syst(test.group(6))
        x            = float(test.group(7))
        coordy       = read_coord_syst(test.group(9))
        y            = float(test.group(10))
      except:
        print "Error reading label. Use format: set label <number> 'text' at (first|second|screen|graph) x (first|second|screen|graph) y"
        print "Error:" , sys.exc_info()[1], "(" , sys.exc_info()[0] , ")"
        return
      try:
        gp_settings.labels[label_number] = (text, coordx, x, coordy, y)
      except:
        print "Unexpected error whilst writing label %d"%label_number
      return

    if autocomplete(linelist[1],"nolabel",4): # set nolabel
      test = re.match(r"""^set?\s*\S*\s*([0-9][0-9]*)""",line)
      if (test == None):
        print "Error reading nolabel. Use format: set nolabel <number>"
      else:
        try:
          label_number = int(test.group(1))
        except:
          print "label number must be specified as an integer."
          return
        try:
          del gp_settings.labels[label_number] # Delete key from label dictionary
        except:
          print "Error removing label %d -- no such label."%label_number
      return

    if ((len(linelist) > 2) and autocomplete(linelist[2],"style",1)):
      key=""
      if autocomplete(linelist[1],"data",1):
        key = "DATASTYLE" ; name = "data"
      if autocomplete(linelist[1],"function",1):
        key = "FUNCSTYLE" ; name = "function"
      if (len(key) > 0):
        test = re.match(r"""^set?\s*\S*\s*\S*\s*(.*)""",line)
        if ((test == None) or (len(test.group(1)) == 0)):
          print "Error reading %s style"%name
          return
        else:
          if autocomplete(test.group(1),"lines",1)      : gp_settings.settings[key] = 'lines'      ; return
          if autocomplete(test.group(1),"points",1)     : gp_settings.settings[key] = 'points'     ; return
          if autocomplete(test.group(1),"lp",2)         : gp_settings.settings[key] = 'linespoints'; return
          if autocomplete(test.group(1),"linespoints",5): gp_settings.settings[key] = 'linespoints'; return
          if autocomplete(test.group(1),"xerrorbars",2) : gp_settings.settings[key] = 'xerrorbars' ; return
          if autocomplete(test.group(1),"yerrorbars",2) : gp_settings.settings[key] = 'yerrorbars' ; return
          if autocomplete(test.group(1),"xyerrorbars",2): gp_settings.settings[key] = 'xyerrorbars'; return
          print "Unknown %s style: '%s'"%(name,test.group(1))
          return

    if autocomplete(linelist[1],"output",1) : # set output
      test = re.match(r"""^set?\s*\S*\s*('|")(.*)('|")""",line)
      if (test == None):
        print "Output filename should be placed in quotes."
      else:
        gp_settings.settings['OUTPUT']=test.group(2)
      return

    if autocomplete(linelist[1],"key",1): # set key
      gp_settings.settings['KEY']='ON'
      if (len(linelist) > 2):
       gp_settings.settings['KEY_XOFF'] = gp_settings.settings['KEY_YOFF'] = 0.0 # Reset offset if position is specified
      keymode = 0 # First offset is x offset
      for i in range(2,len(linelist),1):
        try:
         offset = float(linelist[i])
         if (keymode == 0): gp_settings.settings['KEY_XOFF'] = offset
         if (keymode == 1): gp_settings.settings['KEY_YOFF'] = offset
         if (keymode <  2): keymode = keymode + 1
         else             : raise ValueError
         continue
        except: pass
        if (len(gp_settings.settings['KEYPOS'].split()) != 2): gp_settings.settings['KEYPOS'] = "TOP RIGHT" # Deal with if previously "below"
        if autocomplete(linelist[i],"top"    ,1): gp_settings.settings['KEYPOS'] = 'TOP '    + gp_settings.settings['KEYPOS'].split()[1] ; continue
        if autocomplete(linelist[i],"bottom" ,1): gp_settings.settings['KEYPOS'] = 'BOTTOM ' + gp_settings.settings['KEYPOS'].split()[1] ; continue
        if autocomplete(linelist[i],"ycentre",1): gp_settings.settings['KEYPOS'] = 'MIDDLE ' + gp_settings.settings['KEYPOS'].split()[1] ; continue
        if autocomplete(linelist[i],"left"   ,1): gp_settings.settings['KEYPOS'] = gp_settings.settings['KEYPOS'].split()[0] + ' LEFT'   ; continue
        if autocomplete(linelist[i],"right"  ,1): gp_settings.settings['KEYPOS'] = gp_settings.settings['KEYPOS'].split()[0] + ' RIGHT'  ; continue
        if autocomplete(linelist[i],"xcentre",1): gp_settings.settings['KEYPOS'] = gp_settings.settings['KEYPOS'].split()[0] + ' MIDDLE' ; continue
        if autocomplete(linelist[i],"below"  ,2): gp_settings.settings['KEYPOS'] = "BELOW"                                               ; continue
        if autocomplete(linelist[i],"outside",1): gp_settings.settings['KEYPOS'] = "OUTSIDE"                                             ; continue
        print "Unrecognised word: %s"%linelist[i]
      return

    if autocomplete(linelist[1],"nokey",3): # set nokey
      gp_settings.settings['KEY']='OFF'
      return

    if autocomplete(linelist[1],"terminal",1): # set terminal
      for i in range(2,len(linelist),1):
        if autocomplete(linelist[i],"x11_singlewindow",1): gp_settings.settings['TERMTYPE'] = "X11_singlewindow" ; continue
        if autocomplete(linelist[i],"x11_multiwindow" ,1): gp_settings.settings['TERMTYPE'] = "X11_multiwindow"  ; continue
        if autocomplete(linelist[i],"postscript"      ,1): gp_settings.settings['TERMTYPE'] = "EPS"              ; continue
        if autocomplete(linelist[i],"eps"             ,1): gp_settings.settings['TERMTYPE'] = "EPS"              ; continue
        if autocomplete(linelist[i],"color"           ,1): gp_settings.settings['COLOUR']   = "ON"               ; continue
        if autocomplete(linelist[i],"colour"          ,1): gp_settings.settings['COLOUR']   = "ON"               ; continue
        if autocomplete(linelist[i],"monochrome"      ,1): gp_settings.settings['COLOUR']   = "OFF"              ; continue
        print "Unrecognised word: %s"%linelist[i]
      return

    test = re.match("""^set?\s*(x|y|z)(\d*)l""",line) # set label
    if (test != None):
     name = test.group(1) + test.group(2)
     if autocomplete(linelist[1],"%slabel"%name,3):
      try:
       direction =     test.group(1)
       if (len(test.group(2)) == 0): number = 1
       else                        : number    = int(test.group(2))
       if (number < 1): raise ValueError # Don't let user assign axis zero!
      except ValueError:
       print "Illegal axis number in set %s<n>label statement"%test.group(1)
       return
      if (not number in gp_settings.axes[direction]): gp_settings.axes[direction][number] = gp_settings.default_axis.copy() # Create axis if it doesn't already exist
      test = re.match("""^set?\s*\S*\s*('|")(.*)('|")""",line)
      if (test == None):
       print "Label should be placed in quotes. Defaulting to blank title"
       gp_settings.axes[direction][number]['LABEL']=""
      else:
       gp_settings.axes[direction][number]['LABEL'] = test.group(2)
      if (not number in gp_plot.axes_this[direction]):                  # Modify axes_this is gp_plot, so that replot takes account of changes
       gp_plot.axes_this[direction][number] = {'SETTINGS':gp_settings.axes[direction][number].copy(), 'MIN_USED':None, 'MAX_USED':None, 'AXIS':None}
      else:
       gp_plot.axes_this[direction][number]['SETTINGS']['LABEL'] = gp_settings.axes[direction][number]['LABEL']
      return

    if ((autocomplete(linelist[1],"autoscale",2)) or (autocomplete(linelist[1],"log",2)) or (autocomplete(linelist[1],"nolog",3))): # set log or nolog or autoscale
     if   autocomplete(linelist[1],"autoscale",2): key = "AUTOSCALE" ; keyset = "ON"
     elif autocomplete(linelist[1],"log",2)      : key = "LOG"       ; keyset = "ON"
     else                                        : key = "LOG"       ; keyset = "OFF"
     if (len(linelist)>2):
      for i in range(2,len(linelist)):
       word = linelist[i]
       while (len(word) > 0):
        test = re.match("""(x|y|z)(\d*)(.*)""",word)
        if (test != None):
         try:
          direction =     test.group(1)
          if (len(test.group(2)) == 0): number = 1
          else                        : number    = int(test.group(2))
          word      =     test.group(3)
          if (number < 1): raise ValueError # Don't let user assign axis zero!
         except ValueError:
          print "Illegal axis number in set statement"
          return
         if (not number in gp_settings.axes[direction]): gp_settings.axes[direction][number] = gp_settings.default_axis.copy() # Create axis if it doesn't already exist
         gp_settings.axes[direction][number][key] = keyset
         if (not number in gp_plot.axes_this[direction]):                  # Modify axes_this is gp_plot, so that replot takes account of changes
          gp_plot.axes_this[direction][number] = {'SETTINGS':gp_settings.axes[direction][number].copy(), 'MIN_USED':None, 'MAX_USED':None, 'AXIS':None}
         else:
          gp_plot.axes_this[direction][number]['SETTINGS'][key] = gp_settings.axes[direction][number][key]
        else:
         print "No such axis as %s"%word
         break
     else:
      print "Apply this to which axis?"
     return

    test = re.match("""^set?\s*(x|y|z)(\d*)r""",line) # set range
    if (test != None):
     name = test.group(1) + test.group(2)
     if autocomplete(linelist[1],"%srange"%name,3):
      try:
       direction =     test.group(1)
       if (len(test.group(2)) == 0):
        number   = 1
       else:
        number   = int(test.group(2))
      except ValueError:
       print "Illegal axis number is set %s<n>range statement"%test.group(1)
       return
      test = re.match("""^set?\s*\S*\s*restore""",line)
      if (test != None):
       if (not number in gp_settings.axes[direction]): gp_settings.axes[direction][number] = gp_settings.default_axis.copy() # Create axis if it doesn't already exist
       gp_settings.axes[direction][number]['AUTOSCALE'] = 'ON'
       return
      test = re.match(r"""^set?\s*\S*\s*\[([^:\]]*)((:)|( *to *))?([^:\]]*)\]""",line)
      if (test == None):
       print "Could not read range. Use format: set xrange [0:1]."
      else:
       if (not number in gp_settings.axes[direction]): gp_settings.axes[direction][number] = gp_settings.default_axis.copy() # Create axis if it doesn't already exis
       try:
        gp_settings.axes[direction][number]['AUTOSCALE']='OFF'
        if (len(test.group(1).strip()) != 0):
          gp_settings.axes[direction][number]['MIN'] = gp_eval.gp_eval(test.group(1),gp_settings.variables,gp_settings.functions)
        if (len(test.group(5).strip()) != 0):
          gp_settings.axes[direction][number]['MAX'] = gp_eval.gp_eval(test.group(5),gp_settings.variables,gp_settings.functions)
       except:
        print "Error reading specified range."
        print "Error:" , sys.exc_info()[1], "(" , sys.exc_info()[0] , ")"

       if (not number in gp_plot.axes_this[direction]):                  # Modify axes_this is gp_plot, so that replot takes account of changes
        gp_plot.axes_this[direction][number] = {'SETTINGS':gp_settings.axes[direction][number].copy(), 'MIN_USED':None, 'MAX_USED':None, 'AXIS':None}
       else:
        gp_plot.axes_this[direction][number]['SETTINGS']['AUTOSCALE'] = gp_settings.axes[direction][number]['AUTOSCALE']
        gp_plot.axes_this[direction][number]['SETTINGS']['MIN']       = gp_settings.axes[direction][number]['MIN']
        gp_plot.axes_this[direction][number]['SETTINGS']['MAX']       = gp_settings.axes[direction][number]['MAX']
      return

    os.system("cat %s/txt/set.txt"%PATH) # Set what??

# Main Directive Processor

def directive(line):
  global exitting

  # Can use ; to pass multiple commmands on one line
  linelist = gp_eval.gp_split(line,';')
  if (len(linelist) > 1):
    for i in range(len(linelist)):
      directive(linelist[i])
    return

  line     = line.strip() # Get rid of leading/trailing spaces
  linelist = line.split()
  if (len(linelist) < 1): return

  if   (   re.match(r'^([A-Za-z]\w*\([A-Za-z, ]\w*\))\s*=\s*(.*)',line) != None): # f(x) = ...
    test = re.match(r'^([A-Za-z]\w*\([A-Za-z, ]\w*\))\s*=\s*(.*)',line)
    gp_settings.functions[test.group(1).strip()] = test.group(2).strip()
  elif (   re.match(r'^([A-Za-z]\w*)\s*=(.*)',line) != None):                     # x = ...
    test = re.match(r'^([A-Za-z]\w*)\s*=(.*)',line)
    try:
      gp_settings.variables[test.group(1).strip()] = gp_eval.gp_eval(test.group(2),gp_settings.variables,gp_settings.functions)
    except: pass

  elif (autocomplete(linelist[0],"exit",2) or      # exit / quit
        autocomplete(linelist[0],"quit",1)    ):
           exitting=1; return
  elif (autocomplete(linelist[0],"help",1) or      # help / ?
        autocomplete(linelist[0],"?",1)       ):
           os.system("fortune")
  elif autocomplete(linelist[0],"set",2):          # set
    directive_set(line,linelist)
  elif autocomplete(linelist[0],"show",2):         # show
    directive_show(line,linelist)
  elif autocomplete(linelist[0],"fit",1):          # fit
    gp_fit.directive_fit(line,linelist,gp_settings.variables,gp_settings.functions)
  elif autocomplete(linelist[0],"plot",1):         # plot
    gp_plot.directive_plot(line,gp_settings.linestyles,gp_settings.variables,gp_settings.functions,gp_settings.settings,gp_settings.axes,gp_settings.labels,gp_settings.arrows,0)
  elif autocomplete(linelist[0],"replot",3):       # replot
    gp_plot.directive_plot(line,gp_settings.linestyles,gp_settings.variables,gp_settings.functions,gp_settings.settings,gp_settings.axes,gp_settings.labels,gp_settings.arrows,1)

  elif autocomplete(linelist[0],"print",2):        # print
    test = re.match(r'\s*\S*\s*(.*)',line)
    if (test != None):
      args = gp_eval.gp_split(test.group(1),",")   # print , separated list
      for arg in args:
        test = re.match(r"""^\s*'(.*)'\s*$""",arg)
        if (test != None): sys.stdout.write(test.group(1)); continue
        test = re.match(r"""^\s*"(.*)"\s*$""",arg)
        if (test != None): sys.stdout.write(test.group(1)); continue
        try:
          sys.stdout.write( floatprint( gp_eval.gp_eval(arg,gp_settings.variables,gp_settings.functions) ) )
        except: pass
        sys.stdout.write(" ")
    print

  else:
    os.system("cat %s/txt/invalid.txt"%PATH)       # invalid cmd

def Interactive():   # Interactive GnuPlot terminal
  global exitting
  exitting=0
  if (sys.stdin.isatty()): # Only print welcome blurb if running interactively, i.e. not from pipe
    print 
    print "        G N U P L O T +"
    print "        Version %s"%VERSION
    print "        %s"%DATE
    print 
    print "        Copyright (C) 2006"
    print "        Dominic Ford"
    print
    os.system("cat %s/txt/init.txt"%PATH)
  try:
    while (exitting==0):
      if (sys.stdin.isatty()):
        directive(raw_input("gnuplot+> "))
      else:
        directive(raw_input()) # Don't print command prompt when running from a pipe
  except (KeyboardInterrupt,EOFError): pass
  if (sys.stdin.isatty()): print "\nGoodbye. Have a nice day."

# MAIN ENTRY POINT

gp_settings.cwd = os.getcwd() # Store path to user's cwd ; but put LaTeX's junk in /tmp for tidiness
os.chdir('/tmp')

if (len(sys.argv) > 1): # Input files specified on commandline
  for i in range(1,len(sys.argv),1):
    exitting=0
    if (sys.argv[i] == '-'): # A minus on commandline means interactive
      Interactive()
    else:
      try:
        infile = open(sys.argv[i],'r')
      except:
        print "Gnuplot Error: Could not read input file %s"%sys.argv[i]
        print "Skipping on to next input file"
      else:
        for line in infile.readlines():
          directive(line)
          if (exitting==1): break
else: # Otherwise enter interactive mode
  Interactive()
