org.apache.poi.hssf.record.NameRecord

public class NameRecord extends Record {
    /**
     */

	/**Included for completeness sake, not implemented
	   */
	public final static byte  BUILTIN_CONSOLIDATE_AREA      = (byte)1;

	/**Included for completeness sake, not implemented
	 */
	public final static byte  BUILTIN_AUTO_OPEN             = (byte)2;

	/**Included for completeness sake, not implemented
	 */
	public final static byte  BUILTIN_AUTO_CLOSE            = (byte)3;

	/**Included for completeness sake, not implemented
	 */
	public final static byte  BUILTIN_DATABASE              = (byte)4;

	/**Included for completeness sake, not implemented
	 */
	public final static byte  BUILTIN_CRITERIA              = (byte)5;

	public final static byte  BUILTIN_PRINT_AREA            = (byte)6;
	public final static byte  BUILTIN_PRINT_TITLE           = (byte)7;

	/**Included for completeness sake, not implemented
	 */
	public final static byte  BUILTIN_RECORDER              = (byte)8;

	/**Included for completeness sake, not implemented
	 */
	public final static byte  BUILTIN_DATA_FORM             = (byte)9;

	/**Included for completeness sake, not implemented
	 */

	public final static byte  BUILTIN_AUTO_ACTIVATE         = (byte)10;

	/**Included for completeness sake, not implemented
	 */

	public final static byte  BUILTIN_AUTO_DEACTIVATE       = (byte)11;

	/**Included for completeness sake, not implemented
	 */
	public final static byte  BUILTIN_SHEET_TITLE           = (byte)12;

    public static final short OPT_HIDDEN_NAME =   (short) 0x0001;
    public static final short OPT_FUNCTION_NAME = (short) 0x0002;
    public static final short OPT_COMMAND_NAME =  (short) 0x0004;
    public static final short OPT_MACRO =         (short) 0x0008;
    public static final short OPT_COMPLEX =       (short) 0x0010;
    public static final short OPT_BUILTIN =       (short) 0x0020;
    public static final short OPT_BINDATA =       (short) 0x1000;

    private short             field_1_option_flag;
    private byte              field_2_keyboard_shortcut;
    private byte              field_3_length_name_text;
    private short             field_4_length_name_definition;
    private short             field_6_equals_to_index_to_sheet;
    private byte              field_7_length_custom_menu;
    private byte              field_8_length_description_text;
    private byte              field_9_length_help_topic_text;
    private byte              field_10_length_status_bar_text;
    private byte              field_12_builtIn_name;
    private String            field_12_name_text;
    private Stack             field_13_name_definition;
    private String            field_14_custom_menu_text;
    private String            field_15_description_text;
    private String            field_16_help_topic_text;
    private String            field_17_status_bar_text;

    /** Creates new NameRecord */
    public NameRecord() {
        field_13_name_definition = new Stack();

        field_12_name_text = new String();
        field_14_custom_menu_text = new String();
        field_15_description_text = new String();
        field_16_help_topic_text = new String();
        field_17_status_bar_text = new String();
    }

    /**
     * Constructs a Name record and sets its fields appropriately.
     *
     * @param id     id must be 0x18 or an exception will be throw upon validation
     * @param size  the size of the data area of the record
     * @param data  data of the record (should not contain sid/len)
     */
    public NameRecord(short id, short size, byte [] data) {
        super(id, size, data);
    }

    /**
     * Constructs a Name record and sets its fields appropriately.
     *
     * @param id     id must be 0x18 or an exception will be throw upon validation
     * @param size  the size of the data area of the record
     * @param data  data of the record (should not contain sid/len)
     * @param offset of the record's data
     */
    public NameRecord(short id, short size, byte [] data, int offset) {
        super(id, size, data, offset);
    }

	/**
	 * Constructor to create a built-in named region
	 * @param builtin Built-in byte representation for the name record, use the public constants
	 * @param index
	 */
	public NameRecord(byte builtin, short index)
	{
	    this();
	    this.field_12_builtIn_name = builtin;
	    this.setOptionFlag((short)(this.getOptionFlag() | OPT_BUILTIN));
	    this.setNameTextLength((byte)1);

		this.setCustomMenuLength((byte)0);
		this.setDescriptionTextLength((byte)0);
		this.setHelpTopicLength((byte)0);
		this.setStatusBarLength((byte)0);

	}

    /** sets the option flag for the named range
     * @param flag option flag
     */
    public void setOptionFlag(short flag){
        field_1_option_flag = flag;
    }

    /** sets the keyboard shortcut
     * @param shortcut keyboard shortcut
     */
    public void setKeyboardShortcut(byte shortcut){
        field_2_keyboard_shortcut = shortcut;
    }

    /** sets the name of the named range length
     * @param length name length
     */
    public void setNameTextLength(byte length){
        field_3_length_name_text = length;
    }

    /** sets the definition (reference - formula) length
     * @param length defenition length
     */
    public void setDefinitionTextLength(short length){
        field_4_length_name_definition = length;
    }

    /** sets the index number to the extern sheet (thats is what writen in documentation
     *  but as i saw , it works differently)
     * @param index extern sheet index
     */
    public void setUnused(short index){
        field_5_index_to_sheet = index;

    }

    public short getEqualsToIndexToSheet()
    {
        return field_6_equals_to_index_to_sheet;
    }

	/**
	 * Convenience method to retrieve the index the name refers to.
	 * @see #getEqualsToIndexToSheet()
	 * @return short
	 */
	public short getIndexToSheet() {
		return getEqualsToIndexToSheet();
	}

    /**
     * @return function group
     * @see FnGroupCountRecord
     */
    public byte getFnGroup() {
        int masked = field_1_option_flag & 0x0fc0;
        return (byte) (masked >> 4);
    }

    public void setEqualsToIndexToSheet(short value)
    {
        field_6_equals_to_index_to_sheet = value;
    }

    /** sets the custom menu length
     * @param length custom menu length
     */
    public void setCustomMenuLength(byte length){
        field_7_length_custom_menu = length;
    }

    /** sets the length of named range description
     * @param length description length
     */
    public void setDescriptionTextLength(byte length){
        field_8_length_description_text = length;
    }

    /** sets the help topic length
     * @param length help topic length
     */
    public void setHelpTopicLength(byte length){
        field_9_length_help_topic_text = length;
    }

    /** sets the length of the status bar text
     * @param length status bar text length
     */
    public void setStatusBarLength(byte length){
        field_10_length_status_bar_text = length;
    }

    /** sets the compressed unicode flag
     * @param flag unicode flag
     */
    public void setCompressedUnicodeFlag(byte flag) {
        field_11_compressed_unicode_flag = flag;
    }

    /** sets the name of the named range
     * @param name named range name
     */
    public void setNameText(String name){
        field_12_name_text = name;
    }

    /** sets the custom menu text
     * @param text custom menu text
     */
    public void setCustomMenuText(String text){
        field_14_custom_menu_text = text;
    }

    /** sets the description text
     * @param text the description text
     */
    public void setDescriptionText(String text){
        field_15_description_text = text;
    }

    /** sets the help topic text
     * @param text help topix text
     */
    public void setHelpTopicText(String text){
        field_16_help_topic_text = text;
    }

    /** sets the status bar text
     * @param text status bar text
     */
    public void setStatusBarText(String text){
        field_17_status_bar_text = text;
    }

    /** gets the option flag
     * @return option flag
     */
    public short getOptionFlag(){
        return field_1_option_flag;
    }

    /** returns the keyboard shortcut
     * @return keyboard shortcut
     */
    public byte getKeyboardShortcut(){
        return field_2_keyboard_shortcut ;
    }

    /** gets the name length
     * @return name length
     */
    public byte getNameTextLength(){
        return field_3_length_name_text;
    }

    /** get the definition length
     * @return definition length
     */
    public short getDefinitionTextLength(){
        return field_4_length_name_definition;
    }

    /** gets the index to extern sheet
     * @return index to extern sheet
     */
    public short getUnused(){
        return field_5_index_to_sheet;
    }

    /** gets the custom menu length
     * @return custom menu length
     */
    public byte getCustomMenuLength(){
        return field_7_length_custom_menu;
    }

    /** gets the description text length
     * @return description text length
     */
    public byte getDescriptionTextLength(){
        return field_8_length_description_text;
    }

    /** gets the help topic length
     * @return help topic length
     */
    public byte getHelpTopicLength(){
        return field_9_length_help_topic_text;
    }

    /** get the status bar text length
     * @return satus bar length
     */
    public byte getStatusBarLength(){
        return field_10_length_status_bar_text;
    }

    /** gets the name compressed Unicode flag
     * @return compressed unicode flag
     */
    public byte getCompressedUnicodeFlag() {
        return field_11_compressed_unicode_flag;
    }

    /**
     * @return true if name is hidden
     */
    public boolean isHiddenName() {
        return (field_1_option_flag & OPT_HIDDEN_NAME) != 0;
    }

    /**
     * @return true if name is a function
     */
    public boolean isFunctionName() {
        return (field_1_option_flag & OPT_FUNCTION_NAME) != 0;
    }

    /**
     * @return true if name is a command
     */
    public boolean isCommandName() {
        return (field_1_option_flag & OPT_COMMAND_NAME) != 0;
    }

    /**
     * @return true if function macro or command macro
     */
    public boolean isMacro() {
        return (field_1_option_flag & OPT_MACRO) != 0;
    }

    /**
     * @return true if array formula or user defined
     */
    public boolean isComplexFunction() {
        return (field_1_option_flag & OPT_COMPLEX) != 0;
    }

	/**Convenience Function to determine if the name is a built-in name
	 */
	public boolean isBuiltInName()
	{
	    return ((this.getOptionFlag() & OPT_BUILTIN) != 0);
	}

	/** gets the name
	 * @return name
	 */
	public String getNameText(){

    	return this.isBuiltInName() ? this.translateBuiltInName(this.getBuiltInName()) : field_12_name_text;
	}

	/** Gets the Built In Name
	 * @return the built in Name
	 */
	public byte getBuiltInName()
	{
	    return this.field_12_builtIn_name;
	}

    /** gets the definition, reference (Formula)
     * @return definition -- can be null if we cant parse ptgs
     */
    public List getNameDefinition() {
        return field_13_name_definition;
    }

    public void setNameDefinition(Stack nameDefinition) {
        field_13_name_definition = nameDefinition;
    }

    /** get the custom menu text
     * @return custom menu text
     */
    public String getCustomMenuText(){
        return field_14_custom_menu_text;
    }

    /** gets the description text
     * @return description text
     */
    public String getDescriptionText(){
        return field_15_description_text;
    }

    /** get the help topic text
     * @return gelp topic text
     */
    public String getHelpTopicText(){
        return field_16_help_topic_text;
    }

    /** gets the status bar text
     * @return status bar text
     */
    public String getStatusBarText(){
        return field_17_status_bar_text;
    }

    /**
     * called by constructor, should throw runtime exception in the event of a
     * record passed with a differing ID.
     *
     * @param id alleged id for this record
     */
    protected void validateSid(short id) {
        if (id != sid) {
            throw new RecordFormatException("NOT A valid Name RECORD");
        }
    }

