| package xdc.rta; |
| |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| import xdc.rov.ISymbolTable; |
| |
| /* |
| * ======== Formatter ======== |
| */ |
| public class Formatter { |
| |
| private static ISymbolTable symTab = null; |
| private static IOFReader ofReader = null; |
| |
| public static void setSymbolTable(ISymbolTable inSymTab) |
| { |
| symTab = inSymTab; |
| } |
| |
| public static void setOFReader(IOFReader inOFReader) |
| { |
| ofReader = inOFReader; |
| } |
| |
| public static ISymbolTable getSymbolTable() |
| { |
| return (symTab); |
| } |
| |
| /* |
| * ======== ParseData ======== |
| */ |
| static class ParseData { |
| public String ptr; |
| public boolean lJust; |
| public boolean lFlag; |
| public int zpad; |
| public int len; |
| public int width; |
| public int precis; |
| } |
| |
| /* |
| * ======== doPrint ======== |
| */ |
| public static String doPrint(String format, int [] args) |
| { |
| return (doPrint(format, args, 4)); |
| } |
| |
| public static String doPrint(String format, int [] args, int argSize) |
| { |
| if (format == null) { |
| return ("(null format)"); |
| } |
| |
| String res = ""; |
| char [] fmt = format.toCharArray(); |
| |
| /* temp vars */ |
| int base = 10; |
| char c; |
| int findex = 0; /* index into format string */ |
| int aindex = 0; /* imdex into args array */ |
| |
| ParseData parse = new ParseData(); |
| |
| while (findex < fmt.length) { |
| c = fmt[findex++]; |
| if (c != '%') { |
| res += Character.toString(c); |
| } |
| else { |
| c = fmt[findex++]; |
| /* check for - flag (pad on right) */ |
| if (c == '-') { |
| parse.lJust = true; |
| c = fmt[findex++]; |
| } |
| else { |
| parse.lJust = false; |
| } |
| |
| /* check for leading 0 pad */ |
| if (c == '0') { |
| parse.zpad = 1; |
| c = fmt[findex++]; |
| } |
| else { |
| parse.zpad = 0; |
| } |
| |
| /* allow optional field width/precision specification */ |
| parse.width = 0; |
| parse.precis = -1; |
| |
| if (c == '*') { |
| parse.width = aindex >= args.length ? 0 : args[aindex++]; |
| c = fmt[findex++]; |
| if (parse.width < 0) { |
| parse.lJust = true; |
| parse.width = -parse.width; |
| } |
| } |
| else { |
| while (c >= '0' && c <= '9') { |
| parse.width = parse.width * 10 + c - '0'; |
| c = fmt[findex++]; |
| } |
| } |
| |
| /* allow optional field precision specification */ |
| if (c == '.') { |
| parse.precis = 0; |
| c = fmt[findex++]; |
| if (c == '*') { |
| parse.precis = aindex >= args.length ? 0 : args[aindex++]; |
| if (parse.precis < 0) { |
| parse.precis = 0; |
| } |
| |
| c = fmt[findex++]; |
| } |
| else { |
| while (c >= '0' && c <= '9') { |
| parse.precis = parse.precis * 10 + c - '0'; |
| c = fmt[findex++]; |
| } |
| } |
| } |
| |
| /* setup for leading zero padding */ |
| if (parse.zpad != 0) { |
| parse.zpad = parse.width; |
| } |
| |
| if (parse.precis > parse.zpad) { |
| parse.zpad = parse.precis; |
| } |
| |
| /* check for presence of l flag (e.g., %ld) */ |
| if (c == 'l' || c == 'L') { |
| parse.lFlag = true; |
| c = fmt[findex++]; |
| } |
| else { |
| parse.lFlag = false; |
| } |
| |
| parse.ptr = ""; |
| parse.len = 0; |
| |
| int val = aindex >= args.length ? 0 : args[aindex++]; |
| |
| if (c == 'd' || c == 'i') { |
| /* signed decimal */ |
| parse.ptr = formatNum(val, parse.zpad, -10, argSize); |
| parse.len = parse.ptr.length(); |
| } |
| else if (c == 'u' || /* unsigned decimal */ |
| c == 'x' || /* unsigned hex */ |
| c == 'X' || /* uppercase hex */ |
| c == 'o') { /* unsigned octal */ |
| base = 10; |
| if (c == 'x' || c == 'X') { |
| base = 16; |
| } |
| else if (c == 'o') { |
| base = 8; |
| } |
| |
| if (c == 'X') { |
| /* Parse using upper case digits */ |
| parse.ptr = formatNum(val, parse.zpad, base, argSize, true); |
| } |
| else { |
| /* Parse using lower case digits */ |
| parse.ptr = formatNum(val, parse.zpad, base, argSize, false); |
| } |
| |
| parse.len = parse.ptr.length(); |
| } |
| else if (c == 'p') { |
| base = 16; |
| parse.zpad = 2 * argSize; |
| parse.ptr = formatNum( |
| val, |
| parse.zpad, base, |
| argSize); |
| parse.ptr = "@" + parse.ptr; |
| parse.len = parse.ptr.length(); |
| } |
| else if (c == 'c') { |
| /* character */ |
| parse.ptr = Character.toString((char)val); |
| parse.len = 1; |
| } |
| else if (c == 'r') { |
| /* lookup symbol table symbol */ |
| parse.ptr = lookupSymbol(val); |
| parse.len = parse.ptr.length(); |
| } |
| else if (c == 's') { |
| /* string */ |
| /* substitute (null) for NULL pointer */ |
| if (val == 0) { |
| parse.ptr = "(null)"; |
| } |
| else { |
| parse.ptr = lookupString(val); |
| } |
| parse.len = parse.ptr.length(); |
| if (parse.precis != -1 && parse.precis < parse.len) { |
| parse.len = parse.precis; |
| } |
| } |
| else { |
| /* unknown format, just output the character */ |
| parse.ptr = Character.toString(c); |
| parse.len = 1; |
| aindex--; /* unget the value */ |
| } |
| |
| /* compute number of characters left in field */ |
| parse.width -= parse.len; |
| |
| if (!parse.lJust) { |
| /* pad with blanks on left */ |
| while (--parse.width >= 0) { |
| res += " "; |
| } |
| } |
| |
| /* output number, character or string */ |
| res += parse.ptr; |
| |
| /* pad with blanks on right */ |
| if (parse.lJust) { |
| while (--parse.width >= 0) { |
| res += " "; |
| } |
| } |
| } /* if */ |
| } /* while */ |
| |
| return (res); |
| } |
| |
| /* |
| * ======== formatNum ======== |
| */ |
| static String formatNum(int val, int zpad, int base, int argSize) |
| { |
| return (formatNum(val, zpad, base, argSize, false)); |
| } |
| |
| /* |
| * ======== formatNum ======== |
| */ |
| static String formatNum(int val, int zpad, int base, int argSize, boolean caps) |
| { |
| String res = ""; |
| int i = 0; |
| char sign = '\0'; |
| |
| char[] upper = { |
| '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', |
| 'A', 'B', 'C', 'D', 'E', 'F' |
| }; |
| |
| char[] lower = { |
| '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', |
| 'a', 'b', 'c', 'd', 'e', 'f' |
| }; |
| |
| char [] digtohex; |
| |
| if (caps) { |
| digtohex = upper; |
| } |
| else { |
| digtohex = lower; |
| } |
| |
| long n = val >= 0 ? (long)val : ((0x1L << (8 * argSize)) + val); |
| |
| if (base < 0) { |
| /* treat val as a signed value */ |
| base = -base; |
| if (val < 0) { |
| n = -val; |
| /* account for sign '-': ok since zpad is signed */ |
| --zpad; |
| sign = '-'; |
| } |
| } |
| |
| /* compute digits in the number from right to left */ |
| do { |
| res = digtohex[(int)(n % base)] + res; |
| n = n / base; |
| ++i; |
| } while (n != 0); |
| |
| /* pad with leading 0s on left */ |
| while (i < zpad) { |
| res = '0' + res; |
| ++i; |
| } |
| |
| /* add sign indicator */ |
| if (sign != '\0') { |
| res = sign + res; |
| } |
| |
| return (res); |
| } |
| |
| /* |
| * ======== lookupString ======== |
| */ |
| private static String lookupString(long addr) |
| { |
| /* |
| * Convert address to unsigned. |
| * The arguments are signed IArgs, so the address may be negative and |
| * need to be converted. |
| */ |
| if (addr < 0) { |
| addr += Math.pow(2, 32); |
| } |
| |
| if (ofReader != null) { |
| String str = ofReader.findString(addr); |
| if (str != null) { |
| return (str); |
| } |
| } |
| |
| /* can't find a static string */ |
| return ("<String @" + Long.toHexString(addr) + ">"); |
| } |
| |
| /* |
| * ======== lookupSymbol ======== |
| * Lookup symbol name in symbol table |
| */ |
| private static String lookupSymbol(long addr) |
| { |
| /* |
| * Convert address to unsigned. |
| * The arguments are signed IArgs, so the address may be negative and |
| * need to be converted. |
| */ |
| if (addr < 0) { |
| addr += Math.pow(2, 32); |
| } |
| |
| if (symTab != null) { |
| String symbols[] = null; |
| /* Try code symbol first. */ |
| symbols = symTab.lookupFuncName(addr); |
| if ((symbols != null) && (symbols.length > 0)) { |
| return (symbols[0]); |
| } |
| |
| /* If no code symbol, try data symbol. */ |
| symbols = symTab.lookupDataSymbol(addr); |
| if ((symbols != null) && (symbols.length > 0)) { |
| return (symbols[0]); |
| } |
| } |
| |
| /* can't find symbol name */ |
| return ("<Symbol @" + Long.toHexString(addr) + ">"); |
| } |
| |
| /* |
| * ======== main ======== |
| * Simple unit test of doPrint |
| */ |
| static public void main(String [] args) |
| { |
| String [] fmts = { |
| "%%d test: %0.3d, %.3d, %3d, '%-3d', '%-0.3d'\n", |
| "%%x test: %0.3x, %.3x, %3x, '%-3x', '%-0.3x'\n", |
| "%%X test: %0.3X, %.3X, %3X, '%-3X', '%-0.3X'\n", |
| "%%o test: %0.3o, %.3o, %3o, '%-3o', '%-0.3o'\n", |
| "%%p test: %0.3p, %.3p, %3p, '%-3p', '%-0.3p'\n", |
| "%%u test: %0.3u, %.3u, %3u, '%-3u', '%-0.3u'\n", |
| "too many %%'s test: %x, %x, %x, %x, %x, %x, %x\n", |
| "%%* test: '%0.*d', '%*.*d'\n", |
| }; |
| |
| int [] argv = {1, 2, 3, 4, 5}; |
| for (int i = 0; i < fmts.length; i++) { |
| System.out.print(doPrint(fmts[i], argv)); |
| System.out.print(doPrint(fmts[i], argv, 2)); |
| } |
| |
| argv = new int [] {-1, -2, -3, -4, -5}; |
| for (int i = 0; i < fmts.length; i++) { |
| System.out.print(doPrint(fmts[i], argv)); |
| System.out.print(doPrint(fmts[i], argv, 2)); |
| } |
| |
| System.out.print(doPrint( |
| "%%*x test: '%0.*x', '%*.*x', '%*.*x'\n", |
| new int [] {5, 0xcafe, |
| -7, 0, 0xbeef, |
| 7, 0, 0xbabe}, 2)); |
| |
| System.out.print(doPrint( |
| "%%*x test: '%0.*x', '%*.*x', '%*.*x'\n", |
| new int [] {5, 0xcafe, |
| -7, 0, 0xbeef, |
| 7, 0, 0xbabe}, 4)); |
| |
| System.out.print(doPrint( |
| "%%s test: '%*s', '%s'\n", |
| new int [] {10, 0, 17}, 4)); |
| |
| System.out.print(doPrint( |
| "%%r test: '%*r', '%r'\n", |
| new int [] {5, 0, 17}, 4)); |
| |
| } |
| } |