From scole@chevron.com  Mon Sep 14 11:34:09 1998
Received: from portallh.chevron.com (firewall-user@portallh.chevron.com [192.131.127.100]) by kana.Stanford.EDU (8.8.6/8.7.1) with ESMTP id LAA00171 for <matt@kana.Stanford.EDU>; Mon, 14 Sep 1998 11:34:09 -0700 (PDT)
Received: (from uucp@localhost)
	by portallh.chevron.com (8.9.1a/8.9.1) id LAA11155
	for <@portal.chevron.com:matt@kana.Stanford.EDU>; Mon, 14 Sep 1998 11:33:41 -0700 (PDT)
Received: from unknown(136.171.132.163) by portallh.chevron.com via smap (4.1)
	id xma011151; Mon, 14 Sep 98 11:33:39 -0700
Received: from localhost by scooter.lahabra.chevron.com via SMTP (980427.SGI.8.8.8/980817.SHC)
	for <matt@kana.Stanford.EDU> id LAA05327; Mon, 14 Sep 1998 11:33:38 -0700 (PDT)
Date: Mon, 14 Sep 1998 11:33:38 -0700 (PDT)
From: Steve Cole <scole@chevron.com>
To: Matthias Schwab <matt@kana.Stanford.EDU>
Subject: Re: your mail
In-Reply-To: <199809110459.VAA24373@kana.Stanford.EDU>
Message-ID: <Pine.SGI.3.96.980914113008.3276B-100000@scooter.lahabra.chevron.com>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII

Matt,
Here are my files ParaKeeper.java and
ParaKeeperTest.java after updating to use a Reader
as you suggested. I don't know if this is exactly
what you had in mind, but I don't get any more
deprecation warnings. 
I think this will do just what I want. Thanks again.
I haven't forgotten about Cubeplot, though I let a
second weekend go by without doing it. I'll try to
fit it in in the next couple days.
-Steve

ParaKeeper.java============================================================
package sep.io;

import java.io.*;
import java.util.*;

/**
 * <BR><!--#include file="./source.inc"--><BR>
 */
public class ParaKeeper {
  private Hashtable paraTable = new Hashtable();

  /**
   * Bug: ParaKeeper computes total nSample: number maybe too big!
   *      should read dim and series of n1,n2,n3 ... later!
   *      Should check for a end of file and then return
   *      the Reader.
   */
  public void read(Reader istr) throws IOException {
    Tokenizer myT = new Tokenizer( istr);
    myT.fillTable(paraTable);
    checkDim();
    set( "dim", String.valueOf(getDim()));
    //System.out.println("Data available in Stream: " + istr.available());
    if (!paraTable.containsKey("dataType"))
      set("dataType","float");
    if (!paraTable.containsKey("nSample"))
      set("nSample", String.valueOf(getNSample()));
  }

  // pout could possibly be a DataOutputStream, but BE CAREFUL with UTF
  public void write(PrintWriter pout) throws IOException {
    for (Enumeration e = paraTable.keys(); e.hasMoreElements(); ) {
      String key = (String)e.nextElement();
      pout.println( key + "=" + paraTable.get(key));
    }
    pout.print("\014\014\004");
  }

  /**
   * Return a set of Axis indices for a single linear index (Fortran
   * style storage).
   */
  int[] getIndex(int index) {
    int    dim    = getDim();
    if (dim > 5) {
      System.out.println("Error: dimension not implemented yet");
    } 
    int[] numbs   = new int[5];
    int[] indices = new int[5];
    if (containsKey("n1")) numbs[0] = getInt("n1"); else numbs[0] = 1;
    if (containsKey("n2")) numbs[1] = getInt("n2"); else numbs[1] = 1;
    if (containsKey("n3")) numbs[2] = getInt("n3"); else numbs[2] = 1;
    if (containsKey("n4")) numbs[3] = getInt("n4"); else numbs[3] = 1;
    if (containsKey("n5")) numbs[4] = getInt("n5"); else numbs[4] = 1;
    //System.out.println("Numbs: " + numbs[0] + " " + numbs[1] + " " + numbs[2] + " "+ numbs[3] + " " + numbs[4]);
    //System.out.println((numbs[0]*numbs[1]*numbs[2]*numbs[3]*numbs[4]));
index      = index ; // array index starts with 1
    //System.out.println("Index: " + index);
    indices[4] = index / (numbs[0]*numbs[1]*numbs[2]*numbs[3]);
    index      = index % (numbs[0]*numbs[1]*numbs[2]*numbs[3]);
    //System.out.println("Indices: " + indices[3] + " Index: " + index);
    indices[3] =  index / (numbs[0]*numbs[1]*numbs[2]);
    index      =  index % (numbs[0]*numbs[1]*numbs[2]);
    //System.out.println("Indices: " + indices[2] + " Index: " + index);
    indices[2] =  index / (numbs[0]*numbs[1]);
    index      =  index % (numbs[0]*numbs[1]);
    //System.out.println("Indices: " + indices[1] + " Index: " + index);
    indices[1] =  index / (numbs[0]);
    index      =  index % (numbs[0]);
    //System.out.println("Indices: " + indices[0] + " Index: " + index);
    indices[0] =  index;
    //System.out.println("Indices: " + indices[0] + " Index: " + index);
    //System.out.println("Indices: " + indices[0] + " " + indices[1] + " " + indices[2] + " "+ indices[3] + " " + indices[4]);
    return indices;
  }

