//
// MOFLexer.java
//
// The contents of this file are subject to the SNIA Public License Version 1.0
// (the "License"); you may not use this file except in compliance with the
// License. You may obtain a copy of the License at
//
//	http://www.snia.org/resources/openSource.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 
// License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is MOFLexer.java
// 
// The Initial Developer of the Original Code is David Simons.
//
// Contributor(s):
//
//
// This source uses the Solaris WBEM APIs version 2.2. 
// Synchronization will be maintained with the Solaris WBEM APIS,
// which are being standardized through the Java Community Process.
//
//
// $Id: MOFLexer.java,v 1.1 2003/07/17 18:32:55 kumpf Exp $
//
// $Log: MOFLexer.java,v $
// Revision 1.1  2003/07/17 18:32:55  kumpf
// HP-BAPU: PEP-64 CIM Client and CIM Listener Java Interface
//
// Revision 1.1.1.1  2001/10/31 18:16:17  karl
// import of SNIA 0_7
//
// Revision 1.7  2001/03/20 13:24:27  davidsi
// - All c/c++ like comments.
//
// Revision 1.6  2000/08/16 05:59:58  shawn
// merge P_TOMCAT31 branch
//
// Revision 1.5.8.1  2000/08/10 00:03:33  shawn
// head merge
//
// Revision 1.5  2000/05/11 10:11:35  davidsi
// - Fixed tabs.
//
// Revision 1.4  2000/05/06 17:11:16  davidsi
// - Various performance improvements
// - Brought in line with SUN WBEM APIs 2.2
//
// Revision 1.3  2000/04/09 14:14:30  davidsi
// - Added support for single token look ahead.
// - Improved error handling.
//
// Revision 1.2  2000/02/13 15:09:54  davidsi
// - Added text to cover re-use of Solaris WBEM APIs.
//
// Revision 1.1.1.1  2000/02/06 16:41:03  davidsi
// Initial version.
//
//
//
package org.snia.wbemcmd.mof;


import java.io.*;


class Tokenstring extends MOFToken {
    String value;
    
    public String tokenString() throws
	    IllegalArgumentException {
	return(value);
    }
    
    public String tokenName() {
	return("tokenval="+value);
    }
    
    public Tokenstring(int iid,String val) {
	super(iid);
	value=val;
    }
}

class Tokennumber extends MOFToken {
    String value;
    
    public int tokenNumber() throws
	    IllegalArgumentException {
	Integer intv=new Integer(value);
	return(intv.intValue());
    }
    public String tokenString() throws
	    IllegalArgumentException {
	return(value);
    }
    
    public String tokenName() {
	return("tokenval="+value);
    }
    
    public Tokennumber(int iid,String val) {
	super(iid);
	value=val;
    }
}



class MOFLexer {
    char[] inarray;			// characters to parse
    int maxFileSize;			// total number of characters in array
    int offset=0;
    int lineno=1;
    MOFStatus status;
    int currentPercentage=-1;
    String pathName;
    MOFToken lookAhead=null;
    MOFToken cachedToken=new MOFToken();  
    
    MOFLexer(MOFStatus istatus) {
	status=istatus;
    }
    
    String getPathName() {
	return(pathName);
    }
    
    public int getLineno() {
	return(lineno);
    }
    
    public void setLookAhead(MOFToken tk) throws MOFParseFailException {
	if (lookAhead!=null)
	    throw new MOFParseFailException(MOFParseFailException.MOF_PARSE_FAILED_LOOKAHEADSET);
	lookAhead=tk;
    }
    