    /**
     * called by the class that is responsible for writing this sucker.
     * Subclasses should implement this so that their data is passed back in a
     * byte array.
     *
     * @param offset to begin writing at
     * @param data byte array containing instance data
     * @return number of bytes written
     */
    public int serialize( int offset, byte[] data )
    {
        LittleEndian.putShort( data, 0 + offset, sid );
        LittleEndian.putShort( data, 4 + offset, getOptionFlag() );
        data[6 + offset] = getKeyboardShortcut();
        data[7 + offset] = getNameTextLength();
        LittleEndian.putShort( data, 8 + offset, getDefinitionTextLength() );
        LittleEndian.putShort( data, 10 + offset, getUnused() );
        LittleEndian.putShort( data, 12 + offset, getEqualsToIndexToSheet() );
        data[14 + offset] = getCustomMenuLength();
        data[15 + offset] = getDescriptionTextLength();
        data[16 + offset] = getHelpTopicLength();
        data[17 + offset] = getStatusBarLength();
        data[18 + offset] = getCompressedUnicodeFlag();

        /* temp: gjs
        if (isBuiltInName())
        {
            LittleEndian.putShort( data, 2 + offset, (short) ( 16 + field_13_raw_name_definition.length ) );

            data[19 + offset] = field_12_builtIn_name;
            System.arraycopy( field_13_raw_name_definition, 0, data, 20 + offset, field_13_raw_name_definition.length );

            return 20 + field_13_raw_name_definition.length;
        }
        else
        {     */
            LittleEndian.putShort( data, 2 + offset, (short) ( 15 + getTextsLength() ) );

			int start_of_name_definition = 19 + field_3_length_name_text;

			if (this.isBuiltInName()) {
				data [19 + offset] =  this.getBuiltInName();
			} else {
				StringUtil.putCompressedUnicode( getNameText(), data, 19 + offset );

			}

			if ( this.field_13_name_definition != null )
			{
				serializePtgs( data, start_of_name_definition + offset );
			}
			else
			{
				System.arraycopy( field_13_raw_name_definition, 0, data
					, start_of_name_definition + offset, field_13_raw_name_definition.length );
			}

            int start_of_custom_menu_text = start_of_name_definition + field_4_length_name_definition;
            StringUtil.putCompressedUnicode( getCustomMenuText(), data, start_of_custom_menu_text + offset );

            int start_of_description_text = start_of_custom_menu_text + field_7_length_custom_menu;
            StringUtil.putCompressedUnicode( getDescriptionText(), data, start_of_description_text + offset );

            int start_of_help_topic_text = start_of_description_text + field_8_length_description_text;
            StringUtil.putCompressedUnicode( getHelpTopicText(), data, start_of_help_topic_text + offset );

            int start_of_status_bar_text = start_of_help_topic_text + field_9_length_help_topic_text;
            StringUtil.putCompressedUnicode( getStatusBarText(), data, start_of_status_bar_text + offset );

            return getRecordSize();
        /* } */
    }

    private void serializePtgs(byte [] data, int offset) {
        int pos = offset;

        for (int k = 0; k < field_13_name_definition.size(); k++) {
            Ptg ptg = ( Ptg ) field_13_name_definition.get(k);

            ptg.writeBytes(data, pos);
            pos += ptg.getSize();
        }
    }

    /** gets the length of all texts
     * @return total length
     */
    public int getTextsLength(){
        int result;

        result = getNameTextLength() + getDefinitionTextLength() + getDescriptionTextLength() +
        getHelpTopicLength() + getStatusBarLength();

        return result;
    }

    /** returns the record size
     */
    public int getRecordSize(){
        int result;

        result = 19 + getTextsLength();

        return result;
    }

    /** gets the extern sheet number
     * @return extern sheet index
     */
    public short getExternSheetNumber(){
        if (field_13_name_definition == null) return 0;
        Ptg ptg = (Ptg) field_13_name_definition.peek();
        short result = 0;

        if (ptg.getClass() == Area3DPtg.class){
            result = ((Area3DPtg) ptg).getExternSheetIndex();

        } else if (ptg.getClass() == Ref3DPtg.class){
            result = ((Ref3DPtg) ptg).getExternSheetIndex();
        }

        return result;
    }

    /** sets the extern sheet number
     * @param externSheetNumber extern sheet number
     */
    public void setExternSheetNumber(short externSheetNumber){
        Ptg ptg;

        if (field_13_name_definition == null || field_13_name_definition.isEmpty()){
            field_13_name_definition = new Stack();
            ptg = createNewPtg();
        } else {
            ptg = (Ptg) field_13_name_definition.peek();
        }

        if (ptg.getClass() == Area3DPtg.class){
            ((Area3DPtg) ptg).setExternSheetIndex(externSheetNumber);

        } else if (ptg.getClass() == Ref3DPtg.class){
            ((Ref3DPtg) ptg).setExternSheetIndex(externSheetNumber);
        }

    }

    private Ptg createNewPtg(){
        Ptg ptg = new Area3DPtg();
        field_13_name_definition.push(ptg);

        return ptg;
    }

    /** gets the reference , the area only (range)
     * @return area reference
     */
    public String getAreaReference(Workbook book){
        if (field_13_name_definition == null) return "#REF!";
        Ptg ptg = (Ptg) field_13_name_definition.peek();
        String result = "";

        if (ptg.getClass() == Area3DPtg.class){
            result = ptg.toFormulaString(book);

        } else if (ptg.getClass() == Ref3DPtg.class){
            result = ptg.toFormulaString(book);
        }

        return result;
    }

    /** sets the reference , the area only (range)
     * @param ref area reference
     */
    public void setAreaReference(String ref){
        RangeAddress ra = new RangeAddress(ref);
        Ptg oldPtg;
        Ptg ptg;

        if (field_13_name_definition==null ||field_13_name_definition.isEmpty()){
            field_13_name_definition = new Stack();
            oldPtg = createNewPtg();
        } else {
            oldPtg = (Ptg) field_13_name_definition.pop();
        }

        short externSheetIndex = 0;

        if (oldPtg.getClass() == Area3DPtg.class){
            externSheetIndex =  ((Area3DPtg) oldPtg).getExternSheetIndex();

        } else if (oldPtg.getClass() == Ref3DPtg.class){
            externSheetIndex =  ((Ref3DPtg) oldPtg).getExternSheetIndex();
        }

        if (ra.hasRange()) {
            ptg = new Area3DPtg();
            ((Area3DPtg) ptg).setExternSheetIndex(externSheetIndex);
            ((Area3DPtg) ptg).setArea(ref);
            this.setDefinitionTextLength((short)ptg.getSize());
        } else {
            ptg = new Ref3DPtg();
            ((Ref3DPtg) ptg).setExternSheetIndex(externSheetIndex);
            ((Ref3DPtg) ptg).setArea(ref);
            this.setDefinitionTextLength((short)ptg.getSize());
        }

        field_13_name_definition.push(ptg);

    }

    /**
     * called by the constructor, should set class level fields.  Should throw
     * runtime exception for bad/icomplete data.
     *
     * @param data raw data
     * @param size size of data
     * @param offset of the record's data (provided a big array of the file)
     */
    protected void fillFields(byte[] data, short size, int offset) {
        field_1_option_flag             = LittleEndian.getShort(data, 0 + offset);
        field_2_keyboard_shortcut       = data [2 + offset];
        field_3_length_name_text        = data [3 + offset];
        field_4_length_name_definition  = LittleEndian.getShort(data, 4 + offset);
        field_5_index_to_sheet          = LittleEndian.getShort(data, 6 + offset);
        field_6_equals_to_index_to_sheet= LittleEndian.getShort(data, 8 + offset);
        field_7_length_custom_menu      = data [10 + offset];
        field_8_length_description_text = data [11 + offset];
        field_9_length_help_topic_text  = data [12 + offset];
        field_10_length_status_bar_text = data [13 + offset];

        /*
        temp: gjs
        if (isBuiltInName()) {

            field_11_compressed_unicode_flag = data[ 14 + offset ];
            field_12_builtIn_name = data[ 15 + offset ];

            if ( (field_12_builtIn_name & (short)0x07) != 0 ) {
                field_12_name_text = "Print_Titles";

                field_13_raw_name_definition = new byte[ field_4_length_name_definition ];
                System.arraycopy( data, 16 + offset, field_13_raw_name_definition, 0, field_13_raw_name_definition.length );

            }
        }
        else { */

            field_11_compressed_unicode_flag= data [14 + offset];

			if (this.isBuiltInName()) {
				field_12_builtIn_name = data[ 15 + offset ];
			}

            field_12_name_text = StringUtil.getFromCompressedUnicode(data, 15 + offset,
            LittleEndian.ubyteToInt(field_3_length_name_text));

            int start_of_name_definition    = 15 + field_3_length_name_text;
            field_13_name_definition = getParsedExpressionTokens(data, field_4_length_name_definition,
            offset, start_of_name_definition);

            int start_of_custom_menu_text   = start_of_name_definition + field_4_length_name_definition;
            field_14_custom_menu_text       = StringUtil.getFromCompressedUnicode(data, start_of_custom_menu_text + offset,
            LittleEndian.ubyteToInt(field_7_length_custom_menu));

            int start_of_description_text   = start_of_custom_menu_text + field_7_length_custom_menu;;
            field_15_description_text       = StringUtil.getFromCompressedUnicode(data, start_of_description_text + offset,
            LittleEndian.ubyteToInt(field_8_length_description_text));

            int start_of_help_topic_text    = start_of_description_text + field_8_length_description_text;
            field_16_help_topic_text        = StringUtil.getFromCompressedUnicode(data, start_of_help_topic_text + offset,
            LittleEndian.ubyteToInt(field_9_length_help_topic_text));

            int start_of_status_bar_text       = start_of_help_topic_text + field_9_length_help_topic_text;
            field_17_status_bar_text        = StringUtil.getFromCompressedUnicode(data, start_of_status_bar_text +  offset,
            LittleEndian.ubyteToInt(field_10_length_status_bar_text));
        /*} */
    }

    private Stack getParsedExpressionTokens(byte [] data, short size,
        int offset, int start_of_expression) {
        Stack stack = new Stack();
        int   pos           = start_of_expression + offset;
        int   sizeCounter   = 0;
        try {
            while (sizeCounter < size) {
                Ptg ptg = Ptg.createPtg(data, pos);

                pos += ptg.getSize();
                sizeCounter += ptg.getSize();
                stack.push(ptg);
                field_13_raw_name_definition=new byte[size];
                System.arraycopy(data,offset,field_13_raw_name_definition,0,size);
            }
        } catch (java.lang.UnsupportedOperationException uoe) {
            System.err.println("[WARNING] Unknown Ptg "
                    + uoe.getMessage() );
            field_13_raw_name_definition=new byte[size];
            System.arraycopy(data,offset,field_13_raw_name_definition,0,size);
            return null;
        }
        return stack;
    }