  public int[] getNSamples() {
    int dim = getDim();
    if (dim > 6) { 
      System.out.println("Error: dimension not implemented yet");
    }
    int[] nsamples = new int[dim];
    for (int i = 0; i < nsamples.length; i++) {
      int index = i + 1;
      nsamples[i] = getInt(new String(new StringBuffer("n" + index))); 
    }
    return nsamples;
  }

  public int getDim() {
    int dim = 0; int cnt = 1;
    while (containsKey("n" + cnt)) {
      dim++; cnt++; 
    }
    cnt--;                    //counter set to the last existing n value 
    while (containsKey("n" + cnt) && (getInt("n" + cnt) == 1)) {
      dim--; cnt--; 
    }
    return (dim==0) ? 1: dim; // dim = 1 for Rsf with single element
  }

  /* Used at construction time to check if the input's value for "dim"
     is consistent with the value based on n1, n2, ... */
  private void checkDim() {
    int dim1 = getDim(); 
    if (containsKey("dim")) {
      int dim2 = getInt("dim");
      if (dim1 != dim2) {
	System.err.println("Warning: Dimensional mismatch: "+dim1+" "+dim2);
      }
    }
  }

  private int getNSample() {
    if (! containsKey("n1")) {
      return -1;
    }
    else {
      int dim = getDim();
      int nSample = 1;
      for(int i=1; i <= dim; i++)
	nSample *= getInt("n" + i);
      return nSample;
    }
  }

  /**
   * Imitate the SEP In program. should take a PrintStream as argument.
   * This will probably move to rsf.tools.In
   */
  public void in() {
    System.out.println("in=" + getString("in"));
    System.out.println("dataType=" + getString("dataType"));
    System.out.println("esize=" + getString("esize"));
    int dim = getDim();
    for (int i=1; i <= dim; i++) {
      System.out.print("n" + i + "=" + getString("n" + i) + "  ");
      System.out.print("d" + i + "=" + getString("d" + i) + "  ");
      System.out.print("o" + i + "=" + getString("o" + i) + "  ");
      System.out.println("");
    }
    int nSample = getNSample();
    System.out.println(nSample + "  elements in " + getDim() + " dimensions");
    System.out.println((nSample * jsize() / 8) + "  bytes of data expected");
  }

  private int jsize() {
    if (containsKey("dataType") ) {
      if (getString("dataType") == "boolean") return   1;
      if (getString("dataType") == "char")    return  16;
      if (getString("dataType") == "byte")    return   8;
      if (getString("dataType") == "short")   return  16;
      if (getString("dataType") == "int")     return  32;
      if (getString("dataType") == "long")    return  64;
      if (getString("dataType") == "float")   return  32;
      if (getString("dataType") == "double")  return  64;
      if (getString("dataType") == "complex") return  64;
    }
    else if (containsKey("esize") ) {
      if (getString("esize") == "1") return   8;
      if (getString("esize") == "2") return  16;
      if (getString("esize") == "4") return  32;
      if (getString("esize") == "8") return  64;
    }
    return -1;  // maybe the default should be float "32"
  }

  public String toString() { 
    return paraTable.toString();
  }
  public boolean equals(ParaKeeper para) {
    System.out.println("ParaKeeper: equals not implemented yet");
    return false;
  }

  public void    set(String paraName, String paraValue) {
    paraTable.put(paraName,paraValue);
  }
  public void    set(String paraName, int     paraValue) {
    set( paraName, new Integer( paraValue).toString());
  }
  public void    set(String paraName, float   paraValue) {
    set( paraName, new Float  ( paraValue).toString());
  }
  public void    set(String paraName, double  paraValue) {
    set( paraName, new Double ( paraValue).toString());
  }
  public void    set(String paraName, boolean paraValue) {
    set( paraName, new Boolean( paraValue).toString());
  }