    public int load(String pathname) throws
	    MOFLexerException {

	File dummy;
	BufferedReader in;
      
	pathName=pathname;

	//
	// Get length of file
	//
	dummy=new File(pathname);
	status.fileOpened(pathname);
	maxFileSize=(int)dummy.length();

	try {
	    in=new BufferedReader(new FileReader(dummy));
	    inarray=new char[maxFileSize];
	    if (in.read(inarray,0,maxFileSize)!=maxFileSize)
		throw new MOFLexerException(MOFLexerException.LEX_ERR_FILE_NOT_LOAD);
	} catch (FileNotFoundException io) {
		throw new MOFLexerException(MOFLexerException.LEX_ERR_BAD_PATH);
	} catch (IOException io) {
		throw new MOFLexerException(MOFLexerException.LEX_ERR_BAD_IO);
	}
	cachedToken.setInputArray(inarray);
	return(1);
    }
    

    
    private void skip() throws MOFLexerException
    {
	char ch;
	if (offset<0)
	    throw new MOFLexerException(MOFLexerException.LEX_ERR_EOF);
	    
	while (offset<maxFileSize) {
	    ch=inarray[offset];
	    if (ch=='\n') {
		lineno++;
	    }	
	    if (ch==' ' || ch=='\n'||ch=='\t'|| ch==9 || ch==0xd )
		offset++;
	    else if (offset+1<maxFileSize && ch=='/' && inarray[offset+1]=='/') {
		offset++;
		while (offset<maxFileSize && inarray[offset]!='\n')
		    offset++;
		if (offset==maxFileSize)
		    throw new MOFLexerException(MOFLexerException.LEX_ERR_EOF);
	    }
            // Pam Wright, Imation Allow /* */ style comments
	    else if (offset+1<maxFileSize && ch=='/' && inarray[offset+1]=='*') {
		offset++;offset++;
		while (offset+1<maxFileSize && !(inarray[offset]=='*' && inarray[offset+1]=='/'))
                {
                    if (inarray[offset]=='\n') {
                        lineno++;
                    }	
		    offset++;
                }
		if (offset==maxFileSize)
		    throw new MOFLexerException(MOFLexerException.LEX_ERR_EOF);
                offset++;offset++;
	    } 
            else
		break;
	}
	
	if (offset>=maxFileSize)
	    throw new MOFLexerException(MOFLexerException.LEX_ERR_EOF);

    }
    
