/* * `gnu.iou' * Copyright (C) 2006 John Pritchard. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ package gnu.iou ; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.NoSuchElementException; import java.util.StringTokenizer; /** * Parse input `String' text into lines, and then columns split by * "%name%" tokens. * * <p> For example, one line containing one special "%name%" token * would be parsed into three columns. * <pre> * {"The ", "%quick%", " brown fox is famous."} * </pre> * * <p> Instance object for generating output into during parsing of * "src". * * @author John Pritchard (john@syntelos.org) */ public abstract class templ { private final static String[][] add ( String[][] src, String[] element){ if ( null == src) src = new String[1][]; else { String[][] copier = new String[src.length+1][]; System.arraycopy(src,0,copier,0,src.length); src = copier; } src[src.length-1] = element; return src; } /** * Parse as a template, returning null if there are no template * objects in the text. */ public final static String[][] parseValidate ( String text){ return parse(text,true); } /** * Parse text string into lines and columns. One column per line * unless there are "%...%" tokens in the line, in which case the * "%...%" tokens are separated. * * @param text Text string */ public final static String[][] parse ( String text){ return parse(text,false); } /** * @param text Template text * @param validate If true, return null if there are no template tokens. */ public final static String[][] parse ( String text, boolean validate){ if ( null == text) return null; StringTokenizer strtok = new StringTokenizer(text,"\r\n",true); String[][] src = null; int c = 0, cc = 0; String s1, s2, s3; boolean validate_havetok = false; try { /* parse input into lines */ String[] tmp; while (true){ s1 = strtok.nextToken(); if ( 1 == s1.length()){ switch(s1.charAt(0)){ case '\r': break; case '\n': cc += 1; if ( 2 <= cc) src = add(src,null); break; default: cc = 0; tmp = new String[1]; tmp[0] = s1; src = add(src,tmp); break; } } else { cc = 0; tmp = new String[1]; tmp[0] = s1; src = add(src,tmp); } } } catch ( NoSuchElementException nsx){} /* parse lines for %template directives% */ char[] line; int mark, markPC1, markPC2; String[] reline = null, copier; for ( c = 0; c < src.length; c++){ if ( null != src[c]){ reline = null; line = src[c][0].toCharArray(); mark = 0; for ( cc = 0; cc < line.length; cc++){ switch(line[cc]){ case '%': markPC1 = cc++; markPC2 = -1; s1 = null; s2 = null; s3 = null; fl2: for ( ; cc < line.length; cc++){ switch(line[cc]){ case '%': markPC2 = cc; break fl2; default: break; } } if ( markPC2 > markPC1){ validate_havetok = true; /* slice */ if ( 0 < markPC1){ s1 = new String(line,mark,markPC1-mark); s2 = new String(line,markPC1,markPC2-markPC1+1); mark = cc +1; // cc = markPC2 if ( 0 < (line.length-mark)) s3 = new String(line,mark,line.length-mark); } else if ( 0 < (line.length-(cc+1))){ s1 = new String(line,markPC1,markPC2-markPC1+1); mark = cc +1; // cc = markPC2 s2 = new String(line,mark,line.length-mark); } /* reline */ if ( null != s3){ if ( null == reline) reline = new String[3]; else { copier = new String[reline.length+2]; System.arraycopy(reline,0,copier,0,reline.length); reline = copier; } reline[reline.length-3] = s1; reline[reline.length-2] = s2; reline[reline.length-1] = s3; src[c] = reline; } else if ( null != s2){ if ( null == reline) reline = new String[2]; else { copier = new String[reline.length+1]; System.arraycopy(reline,0,copier,0,reline.length); reline = copier; } reline[reline.length-2] = s1; reline[reline.length-1] = s2; src[c] = reline; } } break; default: break; } } } } if (validate){ if (validate_havetok) return src; else return null; } else return src; } private final static String TEXT_PREFIX = "{\\{\\{"; private final static String LINE_LEFT = "{\\{"; private final static String LINE_RIGHT = "}/}"; private final static String LINE_INFIX = "|,|"; private final static String TEXT_SUFFIX = "}/}/}"; private final static String[] helpary = { null, " Usage: templ filename", null, " Description", null, "\tDisplays parsed input file using tryglyph token delimiters.", null, "\tUses \""+TEXT_PREFIX+"\" before the text.", null, "\tUses \""+LINE_LEFT+"\" on the left hand side of a line.", null, "\tUses \""+LINE_INFIX+"\" among tokens within a line.", null, "\tUses \""+LINE_RIGHT+"\" on the right hand side of a line.", null, "\tUses \""+TEXT_SUFFIX+"\" after the text.", null, "\tIn this way, the tokenization of the text is clearly readable.", null }; private final static String help = new linebuf(helpary).toString(); public static void main( String[] argv){ try { if ( null == argv || 1 != argv.length) throw new IllegalArgumentException(help); File inf = new File(argv[0]); if (! (inf.exists() && inf.canRead())) throw new IllegalArgumentException("Can't read file `"+inf+"'"); byte[] inbuf = new byte[ (int)inf.length()]; InputStream in = new FileInputStream(inf); in.read(inbuf); String[][] pars = parse(new String(inbuf)); System.out.println(TEXT_PREFIX); for ( int c = 0, cc; c < pars.length; c++){ System.out.print("\t"+LINE_LEFT); for ( cc = 0; null != pars[c] && cc < pars[c].length; cc++){ if ( null != pars[c][cc]) System.out.print(pars[c][cc]); if ( cc < pars[c].length-1) System.out.print(LINE_INFIX); } System.out.println(LINE_RIGHT); } System.out.println(TEXT_SUFFIX); } catch ( IllegalArgumentException ilx){ System.err.println(ilx.getMessage()); } catch ( Exception exc){ exc.printStackTrace(); } } }