  public boolean containsKey(String paraName) {
    return paraTable.containsKey(paraName);
  }
  public String  getString (String paraName) {
    return (String)paraTable.get(paraName);
  }
  public int     getInt    (String paraName) {
    String dummy = getString(paraName);
    return new Integer(getString(paraName)).intValue();
  }
  public float   getFloat  (String paraName) {
    Float    dummy = new Float(0.F);
    return  (dummy.valueOf(getString(paraName))).floatValue();
  }
  public double  getDouble (String paraName) {
    Double   dummy = new Double(0.D); 
    return  (dummy.valueOf(getString(paraName))).doubleValue();
  }
  public boolean getBoolean(String paraName) {
    return (getString(paraName)).equals("true");
  }

  // JOEL 20 Nov 96
  // The following return the specified default values if the desired
  // parameter is not in paraTable.
  public String  getString (String paraName, String deflt) {
    Object val = paraTable.get(paraName);
    return ( val == null ) ? deflt : (String) val;
  }
  public int     getInt    (String paraName, String deflt) {
    return new Integer(  getString(paraName, deflt)).intValue    ();
  }
   public float   getFloat  (String paraName, String deflt) {
    Float    dummy = new Float(0);
    return  (dummy.valueOf(getString(paraName, deflt))).floatValue();
  }
  public double  getDouble (String paraName, String deflt) {
    Double   dummy = new Double(0);
    return  (dummy.valueOf(getString(paraName, deflt))).doubleValue();
  }
  public boolean getBoolean(String paraName, String deflt) {
    return  getString(paraName, deflt).toLowerCase().equals( "true" );
  }
  /*
    The following versions should work under JDK 1.0.2

  public float   getFloat  (String paraName, String deflt) {
    return new Float  (  getString(paraName, deflt)).floatValue  ();
  }
  public double  getDouble (String paraName, String deflt) {
    return new Double (  getString(paraName, deflt)).doubleValue ();
  }
  public boolean getBoolean(String paraName, String deflt) {
    return new Boolean(  getString(paraName, deflt)).booleanValue();
  }
  */

  public void remove( String paraName) {
    paraTable.remove( paraName);
  }
}

/**
 * Tokenizer accepts an DataInputStream, selects all
 * token of the form <tt>paraName=paraValue,</tt> and stores 
 * the <tt>paraName</tt> and the </tt>paraValue</tt> in a Hashtable. Such 
 * Tokenizer should recurse when encountering </tt>para=fileName</tt>.
 * Should such para statements only be allowed on the arg list?
 *
 * combined files: read stream until ^D then exit (stream can be uses
 * for further processing by parent class.
 *
 * A Tokenizer creates (has) a Hashtable (handed in) 
 * and has a stream (handed in). Maybe a hashtable should be able to 
 * accept various streams and create a single Hashtable? Maybe it should
 * not have any argument in the Constructor? 
 */

class Tokenizer {
    Reader instr;
    Hashtable   paraTable; 

  Tokenizer(Reader instr) {
    this.instr = instr;
  }