    /**
     * return the non static version of the id for this record.
     */
    public short getSid() {
        return this.sid;
    }
    /*
      20 00
      00
      01
      00 00
      01 00
      00
      00
      00
      00

      20 00
      00
      01
      00 00
      01 00
      00
      00
      00
      00

  */
    /*
      18, 00,
      1B, 00,

      20, 00,
      00,
      01,
      0B, 00,
      00,
      00,
      00,
      00,
      00,
      07,
      3B 00 00 07 00 07 00 00 00 FF 00 ]
     */

    /**
     * @see Object#toString()
     */
    public String toString() {
        StringBuffer buffer = new StringBuffer();

        buffer.append("[NAME]\n");
        buffer.append("    .option flags         = ").append( HexDump.toHex( field_1_option_flag ) )
            .append("\n");
        buffer.append("    .keyboard shortcut    = ").append( HexDump.toHex( field_2_keyboard_shortcut ) )
            .append("\n");
        buffer.append("    .length of the name   = ").append( field_3_length_name_text )
            .append("\n");
        buffer.append("    .size of the formula data = ").append( field_4_length_name_definition )
            .append("\n");
        buffer.append("    .unused                   = ").append( field_5_index_to_sheet )
            .append("\n");
        buffer.append("    .index to sheet (1-based, 0=Global)           = ").append( field_6_equals_to_index_to_sheet )
            .append("\n");
        buffer.append("    .Length of menu text (character count)        = ").append( field_7_length_custom_menu )
            .append("\n");
        buffer.append("    .Length of description text (character count) = ").append( field_8_length_description_text )
            .append("\n");
        buffer.append("    .Length of help topic text (character count)  = ").append( field_9_length_help_topic_text )
            .append("\n");
        buffer.append("    .Length of status bar text (character count)  = ").append( field_10_length_status_bar_text )
            .append("\n");
        buffer.append("    .Name (Unicode flag)  = ").append( field_11_compressed_unicode_flag )
            .append("\n");
        buffer.append("    .Name (Unicode text)  = ").append( getNameText() )
            .append("\n");
        buffer.append("    .Formula data (RPN token array without size field)      = ").append( HexDump.toHex(
                       ((field_13_raw_name_definition != null) ? field_13_raw_name_definition : new byte[0] ) ) )
            .append("\n");

        buffer.append("    .Menu text (Unicode string without length field)        = ").append( field_14_custom_menu_text )
            .append("\n");
        buffer.append("    .Description text (Unicode string without length field) = ").append( field_15_description_text )
            .append("\n");
        buffer.append("    .Help topic text (Unicode string without length field)  = ").append( field_16_help_topic_text )
            .append("\n");
        buffer.append("    .Status bar text (Unicode string without length field)  = ").append( field_17_status_bar_text )
            .append("\n");
        buffer.append(org.apache.poi.util.HexDump.dump(this.field_13_raw_name_definition,0,0));
        buffer.append("[/NAME]\n");

        return buffer.toString();
    }