    public MOFToken token() throws MOFLexerException
    {
	int i;
	char ch;
	char initialch;
	boolean flag;
	boolean doalias;
	boolean nodpoint;
	boolean noexp;
	int toffset;
	
	
	//
	// See if there is a lookahead token
	//
	if (lookAhead!=null) {
	    MOFToken look=lookAhead;
	    lookAhead=null;
	    return(look);
	}
	
	int newperc=(int)(100*((float)offset/(float)maxFileSize));
	if (newperc>currentPercentage+2) {
	    currentPercentage=newperc;
	    status.filePercent(currentPercentage);
	}
	    
	
	skip();
	
	try {
	    offset=cachedToken.parse(offset,maxFileSize);
	    return(cachedToken);
	} catch (IllegalArgumentException io) {}
		
	toffset=offset;
   
	//
	// Look for identifiers
	//
	ch=inarray[offset];
	initialch=ch;
	if (  (ch>='A' && ch<='Z') ||(ch>='a' && ch<='z')|| ch=='$' ) {
	    int tokenID=MOFToken.IDENTIFIER;
	    if (ch=='$') {
		offset++;
		tokenID=MOFToken.ALIAS_IDENTIFIER;
	    }
	    while (offset<maxFileSize) {
		ch=inarray[offset];
		if (   (ch>='a' && ch<='z' )
		    || (ch>='A' && ch<='Z' )
		    || (ch>='0' && ch<='9' )
		    || (ch=='_') )
		    offset++;
		else
		    break;
	    }
	    return(new Tokenstring(tokenID,
			String.valueOf(inarray,toffset,offset-toffset)));
	}
	
	//
	// Look for strings
	//
	if (initialch=='"') {
	    offset++;
	    while (offset<maxFileSize) {
		if (inarray[offset]=='\\') {
		    offset++;
		    if (offset>=maxFileSize) {
			throw new MOFLexerException(MOFLexerException.LEX_ERR_BAD_TERM_STRING);
		    }
		    offset++;
		    continue;
		}
		if (inarray[offset]=='"') {
		    String sval=String.valueOf(inarray,toffset+1,offset-toffset-1);
		    offset++;
		    return(new Tokenstring(MOFToken.STRING_VALUE,sval));
		}
		offset++;
	    }
	}
	    
	
	//
	// look for character constants
	//
        // Pam Wright, Imation Update to handle '\''
	if (initialch=='\'') {
	    offset++;  
	    while (offset<maxFileSize && inarray[offset]!='\'' ) {
		if (inarray[offset]=='\\') {
		    offset++;
		}
		offset++;
	    }
	    if (inarray[offset]=='\'') {
		String sval=String.valueOf(inarray,toffset+1,offset-toffset-1);
		offset++;
		return(new Tokenstring(MOFToken.CHAR_VALUE,sval));
	    }
	}
	
	//
	// Look for binary constants
	//
	offset=toffset;
	flag=false;
	if (initialch=='+')
	    offset++;
	else if (initialch=='-')
	    offset++;
	while (offset<maxFileSize) {
	    if (inarray[offset]=='1' || inarray[offset]=='0') {
		flag=true;
		offset++;
	    } else
		break;
	}
	if (flag && (inarray[offset]=='b' || inarray[offset]=='B')) {
            // Pam Wright, Imation Correct the parameter to be the binary string
	    //return(new Tokennumber(MOFToken.BINARY_VALUE,"test"));
            offset++;
	    return(new Tokennumber(MOFToken.BINARY_VALUE,
                                   String.valueOf(inarray,toffset,offset-toffset)));
	}

	//
	// Look for hex identifiers
	//
        // Pam Wright, Imation Move check for hex before octal
        // hex leads with 0x octal leads with 0
	offset=toffset;
	flag=false;
	if (inarray[offset]=='+')
	    offset++;
	else if (inarray[offset]=='-')
	    offset++;
	if ( offset+1<maxFileSize && inarray[offset]=='0' 
	     && ( inarray[offset+1]=='x' || inarray[offset+1]>='X') ) {
	    offset += 2;
	    while (offset<maxFileSize) {
		if (  (inarray[offset]>='a' &&inarray[offset]<='f' )
		    ||(inarray[offset]>='A' &&inarray[offset]<='F' )
		    ||(inarray[offset]>='0' &&inarray[offset]<='9' )) {
		    offset++;
		    flag=true;
		} else
		    break;
	    }
	    if (flag)
		return(new Tokennumber(MOFToken.HEX_VALUE,
			    String.valueOf(inarray,toffset,offset-toffset)));
	}

	
	//
	// Look for octal constants...must do this ahead of considering
	// decimal values because a leading 0 indicates octal
	//
	offset=toffset;
	flag=false;
	if (initialch=='+')
	    offset++;
	else if (initialch=='-')
	    offset++;
	if ((offset<maxFileSize) && inarray[offset]=='0') {
	    offset++;
	    while (offset<maxFileSize) {
		ch=inarray[offset];
		if (ch>='0' && ch<='7') {
		    flag=true;
		    offset++;
		} else
		    break;
	    }
	}
	if (flag) {
	    return(new Tokennumber(MOFToken.OCTAL_VALUE,
				String.valueOf(inarray,toffset,offset-toffset)));
	}
/* Pam Wright, Imation Use float constants to find decimal constants. Otherwise, float
   constants are not recognized
   	
	//
	// Look for decimal constants
	//
	offset=toffset;
	flag=false;
	if (initialch=='+')
	    offset++;
	else if (initialch=='-')
	    offset++;
	if ((offset<maxFileSize) && (inarray[offset]>='0' && inarray[offset]<='9')) {
	    while (offset<maxFileSize) {
		ch=inarray[offset];
		if (ch>='0' && ch<='9') {
		    flag=true;
		    offset++;
		} else
		    break;
	    }
	}
	if (flag) {
	    return(new Tokennumber(MOFToken.DECIMAL_VALUE,
		    String.valueOf(inarray,toffset,offset-toffset)));
	}
*/

	//
	// Look for float constants
	//
	offset=toffset;
	flag=false;	    // only goes true when a number was found
			    // --we can reset this to false if we see
			    // decimal points or exps.
	nodpoint=true;
	noexp=true;
	if (initialch=='+')
	    offset++;
	else if (initialch=='-')
	    offset++;
        // Pam Wright, Imation Change from 1-9 to 0-9 or .
	if ((offset<maxFileSize) && 
            ((inarray[offset]>='0' && inarray[offset]<='9') || inarray[offset]=='.')) {
	    while (offset<maxFileSize) {
		if (inarray[offset]>='0' && inarray[offset]<='9') {
		    flag=true;
		    offset++;
		} else if (nodpoint && noexp && inarray[offset]=='.') {
		    nodpoint=false;
		    offset++;
		    flag=false;
		} else if (noexp && (inarray[offset]=='e' || inarray[offset]=='E')) {
		    noexp=false;
		    offset++;
		    if ( offset<maxFileSize 
			 && (inarray[offset]=='+' || inarray[offset]=='-'))
			    offset++;
		      flag=false;
		} else
		    break;
	    }
	}
	if (flag) {
	    if (nodpoint && noexp)
		 return(new Tokennumber(MOFToken.DECIMAL_VALUE,
			String.valueOf(inarray,toffset,offset-toffset)));
	    else
		return(new Tokennumber(MOFToken.REAL_VALUE,
			String.valueOf(inarray,toffset,offset-toffset)));
	}

	throw new MOFLexerException(MOFLexerException.LEX_ERR_BADTOKEN);
    }