  void fillTable(Hashtable paraTable) throws IOException {
    this.paraTable = paraTable;

    //System.out.println("I am in filltable");
    StreamTokenizer tokenStream = new StreamTokenizer(instr);
    tokenStream.slashSlashComments(true);
    //tokenStream.slashStarComments(true); // only works on single line (sigh)
    tokenStream.commentChar('#'); // backward compatibility
    tokenStream.wordChars('=','=');
    tokenStream.wordChars('+','+');
    tokenStream.wordChars('-','-');
    tokenStream.wordChars('@','@');
    tokenStream.wordChars('"','"');
    tokenStream.wordChars('.','.');
    tokenStream.wordChars(',',',');
    tokenStream.wordChars('/','/');
    tokenStream.wordChars('_','_');
    tokenStream.wordChars(':',':');
    tokenStream.wordChars('(','(');
    tokenStream.wordChars(')',')');
    tokenStream.wordChars('[','[');
    tokenStream.wordChars(']',']');
    tokenStream.wordChars('<','<');
    tokenStream.wordChars('>','>');
    tokenStream.ordinaryChar('\014'); 
    tokenStream.ordinaryChar('\004');

    String paraDef = null; 
    int counter = 0;
    for(;;){
      tokenStream.nextToken();
      //System.out.println("Counter: " + (counter++)); 
      //System.out.println("Token: "   + tokenStream.sval);
      //System.out.println("Token: "   + tokenStream.nval);
      //System.out.println("Token: "   + tokenStream.ttype);
/* 
 * THIS IS A BUG IN JDK1.1: somehow I loose the last byte when
 * stopping the ParaKeeper and handing the input stream to the 
 * DataKeeper. The quick fix: I just don't read the last byte 
 * and let it vanish in the bug's black hole. Needs fixing!
 * This is depricated anyway.
 */
      if (tokenStream.ttype == '\014') { tokenStream.nextToken();
      if (tokenStream.ttype == '\014') { //tokenStream.nextToken();
	//	if (tokenStream.ttype == '\004') {
        System.out.println("Tokenizer: break because of EOT");
	break;
	//      }}}
          }}

      if (tokenStream.ttype == java.io.StreamTokenizer.TT_EOF ) {
	System.out.println("Tokenizer: break because of EOF");
	break;
      }
      if (tokenStream.ttype == java.io.StreamTokenizer.TT_NUMBER) {
	//System.out.println("Tokenizer: number, next token");
	continue;
      }
      if (tokenStream.ttype != java.io.StreamTokenizer.TT_WORD) {
      System.err.println("Counter: " + (counter++)); 
      System.err.println("Token: "   + tokenStream.sval);
      System.err.println("Token: "   + tokenStream.nval);
      System.err.println("Token: "   + tokenStream.ttype);
	System.err.println("Tokenizer: break because of null");
	break;
      }
      if (tokenStream.sval.indexOf("=") != -1) {
        paraDef          = tokenStream.sval;
	//System.out.println("Tokenizer: para Def: " + paraDef);
        int    positionOfEqual = paraDef.indexOf("=");
        String paraName  = paraDef.substring(0,positionOfEqual);
        String paraValue = paraDef.substring(paraName.length() + 1);
        this.paraTable.put(paraName,paraValue);
	//System.out.println("Tokenizer: " + paraName + " = " + paraValue);
      }
    }
  }
}

ParaKeeperTest.java============================================================
package sep.io;

import java.io.*;

/**
 * <BR><!--#include file="./source.inc"--><BR>
 */
public class ParaKeeperTest {
  public static void main(String[] args) throws IOException {

    // Create a Para file (corresponding to the Header's "in") 
    String  inName = new String("junk1.H");
    String outName = new String("junk2.H");
    PrintWriter pout = new PrintWriter(
                       new FileOutputStream(
                       new File(inName)));
    pout.println("in=junky.H");
    //pout.println("in=" + '"' + "./junk.H@" + '"');
    pout.println("o1=0.0 d1=3.5 n1=3 label1=distance unit=km"); 
    pout.println("o1=1.5 n2=2 n3=1 d3=10 d2=3.1 o2=-34 o3=121");
    pout.println('\004'); //This signals the end of the header file
    pout.println("n1=2"); //This should be invisible to the header

    pout.close();

    FileReader fin   = new FileReader(inName);

    PrintWriter fout  = new PrintWriter(
			new FileOutputStream(
			new File(outName)));

    ParaKeeper para = new ParaKeeper();
    para.read(fin);

    para.in();

    System.out.println(para.toString());
    para.write(fout);

    fin.close();
    fout.close();

    // Testing of the result (testing should be grouped by object)
    boolean correct = true;

    // Compare the output's header values with the input's
    int n1        = para.getInt("n1");
    float o1      = para.getFloat("o1");
    String label1 = para.getString("label1");

    System.out.println("Header comparison:");
    System.out.println(n1     + " == 3"       );
    System.out.println(o1     + " == 1.5"     );
    System.out.println(label1 + " == distance");
    
    if (n1     !=   3     )          correct = false;
    if (o1     != 1.5F    )          correct = false;
    if (! label1.equals("distance")) correct = false;

    System.out.println("Look at junk2.H");

    // Announce the result
    if( correct ){ 
      System.out.println("passes test");
      System.exit(0);
    } else {
      System.out.println("fails test");
      System.exit(1);
    }
  }
}

-----------------------------------------------------------------
Steve Cole                                      scole@chevron.com
Chevron Petroleum Technology Co.              Tel: (562) 694-7157
P.O. Box 446, La Habra, CA 90633-0446         Fax: (562) 694-7063

On Thu, 10 Sep 1998, Matthias Schwab wrote:

> No problem. As I said: use Reader. by the way, I believe that there 
> is some funny size limitation. If I have a header file that is HUGE
> my tokenizer may break. It may not be the size: it could be that the
> large header file contains some stupid keysequence that the tokenizer
> does not handle. Anyway, I have only encountered that twice. 
> 
> 	Good luck. Matthias.
> 