	/**Creates a human readable name for built in types
	 * @return Unknown if the built-in name cannot be translated
	 */
	protected String translateBuiltInName(byte name)
	{
	    switch (name)
	    {
	        case NameRecord.BUILTIN_AUTO_ACTIVATE :     return "Auto_Activate";
	        case NameRecord.BUILTIN_AUTO_CLOSE :        return "Auto_Close";
	        case NameRecord.BUILTIN_AUTO_DEACTIVATE :   return "Auto_Deactivate";
	        case NameRecord.BUILTIN_AUTO_OPEN :         return "Auto_Open";
	        case NameRecord.BUILTIN_CONSOLIDATE_AREA :  return "Consolidate_Area";
	        case NameRecord.BUILTIN_CRITERIA :          return "Criteria";
	        case NameRecord.BUILTIN_DATABASE :          return "Database";
	        case NameRecord.BUILTIN_DATA_FORM :         return "Data_Form";
	        case NameRecord.BUILTIN_PRINT_AREA :        return "Print_Area";
	        case NameRecord.BUILTIN_PRINT_TITLE :       return "Print_Titles";
	        case NameRecord.BUILTIN_RECORDER :          return "Recorder";
	        case NameRecord.BUILTIN_SHEET_TITLE :       return "Sheet_Title";

	    }

	    return "Unknown";

FUNC_DECL RETURN COND_EXPR CALL CALL CALL

FUNC_DECL IF IF VAR_DECL IF VAR_DECL VAR_DECL VAR_DECL PARAM CALL CALL IF BINARY_OP BINARY_OP BINARY_OP CALL LITERAL_ANCHOR CALL BINARY_OP CALL ASSIGN ASSIGN CALL ASSIGN ASSIGN ASSIGN ASSIGN LITERAL_ANCHOR CALL CALL CALL CALL ASSIGN CALL CALL CALL CALL CALL

    public short getSid() {
        return this.sid;

FUNC_DECL ASSIGN ASSIGN ASSIGN ASSIGN ASSIGN ASSIGN CALL CALL CALL CALL CALL CALL


public class DefaultParameterMappingStrategy implements ParameterMappingStrategy {
    private Map<Class, Expression> parameterTypeToExpressionMap = new ConcurrentHashMap<Class, Expression>();

    public DefaultParameterMappingStrategy() {
    }

    public synchronized Expression getDefaultParameterTypeExpression(Class parameterType) {
        return parameterTypeToExpressionMap.get(parameterType);
    }

    /**
     * Adds a default parameter type mapping to an expression
     */
    public synchronized void addParameterMapping(Class parameterType, Expression expression) {
        parameterTypeToExpressionMap.put(parameterType, expression);
    }

    /**
     * Creates an invocation on the given POJO using annotations to decide which method to invoke
     * and to figure out which parameters to use
     */
/*
    public MethodInvocation createInvocation(Object pojo,
                                             BeanInfo beanInfo,
                                             Exchange messageExchange,
                                             Endpoint pojoEndpoint) throws RuntimeCamelException {
        return beanInfo.createInvocation(pojo, messageExchange);
    }
*/
    public void loadDefaultRegistry() {
        addParameterMapping(Exchange.class, ExpressionBuilder.exchangeExpression());
        addParameterMapping(Message.class, ExpressionBuilder.inMessageExpression());


public class FtpProducer extends RemoteFileProducer<RemoteFileExchange> {
    private static final transient Log LOG = LogFactory.getLog(FtpProducer.class);

    private FtpEndpoint endpoint;
    private FTPClient client;

    public FtpProducer(FtpEndpoint endpoint, FTPClient client) {
        super(endpoint);
        this.endpoint = endpoint;
        this.client = client;
    }

    public void process(Exchange exchange) throws Exception {
        connectIfNecessary();
        try {
            process(endpoint.createExchange(exchange));
        } catch (FTPConnectionClosedException e) {
            LOG.warn("Disconnecting due to exception: " + e.toString());
            disconnect();
            throw e;
        } catch (RuntimeCamelException e) {
            LOG.warn("Caught RuntimeCamelException: " + e.toString());
            LOG.warn("Hoping an explicit disconnect/reconnect will solve the problem");
            disconnect();
            throw e;
        }
    }

    protected void connectIfNecessary() throws IOException {
        if (!client.isConnected()) {
            LOG.warn("FtpProducer's client isn't connected, trying to reconnect...");
            endpoint.connect(client);
            LOG.info("Connected to " + endpoint.getConfiguration());
        }
    }

    public void disconnect() throws IOException {
        LOG.info("FtpProducer's client is being explicitly disconnected");
        endpoint.disconnect(client);
    }

    public void process(RemoteFileExchange exchange) throws Exception {
        InputStream payload = exchange.getIn().getBody(InputStream.class);
        try {
            String fileName = createFileName(exchange.getIn(), endpoint.getConfiguration());

            int lastPathIndex = fileName.lastIndexOf('/');
            if (lastPathIndex != -1) {
                String directory = fileName.substring(0, lastPathIndex);
                if (!buildDirectory(client, directory)) {
                    LOG.warn("Couldn't build directory: " + directory + " (either permissions deny it, or it already exists)");
                }
            }

            final boolean success = client.storeFile(fileName, payload);
            if (!success) {
                throw new RuntimeCamelException("Error sending file: " + fileName);
            }

            RemoteFileConfiguration config = endpoint.getConfiguration();
            LOG.info("Sent: " + fileName + " to " + config.toString().substring(0, config.toString().indexOf(config.getFile())));
        } finally {
            if (payload != null) {
                payload.close();
            }
        }
    }

    @Override
    protected void doStart() throws Exception {
        LOG.info("Starting");
        try {
            connectIfNecessary();
        } catch (IOException e) {
            LOG.warn("Couldn't connect to " + endpoint.getConfiguration());
        }
        super.doStart();
    }

    @Override
    protected void doStop() throws Exception {
        LOG.info("Stopping");
        disconnect();
        super.doStop();
    }

    protected static boolean buildDirectory(FTPClient ftpClient, String dirName) throws IOException {
        boolean atLeastOneSuccess = false;
        final StringBuilder sb = new StringBuilder(dirName.length());
        final String[] dirs = dirName.split("\\/");

        for (String dir : dirs) {
            sb.append(dir).append('/');
            String directory = sb.toString();

            if (LOG.isDebugEnabled()) {
                LOG.debug("Trying to build directory: " + directory);
            }
            final boolean success = ftpClient.makeDirectory(directory);

            if (!atLeastOneSuccess && success) {
                atLeastOneSuccess = true;
            }
        }

        return atLeastOneSuccess;


org.apache.xpath.compiler.FuncLoader

public class FuncLoader
{

  /** The function ID, which may correspond to one of the FUNC_XXX values
   *  found in {@link org.apache.xpath.compiler.FunctionTable}, but may
   *  be a value installed by an external module.  */
  private int m_funcID;

  /** The class name of the function.  Must not be null.   */
  private String m_funcName;

  /**
   * Get the local class name of the function class.  If function name does
   * not have a '.' in it, it is assumed to be relative to
   * 'org.apache.xpath.functions'.
   *
   * @return The class name of the {org.apache.xpath.functions.Function} class.
   */
  public String getName()
  {
    return m_funcName;
  }

  /**
   * Construct a function loader
   *
   * @param funcName The class name of the {org.apache.xpath.functions.Function}
   *             class, which, if it does not have a '.' in it, is assumed to
   *             be relative to 'org.apache.xpath.functions'.
   * @param funcID  The function ID, which may correspond to one of the FUNC_XXX
   *    values found in {@link org.apache.xpath.compiler.FunctionTable}, but may
   *    be a value installed by an external module.
   */
  public FuncLoader(String funcName, int funcID)
  {

    super();

    m_funcID = funcID;
    m_funcName = funcName;
  }

  /**
   * Get a Function instance that this instance is liaisoning for.
   *
   * @return non-null reference to Function derivative.
   *
   * @throws javax.xml.transform.TransformerException if ClassNotFoundException,
   *    IllegalAccessException, or InstantiationException is thrown.
   */
  public Function getFunction() throws javax.xml.transform.TransformerException
  {

    try
    {
      Class function;

      if (m_funcName.indexOf(".") < 0)
      {

        String classname = "org.apache.xpath.functions." + m_funcName;

        function = Class.forName(classname);
      }
      else
        function = Class.forName(m_funcName);

      Function func = (Function) function.newInstance();

      return func;
    }
    catch (ClassNotFoundException e)
    {
      throw new javax.xml.transform.TransformerException(e);
    }
    catch (IllegalAccessException e)
    {
      throw new javax.xml.transform.TransformerException(e);
    }
    catch (InstantiationException e)
    {
      throw new javax.xml.transform.TransformerException(e);


public class CamelServlet extends HttpServlet {

    private ConcurrentHashMap<String, HttpConsumer> consumers = new ConcurrentHashMap<String, HttpConsumer>();

    public CamelServlet() {
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {

            HttpConsumer consumer = resolve(request);
            if (consumer == null) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND);
                return;
            }

            HttpExchange exchange = new HttpExchange(consumer.getEndpoint(), request, response);
            consumer.getProcessor().process(exchange);

            consumer.getBinding().writeResponse(exchange, response);

        } catch (Exception e) {
            throw new ServletException(e);
        }
    }

    protected HttpConsumer resolve(HttpServletRequest request) {
        String path = request.getPathInfo();
        return consumers.get(path);
    }

    public void connect(HttpConsumer consumer) {
        consumers.put(consumer.getPath(), consumer);
    }

    public void disconnect(HttpConsumer consumer) {
        consumers.remove(consumer.getPath());

FUNC_DECL TRY PARAM PARAM CATCH VAR_DECL IF VAR_DECL THROW_RAISE CALL CALL BINARY_OP CALL CALL CALL CALL RETURN LITERAL_ANCHOR CALL CALL CALL

FUNC_DECL RETURN VAR_DECL PARAM CALL CALL


org.apache.camel.util.UuidGenerator

public class UuidGenerator {

    private static final Logger log = Logger.getLogger(UuidGenerator.class.getName());
    private static final String UNIQUE_STUB;
    private static int instanceCount;
    private static String hostName;
    private String seed;
    private long sequence;

    static {
        String stub = "";
        boolean canAccessSystemProps = true;
        try{
            SecurityManager sm = System.getSecurityManager();
            if(sm != null){
                sm.checkPropertiesAccess();
            }
        }catch(SecurityException se){
            canAccessSystemProps = false;
        }

        if ( canAccessSystemProps) {
            try {
                hostName = InetAddress.getLocalHost().getHostName();
                ServerSocket ss = new ServerSocket(0);
                stub="/" + ss.getLocalPort() + "-" + System.currentTimeMillis() + "/";
                Thread.sleep(100);
                ss.close();
            }catch(Exception ioe){
                log.log(Level.WARNING, "could not generate unique stub",ioe);
            }
        }else{
            hostName="localhost";
            stub = "-1-" +System.currentTimeMillis() +"-";
        }
        UNIQUE_STUB = stub;
    }

    /**
     * As we have to find the hostname as a side-affect of generating
     * a unique stub, we allow it's easy retrevial here
     * @return the local host name
     */

    public static String getHostName(){
        return hostName;
    }

    /**
     * Construct an IdGenerator
     *
     */

    public UuidGenerator(String prefix){
        synchronized(UNIQUE_STUB){
            this.seed = prefix + UNIQUE_STUB +(instanceCount++) +"-";
        }
    }

    public UuidGenerator(){
        this("ID-" + hostName);
    }

    /**
     * Generate a unqiue id
     * @return a unique id
     */

    public synchronized String generateId(){
        return this.seed + (this.sequence++);
    }

    /**
     * Generate a unique ID - that is friendly for a URL or file system
     * @return a unique id
     */
    public String generateSanitizedId(){
        String result = generateId();
        result = result.replace(':', '-');
        result = result.replace('_', '-');
        result = result.replace('.', '-');
        return result;


public class BrowserCommandsMenu extends JPopupMenu
{
	//{{{ BrowserCommandsMenu constructor
	public BrowserCommandsMenu(VFSBrowser browser, VFS.DirectoryEntry[] files)
	{
		this.browser = browser;

		if(files != null)
		{
			VFS vfs = VFSManager.getVFSForPath(files[0].deletePath);
			int type = files[0].type;
			boolean fileOpen = (jEdit.getBuffer(files[0].path) != null);
			boolean delete = !fileOpen && (vfs.getCapabilities() & VFS.DELETE_CAP) != 0;
			boolean rename = !fileOpen && (vfs.getCapabilities() & VFS.RENAME_CAP) != 0;

			for(int i = 1; i < files.length; i++)
			{
				VFS.DirectoryEntry file = files[i];

				VFS _vfs = VFSManager.getVFSForPath(file.deletePath);
				delete &= (vfs == _vfs) && (_vfs.getCapabilities()
					& VFS.DELETE_CAP) != 0;

				if(type == file.type)
					/* all good */;
				else
				{
					// this will disable most operations if
					// files of multiple types are selected
					type = -1;
				}

				// set rename to false if > 1 file selected
				rename = false;

				// show 'close' item if at least one selected
				// file is currently open
				if(jEdit.getBuffer(file.path) != null)
					fileOpen = true;
			}

			if(type == VFS.DirectoryEntry.DIRECTORY
				|| type == VFS.DirectoryEntry.FILESYSTEM)
			{
				if(files.length == 1)
					add(createMenuItem("browse"));
				if(browser.getMode() == VFSBrowser.BROWSER)
					add(createMenuItem("browse-window"));
			}
			else if(type == VFS.DirectoryEntry.FILE
				&& (browser.getMode() == VFSBrowser.BROWSER
				|| browser.getMode() == VFSBrowser.BROWSER_DIALOG))
			{
				add(createMenuItem("open"));
				add(GUIUtilities.loadMenu(
					VFSBrowser.getActionContext(),
					"vfs.browser.open-in"));
				add(createMenuItem("insert"));

				if(fileOpen)
					add(createMenuItem("close"));
			}
			else if(type != -1)
				add(createMenuItem("open"));

			if(rename)
				add(createMenuItem("rename"));
			if(delete)
				add(createMenuItem("delete"));

			add(createMenuItem("copy-path"));
			addSeparator();
		}

		add(createMenuItem("up"));
		add(createMenuItem("reload"));
		add(createMenuItem("roots"));
		add(createMenuItem("home"));
		add(createMenuItem("synchronize"));
		addSeparator();

		if(browser.getMode() == VFSBrowser.BROWSER)
			add(createMenuItem("new-file"));

		add(createMenuItem("new-directory"));

		if(browser.getMode() == VFSBrowser.BROWSER)
		{
			addSeparator();
			add(createMenuItem("search-directory"));
		}

		addSeparator();

		add(createMenuItem("show-hidden-files"));

		if(browser.getMode() == VFSBrowser.BROWSER
			|| browser.getMode() == VFSBrowser.BROWSER_DIALOG)
		{
			addSeparator();
			add(createEncodingMenu());
		}

		update();
	} //}}}

	//{{{ update() method
	public void update()
	{
		if(encodingMenuItems != null)
		{
			JRadioButtonMenuItem mi = (JRadioButtonMenuItem)
				encodingMenuItems.get(browser.currentEncoding);
			if(mi != null)
			{
				mi.setSelected(true);
				otherEncoding.setText(jEdit.getProperty(
					"vfs.browser.other-encoding.label"));
			}
			else
			{
				otherEncoding.setSelected(true);
				otherEncoding.setText(jEdit.getProperty(
					"vfs.browser.other-encoding-2.label",
					new String[] { browser.currentEncoding }));
			}
		}
	} //}}}

	//{{{ Private members
	private VFSBrowser browser;
	private HashMap encodingMenuItems;
	private JCheckBoxMenuItem autoDetect;
	private JRadioButtonMenuItem otherEncoding;

	//{{{ createMenuItem() method
	private JMenuItem createMenuItem(String name)
	{
		return GUIUtilities.loadMenuItem(VFSBrowser.getActionContext(),
			"vfs.browser." + name,false);
	} //}}}

	//{{{ createEncodingMenu() method
	private JMenu createEncodingMenu()
	{
		ActionHandler actionHandler = new ActionHandler();

		encodingMenuItems = new HashMap();
		JMenu encodingMenu = new JMenu(jEdit.getProperty(
			"vfs.browser.commands.encoding.label"));

		JMenu menu = encodingMenu;

		autoDetect = new JCheckBoxMenuItem(
			jEdit.getProperty(
			"vfs.browser.commands.encoding.auto-detect"));
		autoDetect.setSelected(browser.autoDetectEncoding);
		autoDetect.setActionCommand("auto-detect");
		autoDetect.addActionListener(actionHandler);
		menu.add(autoDetect);
		menu.addSeparator();

		ButtonGroup grp = new ButtonGroup();

		List encodingMenuItemList = new ArrayList();
		String[] encodings = MiscUtilities.getEncodings();
		for(int i = 0; i < encodings.length; i++)
		{
			String encoding = encodings[i];
			JRadioButtonMenuItem mi = new JRadioButtonMenuItem(encoding);
			mi.setActionCommand("encoding@" + encoding);
			mi.addActionListener(actionHandler);
			grp.add(mi);
			encodingMenuItems.put(encoding,mi);
			encodingMenuItemList.add(mi);
		}

		String systemEncoding = System.getProperty("file.encoding");
		if(encodingMenuItems.get(systemEncoding) == null)
		{
			JRadioButtonMenuItem mi = new JRadioButtonMenuItem(
				systemEncoding);
			mi.setActionCommand("encoding@" + systemEncoding);
			mi.addActionListener(actionHandler);
			grp.add(mi);
			encodingMenuItems.put(systemEncoding,mi);
			encodingMenuItemList.add(mi);
		}

		Collections.sort(encodingMenuItemList,
			new MiscUtilities.MenuItemCompare());

		Iterator iter = encodingMenuItemList.iterator();
		while(iter.hasNext())
		{
			JRadioButtonMenuItem mi = (JRadioButtonMenuItem)
				iter.next();

			if(menu.getMenuComponentCount() > 20)
			{
				JMenu newMenu = new JMenu(
					jEdit.getProperty("common.more"));
				menu.add(newMenu);
				menu = newMenu;
			}

			menu.add(mi);
		}
		menu.addSeparator();

		otherEncoding = new JRadioButtonMenuItem();
		otherEncoding.setActionCommand("other-encoding");
		otherEncoding.addActionListener(actionHandler);
		grp.add(otherEncoding);
		menu.add(otherEncoding);

		return encodingMenu;
	} //}}}

	//}}}

	//{{{ ActionHandler class
	class ActionHandler implements ActionListener
	{
		public void actionPerformed(ActionEvent evt)
		{
			String actionCommand = evt.getActionCommand();

			if(actionCommand.equals("auto-detect"))
			{
				browser.autoDetectEncoding
					= autoDetect.isSelected();
			}
			else if(actionCommand.equals("other-encoding"))
			{
				String encoding = GUIUtilities.input(browser,
					"encoding-prompt",null,
					jEdit.getProperty("buffer.encoding",
					System.getProperty("file.encoding")));
				if(encoding == null)
					return;
				browser.currentEncoding = encoding;
			}
			else if(actionCommand.startsWith("encoding@"))
			{
				browser.currentEncoding = actionCommand.substring(9);


org.apache.xalan.transformer.StackGuard

public class StackGuard
{

  /**
   * Used for infinite loop check. If the value is -1, do not
   * check for infinite loops. Anyone who wants to enable that
   * check should change the value of this variable to be the
   * level of recursion that they want to check. Be careful setting
   * this variable, if the number is too low, it may report an
   * infinite loop situation, when there is none.
   * Post version 1.0.0, we'll make this a runtime feature.
   */
  private int m_recursionLimit = -1;

  TransformerImpl m_transformer;

  /**
   * Get the recursion limit.
   * Used for infinite loop check. If the value is -1, do not
   * check for infinite loops. Anyone who wants to enable that
   * check should change the value of this variable to be the
   * level of recursion that they want to check. Be careful setting
   * this variable, if the number is too low, it may report an
   * infinite loop situation, when there is none.
   * Post version 1.0.0, we'll make this a runtime feature.
   *
   * @return The recursion limit.
   */
  public int getRecursionLimit()
  {
    return m_recursionLimit;
  }

  /**
   * Set the recursion limit.
   * Used for infinite loop check. If the value is -1, do not
   * check for infinite loops. Anyone who wants to enable that
   * check should change the value of this variable to be the
   * level of recursion that they want to check. Be careful setting
   * this variable, if the number is too low, it may report an
   * infinite loop situation, when there is none.
   * Post version 1.0.0, we'll make this a runtime feature.
   *
   * @param limit The recursion limit.
   */
  public void setRecursionLimit(int limit)
  {
    m_recursionLimit = limit;
  }

  /**
   * Constructor StackGuard
   *
   */
  public StackGuard(TransformerImpl transformerImpl)
  {
    m_transformer = transformerImpl;
  }

  /**
   * Overide equal method for StackGuard objects
   *
   */
  public int countLikeTemplates(ElemTemplate templ, int pos)
  {
  	ObjectStack elems = m_transformer.getCurrentTemplateElements();
  	int count = 1;
    for (int i = pos-1; i >= 0; i--)
    {
    	if((ElemTemplateElement)elems.elementAt(i) == templ)
    		count++;
    }

    return count;
  }

  /**
   * Get the next named or match template down from and including
   * the given position.
   * @param pos the current index position in the stack.
   * @return null if no matched or named template found, otherwise
   * the next named or matched template at or below the position.
   */
  private ElemTemplate getNextMatchOrNamedTemplate(int pos)
  {
  	ObjectStack elems = m_transformer.getCurrentTemplateElements();
    for (int i = pos; i >= 0; i--)
    {
    	ElemTemplateElement elem = (ElemTemplateElement) elems.elementAt(i);
    	if(null != elem)
    	{
	    	if(elem.getXSLToken() == Constants.ELEMNAME_TEMPLATE)
	    	{
	    		return (ElemTemplate)elem;
	    	}
    	}
    }
  	return null;
  }

  /**
   * Check if we are in an infinite loop
   *
   * @throws TransformerException
   */
  public void checkForInfinateLoop() throws TransformerException
  {
    int nTemplates = m_transformer.getCurrentTemplateElementsCount();
    if(nTemplates < m_recursionLimit)
    	return;

    if(m_recursionLimit <= 0)

    for (int i = (nTemplates - 1); i >= m_recursionLimit; i--)
    {
    	ElemTemplate template = getNextMatchOrNamedTemplate(i);

    	if(null == template)
    		break;

    	int loopCount = countLikeTemplates(template, i);

    	if (loopCount >= m_recursionLimit)
    	{

    		String idIs = XSLMessages.createMessage(((null != template.getName()) ? "nameIs" : "matchPatternIs"), null);
        	Object[] msgArgs = new Object[]{ new Integer(loopCount), idIs,
                     ((null != template.getName()) ? template.getName().toString()
    		   : template.getMatch().getPatternString()) };
        	String msg = XSLMessages.createMessage("recursionTooDeep", msgArgs);

    		throw new TransformerException(msg);


org.gjt.sp.jedit.Abbrevs

public class Abbrevs
{
	//{{{ getExpandOnInput() method
	/**
	 * Returns if abbreviations should be expanded after the
	 * user finishes typing a word.
	 */
	public static boolean getExpandOnInput()
	{
		return expandOnInput;
	} //}}}

	//{{{ setExpandOnInput() method
	/**
	 * Sets if abbreviations should be expanded after the
	 * user finishes typing a word.
	 * @param true If true, typing a non-alphanumeric characater will
	 * automatically attempt to expand the current abbrev
	 */
	public static void setExpandOnInput(boolean expandOnInput)
	{
		Abbrevs.expandOnInput = expandOnInput;
	} //}}}

	//{{{ expandAbbrev() method
	/**
	 * Expands the abbrev at the caret position in the specified
	 * view.
	 * @param view The view
	 * @param add If true and abbrev not found, will ask user if
	 * it should be added
	 * @since jEdit 2.6pre4
	 */
	public static boolean expandAbbrev(View view, boolean add)
	{
		//{{{ Figure out some minor things
		Buffer buffer = view.getBuffer();
		JEditTextArea textArea = view.getTextArea();
		if(!buffer.isEditable())
		{
			view.getToolkit().beep();
			return false;
		}

		int line = textArea.getCaretLine();
		int lineStart = buffer.getLineStartOffset(line);
		int caret = textArea.getCaretPosition();

		String lineText = buffer.getLineText(line);
		if(lineText.length() == 0)
		{
			if(add)
				view.getToolkit().beep();
			return false;
		}

		int pos = caret - lineStart;
		if(pos == 0)
		{
			if(add)
				view.getToolkit().beep();
			return false;
		} //}}}

		// we reuse the 'pp' vector to save time
		pp.removeAllElements();

		int wordStart;
		String abbrev;

		//{{{ Handle abbrevs of the form abbrev#pos1#pos2#pos3#...
		if(lineText.charAt(pos-1) == '#')
		{
			wordStart = lineText.indexOf('#');
			wordStart = TextUtilities.findWordStart(lineText,wordStart,
				buffer.getStringProperty("noWordSep") + '#');

			abbrev = lineText.substring(wordStart,pos - 1);

			// positional parameters will be inserted where $1, $2, $3, ...
			// occurs in the expansion

			int lastIndex = 0;
			for(int i = 0; i < abbrev.length(); i++)
			{
				if(abbrev.charAt(i) == '#')
				{
					pp.addElement(abbrev.substring(lastIndex,i));
					lastIndex = i + 1;
				}
			}

			pp.addElement(abbrev.substring(lastIndex));

			// the first element of pp is the abbrev itself
			abbrev = (String)pp.elementAt(0);
			pp.removeElementAt(0);
		} //}}}
		//{{{ Handle ordinary abbrevs
		else
		{
			wordStart = TextUtilities.findWordStart(lineText,pos - 1,
				buffer.getStringProperty("noWordSep"));

			abbrev = lineText.substring(wordStart,pos);
		} //}}}

		Expansion expand = expandAbbrev(buffer.getMode().getName(),
			abbrev,(buffer.getBooleanProperty("noTabs") ?
			buffer.getTabSize() : 0),pp);

		//{{{ Maybe show add abbrev dialog
		if(expand == null)
		{
			if(add)
				new AddAbbrevDialog(view,abbrev);

			return false;
		} //}}}
		//{{{ Insert the expansion
		else
		{
			buffer.beginCompoundEdit();
			try
			{
				// obtain the leading indent for later use
				lineText = buffer.getText(lineStart,wordStart);
				int leadingIndent = MiscUtilities.getLeadingWhiteSpaceWidth(
					lineText,buffer.getTabSize());

				buffer.remove(lineStart + wordStart,pos - wordStart);
				buffer.insert(lineStart + wordStart,expand.text);
				if(expand.caretPosition != -1)
				{
					textArea.setCaretPosition(lineStart + wordStart
						+ expand.caretPosition);
				}

				String whiteSpace = MiscUtilities.createWhiteSpace(
					leadingIndent,buffer.getBooleanProperty("noTabs")
					? 0 : buffer.getTabSize());

				// note that if expand.lineCount is 0, we
				// don't do any indentation at all
				for(int i = line + 1; i <= line + expand.lineCount; i++)
				{
					buffer.insert(buffer.getLineStartOffset(i),
						whiteSpace);
				}
			}
			finally
			{
				buffer.endCompoundEdit();
			}

			if(expand.posParamCount != pp.size())
			{
				view.getStatus().setMessageAndClear(
					jEdit.getProperty(
					"view.status.incomplete-abbrev",
					new Integer[] { new Integer(pp.size()),
					new Integer(expand.posParamCount) }));
			}

			return true;
		} //}}}
	} //}}}

	//{{{ getGlobalAbbrevs() method
	/**
	 * Returns the global abbreviation set.
	 * @since jEdit 2.3pre1
	 */
	public static Hashtable getGlobalAbbrevs()
	{
		if(!loaded)
			load();

		return globalAbbrevs;
	} //}}}

	//{{{ setGlobalAbbrevs() method
	/**
	 * Sets the global abbreviation set.
	 * @param globalAbbrevs The new global abbrev set
	 * @since jEdit 2.3pre1
	 */
	public static void setGlobalAbbrevs(Hashtable globalAbbrevs)
	{
		abbrevsChanged = true;
		Abbrevs.globalAbbrevs = globalAbbrevs;
	} //}}}

	//{{{ getModeAbbrevs() method
	/**
	 * Returns the mode-specific abbreviation set.
	 * @since jEdit 2.3pre1
	 */
	public static Hashtable getModeAbbrevs()
	{
		if(!loaded)
			load();

		return modes;
	} //}}}

	//{{{ setModeAbbrevs() method
	/**
	 * Sets the mode-specific abbreviation set.
	 * @param globalAbbrevs The new global abbrev set
	 * @since jEdit 2.3pre1
	 */
	public static void setModeAbbrevs(Hashtable modes)
	{
		abbrevsChanged = true;
		Abbrevs.modes = modes;
	} //}}}

	//{{{ addGlobalAbbrev() method
	/**
	 * Adds an abbreviation to the global abbreviation list.
	 * @param abbrev The abbreviation
	 * @param expansion The expansion
	 * @since jEdit 3.1pre1
	 */
	public static void addGlobalAbbrev(String abbrev, String expansion)
	{
		if(!loaded)
			load();

		globalAbbrevs.put(abbrev,expansion);
		abbrevsChanged = true;
	} //}}}

	//{{{ addModeAbbrev() method
	/**
	 * Adds a mode-specific abbrev.
	 * @param mode The edit mode
	 * @param abbrev The abbrev
	 * @param expansion The expansion
	 * @since jEdit 3.1pre1
	 */
	public static void addModeAbbrev(String mode, String abbrev, String expansion)
	{
		if(!loaded)
			load();

		Hashtable modeAbbrevs = (Hashtable)modes.get(mode);
		if(modeAbbrevs == null)
		{
			modeAbbrevs = new Hashtable();
			modes.put(mode,modeAbbrevs);
		}
		modeAbbrevs.put(abbrev,expansion);
		abbrevsChanged = true;
	} //}}}

	//{{{ save() method
	static void save()
	{
		jEdit.setBooleanProperty("view.expandOnInput",expandOnInput);

		String settings = jEdit.getSettingsDirectory();
		if(abbrevsChanged && settings != null)
		{
			File file1 = new File(MiscUtilities.constructPath(settings,"#abbrevs#save#"));
			File file2 = new File(MiscUtilities.constructPath(settings,"abbrevs"));
			if(file2.exists() && file2.lastModified() != abbrevsModTime)
			{
				Log.log(Log.WARNING,Abbrevs.class,file2 + " changed on disk;"
					+ " will not save abbrevs");
			}
			else
			{
				jEdit.backupSettingsFile(file2);

				try
				{
					saveAbbrevs(new FileWriter(file1));
				}
				catch(Exception e)
				{
					Log.log(Log.ERROR,Abbrevs.class,"Error while saving " + file1);
					Log.log(Log.ERROR,Abbrevs.class,e);
				}
				file2.delete();
				file1.renameTo(file2);
				abbrevsModTime = file2.lastModified();
			}
		}
	} //}}}

	//{{{ Private members

	//{{{ Instance variables
	private static boolean loaded;
	private static boolean abbrevsChanged;
	private static long abbrevsModTime;
	private static boolean expandOnInput;
	private static Hashtable globalAbbrevs;
	private static Hashtable modes;
	private static Vector pp = new Vector();
	//}}}

	private Abbrevs() {}

	static
	{
		expandOnInput = jEdit.getBooleanProperty("view.expandOnInput");
	}

	//{{{ load() method
	private static void load()
	{
		globalAbbrevs = new Hashtable();
		modes = new Hashtable();

		String settings = jEdit.getSettingsDirectory();
		if(settings != null)
		{
			File file = new File(MiscUtilities.constructPath(settings,"abbrevs"));
			abbrevsModTime = file.lastModified();

			try
			{
				loadAbbrevs(new FileReader(file));
				loaded = true;
			}
			catch(FileNotFoundException fnf)
			{
			}
			catch(Exception e)
			{
				Log.log(Log.ERROR,Abbrevs.class,"Error while loading " + file);
				Log.log(Log.ERROR,Abbrevs.class,e);
			}
		}

		// only load global abbrevs if user abbrevs file could not be loaded
		if(!loaded)
		{
			try
			{
				loadAbbrevs(new InputStreamReader(Abbrevs.class
					.getResourceAsStream("default.abbrevs")));
			}
			catch(Exception e)
			{
				Log.log(Log.ERROR,Abbrevs.class,"Error while loading default.abbrevs");
				Log.log(Log.ERROR,Abbrevs.class,e);
			}
			loaded = true;
		}
	} //}}}

	//{{{ expandAbbrev() method
	private static Expansion expandAbbrev(String mode, String abbrev,
		int softTabSize, Vector pp)
	{
		if(!loaded)
			load();

		// try mode-specific abbrevs first
		String expand = null;
		Hashtable modeAbbrevs = (Hashtable)modes.get(mode);
		if(modeAbbrevs != null)
			expand = (String)modeAbbrevs.get(abbrev);

		if(expand == null)
			expand = (String)globalAbbrevs.get(abbrev);

		if(expand == null)
			return null;
		else
			return new Expansion(expand,softTabSize,pp);
	} //}}}

	//{{{ loadAbbrevs() method
	private static void loadAbbrevs(Reader _in) throws Exception
	{
		BufferedReader in = new BufferedReader(_in);

		Hashtable currentAbbrevs = null;

		String line;
		while((line = in.readLine()) != null)
		{
			if(line.length() == 0)
				continue;
			else if(line.startsWith("[") && line.indexOf('|') == -1)
			{
				if(line.equals("[global]"))
					currentAbbrevs = globalAbbrevs;
				else
				{
					String mode = line.substring(1,
						line.length() - 1);
					currentAbbrevs = (Hashtable)modes.get(mode);
					if(currentAbbrevs == null)
					{
						currentAbbrevs = new Hashtable();
						modes.put(mode,currentAbbrevs);
					}
				}
			}
			else
			{
				int index = line.indexOf('|');
				currentAbbrevs.put(line.substring(0,index),
					line.substring(index + 1));
			}
		}

		in.close();
	} //}}}

	//{{{ saveAbbrevs() method
	private static void saveAbbrevs(Writer _out) throws Exception
	{
		BufferedWriter out = new BufferedWriter(_out);
		String lineSep = System.getProperty("line.separator");

		// write global abbrevs
		out.write("[global]");
		out.write(lineSep);

		saveAbbrevs(out,globalAbbrevs);

		// write mode abbrevs
		Enumeration keys = modes.keys();
		Enumeration values = modes.elements();
		while(keys.hasMoreElements())
		{
			out.write('[');
			out.write((String)keys.nextElement());
			out.write(']');
			out.write(lineSep);
			saveAbbrevs(out,(Hashtable)values.nextElement());
		}

		out.close();
	} //}}}

	//{{{ saveAbbrevs() method
	private static void saveAbbrevs(Writer out, Hashtable abbrevs)
		throws Exception
	{
		String lineSep = System.getProperty("line.separator");

		Enumeration keys = abbrevs.keys();
		Enumeration values = abbrevs.elements();
		while(keys.hasMoreElements())
		{
			String abbrev = (String)keys.nextElement();
			out.write(abbrev);
			out.write('|');
			out.write(values.nextElement().toString());
			out.write(lineSep);
		}
	} //}}}

	//}}}

	//{{{ Expansion class
	static class Expansion
	{
		String text;
		int caretPosition = -1;
		int lineCount;

		// number of positional parameters in abbreviation expansion
		int posParamCount;

		//{{{ Expansion constructor
		Expansion(String text, int softTabSize, Vector pp)
		{
			StringBuffer buf = new StringBuffer();
			boolean backslash = false;

			for(int i = 0; i < text.length(); i++)
			{
				char ch = text.charAt(i);
				//{{{ Handle backslash
				if(backslash)
				{
					backslash = false;

					if(ch == '|')
						caretPosition = buf.length();
					else if(ch == 'n')
					{
						buf.append('\n');
						lineCount++;
					}
					else if(ch == 't')
					{
						if(softTabSize == 0)
							buf.append('\t');
						else
						{
							for(int j = 0; j < softTabSize; j++)
								buf.append(' ');
						}
					}
					else
						buf.append(ch);
				}
				else if(ch == '\\')
					backslash = true;
				//}}}
				//{{{ Handle $
				else if(ch == '$')
				{
					if(i != text.length() - 1)
					{
						ch = text.charAt(i + 1);
						if(Character.isDigit(ch) && ch != '0')
						{
							i++;

							int pos = ch - '0';
							posParamCount = Math.max(pos,posParamCount);
							// $n is 1-indexed, but vector
							// contents is zero indexed
							if(pos <= pp.size())
								buf.append(pp.elementAt(pos - 1));
						}
						else
						{
							// $key will be $key, for
							// example
							buf.append('$');
						}
					}
					else
						buf.append('$'); // $ at end is literal
				} //}}}
				else
					buf.append(ch);
			}

			this.text = buf.toString();

FUNC_DECL IF PARAM PARAM ASSIGN CALL LITERAL_ANCHOR CALL

FUNC_DECL IF VAR_DECL IF PARAM PARAM PARAM ASSIGN CALL BINARY_OP LITERAL_ANCHOR LITERAL_ANCHOR CALL CALL ASSIGN CALL CALL

FUNC_DECL IF IF VAR_DECL BINARY_OP ASSIGN ASSIGN TRY TRY VAR_DECL LITERAL_ANCHOR CALL CALL CALL ASSIGN CATCH CATCH CATCH ASSIGN LITERAL_ANCHOR CALL ASSIGN CALL CALL CALL CALL CALL CALL CALL CALL LITERAL_ANCHOR CALL CALL LITERAL_ANCHOR CALL BINARY_OP LITERAL_ANCHOR LITERAL_ANCHOR LITERAL_ANCHOR

FUNC_DECL LOOP VAR_DECL VAR_DECL VAR_DECL VAR_DECL PARAM CALL CALL CALL CALL CALL CALL CALL LITERAL_ANCHOR CALL CALL CALL CALL CALL CALL CALL LITERAL_ANCHOR LITERAL_ANCHOR LITERAL_ANCHOR CALL CALL

FUNC_DECL LOOP VAR_DECL VAR_DECL VAR_DECL PARAM PARAM CALL VAR_DECL CALL CALL CALL CALL CALL CALL CALL LITERAL_ANCHOR CALL LITERAL_ANCHOR CALL CALL


org.apache.tools.ant.DirectoryScanner

public class DirectoryScanner implements FileScanner {

    /**
     * Patterns that should be excluded by default.
     *
     * @see #addDefaultExcludes()
     */
    protected final static String[] DEFAULTEXCLUDES = {
        "**/*~",
        "**/#*#",
        "**/.#*",
        "**/%*%",
        "**/CVS",
        "**/CVS/**",
        "**/.cvsignore",
        "**/SCCS",
        "**/SCCS/**",
        "**/vssver.scc"
    };

    /**
     * The base directory which should be scanned.
     */
    protected File basedir;

    /**
     * The patterns for the files that should be included.
     */
    protected String[] includes;

    /**
     * The patterns for the files that should be excluded.
     */
    protected String[] excludes;

    /**
     * The files that where found and matched at least one includes, and matched
     * no excludes.
     */
    protected Vector filesIncluded;

    /**
     * The files that where found and did not match any includes.
     */
    protected Vector filesNotIncluded;

    /**
     * The files that where found and matched at least one includes, and also
     * matched at least one excludes.
     */
    protected Vector filesExcluded;

    /**
     * The directories that where found and matched at least one includes, and
     * matched no excludes.
     */
    protected Vector dirsIncluded;

    /**
     * The directories that where found and did not match any includes.
     */
    protected Vector dirsNotIncluded;

    /**
     * The files that where found and matched at least one includes, and also
     * matched at least one excludes.
     */
    protected Vector dirsExcluded;

    /**
     * Have the Vectors holding our results been built by a slow scan?
     */
    protected boolean haveSlowResults = false;

    /**
     * Should the file system be treated as a case sensitive one?
     */
    protected boolean isCaseSensitive = true;

    /**
     * Constructor.
     */
    public DirectoryScanner() {
    }

    /**
     * Does the path match the start of this pattern up to the first "**".
     *
     *
This is not a general purpose test and should only be used if you
     * can live with false positives.

     *
     *
pattern=**\\a and str=b will yield true.
     *
     * @param pattern the (non-null) pattern to match against
     * @param str     the (non-null) string (path) to match
     */
    protected static boolean matchPatternStart(String pattern, String str) {
        return matchPatternStart(pattern, str, true);
    }

    /**
     * Does the path match the start of this pattern up to the first "**".
     *
     *
This is not a general purpose test and should only be used if you
     * can live with false positives.

     *
     *
pattern=**\\a and str=b will yield true.
     *
     * @param pattern             the (non-null) pattern to match against
     * @param str                 the (non-null) string (path) to match
     * @param isCaseSensitive     must matches be case sensitive?
     */
    protected static boolean matchPatternStart(String pattern, String str,
                                               boolean isCaseSensitive) {
        if (str.startsWith(File.separator) !=
            pattern.startsWith(File.separator)) {
            return false;
        }

        Vector patDirs = new Vector();
        StringTokenizer st = new StringTokenizer(pattern,File.separator);
        while (st.hasMoreTokens()) {
            patDirs.addElement(st.nextToken());
        }

        Vector strDirs = new Vector();
        st = new StringTokenizer(str,File.separator);
        while (st.hasMoreTokens()) {
            strDirs.addElement(st.nextToken());
        }

        int patIdxStart = 0;
        int patIdxEnd   = patDirs.size()-1;
        int strIdxStart = 0;
        int strIdxEnd   = strDirs.size()-1;

        while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
            String patDir = (String)patDirs.elementAt(patIdxStart);
            if (patDir.equals("**")) {
                break;
            }
            if (!match(patDir,(String)strDirs.elementAt(strIdxStart), isCaseSensitive)) {
                return false;
            }
            patIdxStart++;
            strIdxStart++;
        }

        if (strIdxStart > strIdxEnd) {
            return true;
        } else if (patIdxStart > patIdxEnd) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * Matches a path against a pattern.
     *
     * @param pattern the (non-null) pattern to match against
     * @param str     the (non-null) string (path) to match
     *
     * @return true when the pattern matches against the string.
     *         false otherwise.
     */
    protected static boolean matchPath(String pattern, String str) {
        return matchPath(pattern, str, true);
    }

    /**
     * Matches a path against a pattern.
     *
     * @param pattern            the (non-null) pattern to match against
     * @param str                the (non-null) string (path) to match
     * @param isCaseSensitive    must a case sensitive match be done?
     *
     * @return true when the pattern matches against the string.
     *         false otherwise.
     */
    protected static boolean matchPath(String pattern, String str, boolean isCaseSensitive) {
        if (str.startsWith(File.separator) !=
            pattern.startsWith(File.separator)) {
            return false;
        }

        Vector patDirs = new Vector();
        StringTokenizer st = new StringTokenizer(pattern,File.separator);
        while (st.hasMoreTokens()) {
            patDirs.addElement(st.nextToken());
        }

        Vector strDirs = new Vector();
        st = new StringTokenizer(str,File.separator);
        while (st.hasMoreTokens()) {
            strDirs.addElement(st.nextToken());
        }

        int patIdxStart = 0;
        int patIdxEnd   = patDirs.size()-1;
        int strIdxStart = 0;
        int strIdxEnd   = strDirs.size()-1;

        while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
            String patDir = (String)patDirs.elementAt(patIdxStart);
            if (patDir.equals("**")) {
                break;
            }
            if (!match(patDir,(String)strDirs.elementAt(strIdxStart), isCaseSensitive)) {
                return false;
            }
            patIdxStart++;
            strIdxStart++;
        }
        if (strIdxStart > strIdxEnd) {
            for (int i = patIdxStart; i <= patIdxEnd; i++) {
                if (!patDirs.elementAt(i).equals("**")) {
                    return false;
                }
            }
            return true;
        } else {
            if (patIdxStart > patIdxEnd) {
                return false;
            }
        }

        while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
            String patDir = (String)patDirs.elementAt(patIdxEnd);
            if (patDir.equals("**")) {
                break;
            }
            if (!match(patDir,(String)strDirs.elementAt(strIdxEnd), isCaseSensitive)) {
                return false;
            }
            patIdxEnd--;
            strIdxEnd--;
        }
        if (strIdxStart > strIdxEnd) {
            for (int i = patIdxStart; i <= patIdxEnd; i++) {
                if (!patDirs.elementAt(i).equals("**")) {
                    return false;
                }
            }
            return true;
        }

        while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
            int patIdxTmp = -1;
            for (int i = patIdxStart+1; i <= patIdxEnd; i++) {
                if (patDirs.elementAt(i).equals("**")) {
                    patIdxTmp = i;
                    break;
                }
            }
            if (patIdxTmp == patIdxStart+1) {
                patIdxStart++;
                continue;
            }
            int patLength = (patIdxTmp-patIdxStart-1);
            int strLength = (strIdxEnd-strIdxStart+1);
            int foundIdx  = -1;
strLoop:
            for (int i = 0; i <= strLength - patLength; i++) {
                for (int j = 0; j < patLength; j++) {
                    String subPat = (String)patDirs.elementAt(patIdxStart+j+1);
                    String subStr = (String)strDirs.elementAt(strIdxStart+i+j);
                    if (!match(subPat,subStr, isCaseSensitive)) {
                        continue strLoop;
                    }
                }

                foundIdx = strIdxStart+i;
                break;
            }

            if (foundIdx == -1) {
                return false;
            }

            patIdxStart = patIdxTmp;
            strIdxStart = foundIdx+patLength;
        }

        for (int i = patIdxStart; i <= patIdxEnd; i++) {
            if (!patDirs.elementAt(i).equals("**")) {
                return false;
            }
        }

        return true;
    }

    /**
     * Matches a string against a pattern. The pattern contains two special
     * characters:
     * '*' which means zero or more characters,
     * '?' which means one and only one character.
     *
     * @param pattern the (non-null) pattern to match against
     * @param str     the (non-null) string that must be matched against the
     *                pattern
     *
     * @return true when the string matches against the pattern,
     *         false otherwise.
     */
    protected static boolean match(String pattern, String str) {
        return match(pattern, str, true);
    }

    /**
     * Matches a string against a pattern. The pattern contains two special
     * characters:
     * '*' which means zero or more characters,
     * '?' which means one and only one character.
     *
     * @param pattern the (non-null) pattern to match against
     * @param str     the (non-null) string that must be matched against the
     *                pattern
     *
     * @return true when the string matches against the pattern,
     *         false otherwise.
     */
    protected static boolean match(String pattern, String str, boolean isCaseSensitive) {
        char[] patArr = pattern.toCharArray();
        char[] strArr = str.toCharArray();
        int patIdxStart = 0;
        int patIdxEnd   = patArr.length-1;
        int strIdxStart = 0;
        int strIdxEnd   = strArr.length-1;
        char ch;

        boolean containsStar = false;
        for (int i = 0; i < patArr.length; i++) {
            if (patArr[i] == '*') {
                containsStar = true;
                break;
            }
        }

        if (!containsStar) {
            if (patIdxEnd != strIdxEnd) {
            }
            for (int i = 0; i <= patIdxEnd; i++) {
                ch = patArr[i];
                if (ch != '?') {
                    if (isCaseSensitive && ch != strArr[i]) {
                    }
                    if (!isCaseSensitive && Character.toUpperCase(ch) !=
                        Character.toUpperCase(strArr[i])) {
                    }
                }
            }
        }

        if (patIdxEnd == 0) {
        }

        while((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
            if (ch != '?') {
                if (isCaseSensitive && ch != strArr[strIdxStart]) {
                }
                if (!isCaseSensitive && Character.toUpperCase(ch) !=
                    Character.toUpperCase(strArr[strIdxStart])) {
                }
            }
            patIdxStart++;
            strIdxStart++;
        }
        if (strIdxStart > strIdxEnd) {
            for (int i = patIdxStart; i <= patIdxEnd; i++) {
                if (patArr[i] != '*') {
                    return false;
                }
            }
            return true;
        }

        while((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
            if (ch != '?') {
                if (isCaseSensitive && ch != strArr[strIdxEnd]) {
                }
                if (!isCaseSensitive && Character.toUpperCase(ch) !=
                    Character.toUpperCase(strArr[strIdxEnd])) {
                }
            }
            patIdxEnd--;
            strIdxEnd--;
        }
        if (strIdxStart > strIdxEnd) {
            for (int i = patIdxStart; i <= patIdxEnd; i++) {
                if (patArr[i] != '*') {
                    return false;
                }
            }
            return true;
        }

        while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
            int patIdxTmp = -1;
            for (int i = patIdxStart+1; i <= patIdxEnd; i++) {
                if (patArr[i] == '*') {
                    patIdxTmp = i;
                    break;
                }
            }
            if (patIdxTmp == patIdxStart+1) {
                patIdxStart++;
                continue;
            }
            int patLength = (patIdxTmp-patIdxStart-1);
            int strLength = (strIdxEnd-strIdxStart+1);
            int foundIdx  = -1;
            strLoop:
            for (int i = 0; i <= strLength - patLength; i++) {
                for (int j = 0; j < patLength; j++) {
                    ch = patArr[patIdxStart+j+1];
                    if (ch != '?') {
                        if (isCaseSensitive && ch != strArr[strIdxStart+i+j]) {
                            continue strLoop;
                        }
                        if (!isCaseSensitive && Character.toUpperCase(ch) !=
                            Character.toUpperCase(strArr[strIdxStart+i+j])) {
                            continue strLoop;
                        }
                    }
                }

                foundIdx = strIdxStart+i;
                break;
            }

            if (foundIdx == -1) {
                return false;
            }

            patIdxStart = patIdxTmp;
            strIdxStart = foundIdx+patLength;
        }

        for (int i = patIdxStart; i <= patIdxEnd; i++) {
            if (patArr[i] != '*') {
                return false;
            }
        }
        return true;
    }

    /**
     * Sets the basedir for scanning. This is the directory that is scanned
     * recursively. All '/' and '\' characters are replaced by
     * File.separatorChar. So the separator used need not match
     * File.separatorChar.
     *
     * @param basedir the (non-null) basedir for scanning
     */
    public void setBasedir(String basedir) {
        setBasedir(new File(basedir.replace('/',File.separatorChar).replace('\\',File.separatorChar)));
    }

    /**
     * Sets the basedir for scanning. This is the directory that is scanned
     * recursively.
     *
     * @param basedir the basedir for scanning
     */
    public void setBasedir(File basedir) {
        this.basedir = basedir;
    }

    /**
     * Gets the basedir that is used for scanning. This is the directory that
     * is scanned recursively.
     *
     * @return the basedir that is used for scanning
     */
    public File getBasedir() {
        return basedir;
    }

    /**
     * Sets the case sensitivity of the file system
     *
     * @param specifies if the filesystem is case sensitive
     */
    public void setCaseSensitive(boolean isCaseSensitive) {
        this.isCaseSensitive = isCaseSensitive;
    }

    /**
     * Sets the set of include patterns to use. All '/' and '\' characters are
     * replaced by File.separatorChar. So the separator used need
     * not match File.separatorChar.
     *

     * When a pattern ends with a '/' or '\', "**" is appended.
     *
     * @param includes list of include patterns
     */
    public void setIncludes(String[] includes) {
        if (includes == null) {
            this.includes = null;
        } else {
            this.includes = new String[includes.length];
            for (int i = 0; i < includes.length; i++) {
                String pattern;
                pattern = includes[i].replace('/',File.separatorChar).replace('\\',File.separatorChar);
                if (pattern.endsWith(File.separator)) {
                    pattern += "**";
                }
                this.includes[i] = pattern;
            }
        }
    }

    /**
     * Sets the set of exclude patterns to use. All '/' and '\' characters are
     * replaced by File.separatorChar. So the separator used need
     * not match File.separatorChar.
     *

     * When a pattern ends with a '/' or '\', "**" is appended.
     *
     * @param excludes list of exclude patterns
     */
    public void setExcludes(String[] excludes) {
        if (excludes == null) {
            this.excludes = null;
        } else {
            this.excludes = new String[excludes.length];
            for (int i = 0; i < excludes.length; i++) {
                String pattern;
                pattern = excludes[i].replace('/',File.separatorChar).replace('\\',File.separatorChar);
                if (pattern.endsWith(File.separator)) {
                    pattern += "**";
                }
                this.excludes[i] = pattern;
            }
        }
    }

    /**
     * Scans the base directory for files that match at least one include
     * pattern, and don't match any exclude patterns.
     *
     * @exception IllegalStateException when basedir was set incorrecly
     */
    public void scan() {
        if (basedir == null) {
            throw new IllegalStateException("No basedir set");
        }
        if (!basedir.exists()) {
            throw new IllegalStateException("basedir " + basedir
                                            + " does not exist");
        }
        if (!basedir.isDirectory()) {
            throw new IllegalStateException("basedir " + basedir
                                            + " is not a directory");
        }

        if (includes == null) {
            includes = new String[1];
            includes[0] = "**";
        }
        if (excludes == null) {
            excludes = new String[0];
        }

        filesIncluded    = new Vector();
        filesNotIncluded = new Vector();
        filesExcluded    = new Vector();
        dirsIncluded     = new Vector();
        dirsNotIncluded  = new Vector();
        dirsExcluded     = new Vector();

        if (isIncluded("")) {
            if (!isExcluded("")) {
                dirsIncluded.addElement("");
            } else {
                dirsExcluded.addElement("");
            }
        } else {
            dirsNotIncluded.addElement("");
        }
        scandir(basedir, "", true);
    }

    /**
     * Toplevel invocation for the scan.
     *
     *
Returns immediately if a slow scan has already been requested.
     */
    protected void slowScan() {
        if (haveSlowResults) {
            return;
        }

        String[] excl = new String[dirsExcluded.size()];
        dirsExcluded.copyInto(excl);

        String[] notIncl = new String[dirsNotIncluded.size()];
        dirsNotIncluded.copyInto(notIncl);

        for (int i=0; i<excl.length; i++) {
            if (!couldHoldIncluded(excl[i])) {
                scandir(new File(basedir, excl[i]),
                        excl[i]+File.separator, false);
            }
        }

        for (int i=0; i<notIncl.length; i++) {
            if (!couldHoldIncluded(notIncl[i])) {
                scandir(new File(basedir, notIncl[i]),
                        notIncl[i]+File.separator, false);
            }
        }

        haveSlowResults  = true;
    }

    /**
     * Scans the passed dir for files and directories. Found files and
     * directories are placed in their respective collections, based on the
     * matching of includes and excludes. When a directory is found, it is
     * scanned recursively.
     *
     * @param dir   the directory to scan
     * @param vpath the path relative to the basedir (needed to prevent
     *              problems with an absolute path when using dir)
     *
     * @see #filesIncluded
     * @see #filesNotIncluded
     * @see #filesExcluded
     * @see #dirsIncluded
     * @see #dirsNotIncluded
     * @see #dirsExcluded
     */
    protected void scandir(File dir, String vpath, boolean fast) {
        String[] newfiles = dir.list();

        if (newfiles == null) {
            /*
             * two reasons are mentioned in the API docs for File.list
             * (1) dir is not a directory. This is impossible as
             *     we wouldn't get here in this case.
             * (2) an IO error occurred (why doesn't it throw an exception
             *     then???)
             */
            throw new BuildException("IO error scanning directory "
                                     + dir.getAbsolutePath());
        }

        for (int i = 0; i < newfiles.length; i++) {
            String name = vpath+newfiles[i];
            File   file = new File(dir,newfiles[i]);
            if (file.isDirectory()) {
                if (isIncluded(name)) {
                    if (!isExcluded(name)) {
                        dirsIncluded.addElement(name);
                        if (fast) {
                            scandir(file, name+File.separator, fast);
                        }
                    } else {
                        dirsExcluded.addElement(name);
                        if (fast && couldHoldIncluded(name)) {
                            scandir(file, name+File.separator, fast);
                        }
                    }
                } else {
                    dirsNotIncluded.addElement(name);
                    if (fast && couldHoldIncluded(name)) {
                        scandir(file, name+File.separator, fast);
                    }
                }
                if (!fast) {
                    scandir(file, name+File.separator, fast);
                }
            } else if (file.isFile()) {
                if (isIncluded(name)) {
                    if (!isExcluded(name)) {
                        filesIncluded.addElement(name);
                    } else {
                        filesExcluded.addElement(name);
                    }
                } else {
                    filesNotIncluded.addElement(name);
                }
            }
        }
    }

    /**
     * Tests whether a name matches against at least one include pattern.
     *
     * @param name the name to match
     * @return true when the name matches against at least one
     *         include pattern, false otherwise.
     */
    protected boolean isIncluded(String name) {
        for (int i = 0; i < includes.length; i++) {
            if (matchPath(includes[i],name, isCaseSensitive)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Tests whether a name matches the start of at least one include pattern.
     *
     * @param name the name to match
     * @return true when the name matches against at least one
     *         include pattern, false otherwise.
     */
    protected boolean couldHoldIncluded(String name) {
        for (int i = 0; i < includes.length; i++) {
            if (matchPatternStart(includes[i],name, isCaseSensitive)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Tests whether a name matches against at least one exclude pattern.
     *
     * @param name the name to match
     * @return true when the name matches against at least one
     *         exclude pattern, false otherwise.
     */
    protected boolean isExcluded(String name) {
        for (int i = 0; i < excludes.length; i++) {
            if (matchPath(excludes[i],name, isCaseSensitive)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Get the names of the files that matched at least one of the include
     * patterns, and matched none of the exclude patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the files
     */
    public String[] getIncludedFiles() {
        int count = filesIncluded.size();
        String[] files = new String[count];
        for (int i = 0; i < count; i++) {
            files[i] = (String)filesIncluded.elementAt(i);
        }
        return files;
    }

    /**
     * Get the names of the files that matched at none of the include patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the files
     */
    public String[] getNotIncludedFiles() {
        slowScan();
        int count = filesNotIncluded.size();
        String[] files = new String[count];
        for (int i = 0; i < count; i++) {
            files[i] = (String)filesNotIncluded.elementAt(i);
        }
        return files;
    }

    /**
     * Get the names of the files that matched at least one of the include
     * patterns, an matched also at least one of the exclude patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the files
     */
    public String[] getExcludedFiles() {
        slowScan();
        int count = filesExcluded.size();
        String[] files = new String[count];
        for (int i = 0; i < count; i++) {
            files[i] = (String)filesExcluded.elementAt(i);
        }
        return files;
    }

    /**
     * Get the names of the directories that matched at least one of the include
     * patterns, an matched none of the exclude patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the directories
     */
    public String[] getIncludedDirectories() {
        int count = dirsIncluded.size();
        String[] directories = new String[count];
        for (int i = 0; i < count; i++) {
            directories[i] = (String)dirsIncluded.elementAt(i);
        }
        return directories;
    }

    /**
     * Get the names of the directories that matched at none of the include
     * patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the directories
     */
    public String[] getNotIncludedDirectories() {
        slowScan();
        int count = dirsNotIncluded.size();
        String[] directories = new String[count];
        for (int i = 0; i < count; i++) {
            directories[i] = (String)dirsNotIncluded.elementAt(i);
        }
        return directories;
    }

    /**
     * Get the names of the directories that matched at least one of the include
     * patterns, an matched also at least one of the exclude patterns.
     * The names are relative to the basedir.
     *
     * @return the names of the directories
     */
    public String[] getExcludedDirectories() {
        slowScan();
        int count = dirsExcluded.size();
        String[] directories = new String[count];
        for (int i = 0; i < count; i++) {
            directories[i] = (String)dirsExcluded.elementAt(i);
        }
        return directories;
    }

    /**
     * Adds the array with default exclusions to the current exclusions set.
     *
     */
    public void addDefaultExcludes() {
        int excludesLength = excludes == null ? 0 : excludes.length;
        String[] newExcludes;
        newExcludes = new String[excludesLength + DEFAULTEXCLUDES.length];
        if (excludesLength > 0) {
            System.arraycopy(excludes,0,newExcludes,0,excludesLength);
        }
        for (int i = 0; i < DEFAULTEXCLUDES.length; i++) {
            newExcludes[i+excludesLength] = DEFAULTEXCLUDES[i].replace('/',File.separatorChar).replace('\\',File.separatorChar);
        }
        excludes = newExcludes;

FUNC_DECL RETURN PARAM PARAM CALL LITERAL_ANCHOR

FUNC_DECL LOOP IF VAR_DECL PARAM PARAM PARAM BINARY_OP BINARY_OP IF VAR_DECL VAR_DECL THROW_RAISE LITERAL_ANCHOR CALL IF CALL LITERAL_ANCHOR CALL CALL IF IF CALL BINARY_OP BINARY_OP IF CALL CALL LITERAL_ANCHOR CALL IF IF IF CALL BINARY_OP CALL CALL CALL CALL BINARY_OP CALL IF IF CALL BINARY_OP CALL CALL CALL CALL BINARY_OP CALL CALL CALL BINARY_OP BINARY_OP


public class IBatisComponent extends DefaultComponent {
    private static final transient Log LOG = LogFactory.getLog(IBatisComponent.class);

    public static final String DEFAULT_CONFIG_URI = "SqlMapConfig.xml";
    private SqlMapClient sqlMapClient;
    private Resource sqlMapResource;

    public IBatisComponent() {
    }

    public IBatisComponent(SqlMapClient sqlMapClient) {
        this.sqlMapClient = sqlMapClient;
    }

    public SqlMapClient getSqlMapClient() throws IOException {
        if (sqlMapClient == null) {
            sqlMapClient = createSqlMapClient();
        }
        return sqlMapClient;
    }

    public void setSqlMapClient(SqlMapClient sqlMapClient) {
        this.sqlMapClient = sqlMapClient;
    }

    public Resource getSqlMapResource() {
        if (sqlMapResource == null) {
            sqlMapResource = new ClassPathResource(DEFAULT_CONFIG_URI);
            LOG.debug("Defaulting to use the iBatis configuration from: " + sqlMapResource);
        }
        return sqlMapResource;
    }

    public void setSqlMapResource(Resource sqlMapResource) {
        this.sqlMapResource = sqlMapResource;
    }

    protected Endpoint createEndpoint(String uri, String remaining, Map parameters) throws Exception {
        return new IBatisEndpoint(uri, this, remaining);
    }

    protected SqlMapClient createSqlMapClient() throws IOException {
        InputStream in = getSqlMapResource().getInputStream();
        return SqlMapClientBuilder.buildSqlMapClient(in);

FUNC_DECL RETURN VAR_DECL CALL CALL CALL


public interface MethodInvocation {

    Method getMethod();

    Object[] getArguments();

    Object proceed() throws Throwable;

    Object getThis();

    AccessibleObject getStaticPart();