    //
    // Need to be able to distinctly ask for tokens when parsing MOF because
    // items like association will appear as both a token and as an identifier
    // in a qualifier declaration
    //
   public MOFToken tokenIdentifier() throws MOFLexerException
    {
	char ch;
    
	//
	// See if there is a lookahead token 
	//
	if (lookAhead!=null) {
	    throw new MOFLexerException("Internal error: className cannot process look ahead tokens");
	}
	skip();
	//
	// Look for identifiers
	//
	int toffset=offset;
	ch=inarray[offset];
	if (  (ch>='A' && ch<='Z' )
	    ||(ch>='a' && ch<='z' )
	    ||ch=='$') {
	    int tokenID=MOFToken.IDENTIFIER;
	    if (ch=='$') {
		offset++;
		tokenID=MOFToken.ALIAS_IDENTIFIER;
	    }
	    while (offset<maxFileSize) {
		ch=inarray[offset];
		if (   (ch>='a' && ch<='z' )
		    || (ch>='A' && ch<='Z' )
		    || (ch>='0' && ch<='9' )
		    || (ch=='_') )
		    offset++;
		else
		    break;
	    }
	    return(new Tokenstring(tokenID,
			String.valueOf(inarray,toffset,offset-toffset)));
	}
	offset=toffset;
	throw new MOFLexerException(MOFLexerException.LEX_ERR_BADTOKEN);
    }
   
     public MOFToken className() throws MOFLexerException {
	char ch;
	int toffset;
	int cnt=0;		// number of white spaces
	
	//
	// See if there is a lookahead token 
	//
	if (lookAhead!=null) {
	    throw new MOFLexerException("Internal error: className cannot process look ahead tokens");
	}
	
	skip();
	//
	// Look for identifiers
	//
	toffset=offset;
	ch=inarray[offset];
	if (  (ch>='A' && ch<='Z' )
	    ||(ch>='a' && ch<='z' )
	    ||ch=='$') {
	    int tokenID=MOFToken.IDENTIFIER;
	    if (ch=='$') {
		offset++;
		tokenID=MOFToken.ALIAS_IDENTIFIER;
	    }
	    while (offset<maxFileSize) {
		ch=inarray[offset];
		if (   (ch>='a' && ch<='z' )
		    || (ch>='A' && ch<='Z' )
		    || (ch>='0' && ch<='9' )
		    || ((ch=='_') && cnt==0) ) {
		    if (ch=='_')
			cnt++;
		    offset++;
		} else
		    break;
	    }
	    return(new Tokenstring(tokenID,
			String.valueOf(inarray,toffset,offset-toffset)));
	}
	offset=toffset;
	throw new MOFLexerException(MOFLexerException.LEX_ERR_BADTOKEN);
    }
}
