Quadcap Embeddable Server

com/quadcap/util/Util.java

Go to the documentation of this file.
00001 package com.quadcap.util; 00002 00003 /* Copyright 1997 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 //-//#ifdef JDK11 00042 //-import com.sun.java.util.collections.ArrayList; 00043 //-import com.sun.java.util.collections.Collections; 00044 //-import com.sun.java.util.collections.Comparator; 00045 //#endif 00046 00047 import java.util.ArrayList; 00048 import java.util.Collections; 00049 import java.util.Comparator; 00050 import java.util.HashMap; 00051 import java.util.Hashtable; 00052 import java.util.List; 00053 import java.util.Properties; 00054 import java.util.Vector; 00055 00056 import java.io.ByteArrayInputStream; 00057 import java.io.ByteArrayOutputStream; 00058 import java.io.File; 00059 import java.io.FileInputStream; 00060 import java.io.FileOutputStream; 00061 import java.io.IOException; 00062 import java.io.InputStream; 00063 import java.io.OutputStream; 00064 import java.io.PrintStream; 00065 00066 import java.text.Collator; 00067 00068 import java.lang.reflect.Array; 00069 00070 /** 00071 * This class aggregates a bunch of various string manipulation utilities. 00072 * 00073 * @author Stan Bailes 00074 */ 00075 public class Util { 00076 /** 00077 * Split a string into a vector of elements. 00078 */ 00079 public static Vector split(String s, char delim) { 00080 return split(s, delim, -1); 00081 } 00082 00083 public static Vector split(String s, char delim, int cnt) { 00084 Vector v = new Vector(); 00085 StringBuffer sb = new StringBuffer(); 00086 for (int i = 0; i < s.length(); i++) { 00087 char c = s.charAt(i); 00088 if (c == delim && (cnt < 0 || v.size()+1 < cnt)) { 00089 if (sb.length() > 0) { 00090 v.addElement(sb.toString()); 00091 sb = new StringBuffer(); 00092 } 00093 } else { 00094 sb.append(c); 00095 } 00096 } 00097 if (sb.length() > 0) { 00098 v.addElement(sb.toString()); 00099 } 00100 while (v.size() < cnt) { 00101 v.addElement(new String("")); 00102 } 00103 return v; 00104 } 00105 00106 public static Hashtable parseArgs(String args[]) { 00107 Hashtable t = new Hashtable(); 00108 int i = 0; 00109 Vector a = new Vector(); 00110 while (i < args.length && args[i].startsWith("-")) { 00111 String arg = args[i]; 00112 if (arg.charAt(0) == '-') { 00113 Vector v = (Vector)t.get(arg); 00114 if (v == null) v = new Vector(); 00115 v.addElement(args[i+1]); 00116 t.put(arg.substring(1), v); 00117 i++; 00118 } else { 00119 a.addElement(arg); 00120 } 00121 i++; 00122 } 00123 t.put("", a); 00124 return t; 00125 } 00126 00127 public static String readFile(String filename) { 00128 File f = new File(filename); 00129 if (f.exists()) { 00130 try { 00131 FileInputStream is = new FileInputStream(f); 00132 StringBuffer sb = new StringBuffer(); 00133 int c; 00134 while ((c = is.read()) >= 0) sb.append((char)c); 00135 String r = sb.toString(); 00136 return r; 00137 } catch (IOException e) { 00138 Debug.println("Util.readFile(" + filename + ") " + 00139 "Got IOException: " + e.toString()); 00140 } 00141 } 00142 return null; 00143 } 00144 00145 public static char[] hexMap = {'0', '1', '2', '3', '4', '5', '6', '7', 00146 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 00147 00148 public static String strBytes(byte[] buf, int offset, int len) { 00149 if (buf == null || len == 0) return "<null>"; 00150 StringBuffer sb = new StringBuffer(); 00151 for (int i = 0; i < len; i++) { 00152 if ((i % 16) == 0 && (len - i > 12 || i > 0)) { 00153 if (i > 0) { 00154 sb.append(' '); 00155 sb.append(' '); 00156 for (int j = (i-1) & ~15; j < i; j++) { 00157 byte c = buf[offset + j]; 00158 if (c >= 0x20 && c <= 0x7f) sb.append((char)c); 00159 else sb.append('.'); 00160 } 00161 } 00162 sb.append('\n'); 00163 } 00164 byte b = buf[offset+i]; 00165 sb.append(hexMap[(b >> 4) & 0xf]); 00166 sb.append(hexMap[b & 0xf]); 00167 sb.append(' '); 00168 } 00169 if (len > 16) for (int j = len; (j&15) != 0; j++) sb.append(" "); 00170 sb.append(" "); 00171 for (int j = (len-1) & ~15; j < len; j++) { 00172 byte c = buf[offset + j]; 00173 if (c >= 0x20 && c <= 0x7f) sb.append((char)c); 00174 else sb.append('.'); 00175 } 00176 return sb.toString(); 00177 } 00178 00179 public static String hexBytes(byte[] buf) { 00180 if (buf == null) return "<null>"; 00181 return hexBytes(buf, 0, buf.length); 00182 } 00183 00184 public static String hexBytes(byte[] buf, int off, int len) { 00185 if (buf == null) return "<null>"; 00186 StringBuffer sb = new StringBuffer(); 00187 for (int i = off; i < off + len; i++) { 00188 if (i >= buf.length) { 00189 sb.append("###### OVERRUN ######"); 00190 break; 00191 } 00192 byte b = buf[i]; 00193 sb.append(hexMap[(b >> 4) & 0xf]); 00194 sb.append(hexMap[b & 0xf]); 00195 } 00196 return sb.toString(); 00197 } 00198 00199 public static String hexInts(byte[] buf) { 00200 return hexInts(buf, 0, buf.length); 00201 } 00202 00203 public static String hexInts(byte[] buf, int off, int len) { 00204 if (buf == null) return "<null>"; 00205 StringBuffer sb = new StringBuffer(); 00206 for (int i = off; i < off + len; i++) { 00207 if (i >= buf.length) { 00208 sb.append("###### OVERRUN ######"); 00209 break; 00210 } 00211 byte b = buf[i]; 00212 sb.append(hexMap[(b >> 4) & 0xf]); 00213 sb.append(hexMap[b & 0xf]); 00214 if ((((i+1) - off) % 4) == 0) sb.append(' '); 00215 } 00216 return sb.toString(); 00217 } 00218 00219 public static String strBytes(byte[] buf) { 00220 if (buf == null) return "<null>"; 00221 return strBytes(buf, 0, buf.length); 00222 } 00223 00224 public static boolean boolProperty(String s) { 00225 return Boolean.getBoolean(s); 00226 } 00227 00228 public static int intProperty(String s, int defVal) { 00229 String v = System.getProperty(s); 00230 return v == null ? defVal : Integer.parseInt(v); 00231 } 00232 00233 public static String strProperty(String s, String defVal) { 00234 String v = System.getProperty(s); 00235 return v == null ? defVal : v; 00236 } 00237 public static byte[] bytes(String s) { 00238 byte[] buf = new byte[s.length()]; 00239 s.getBytes(0, buf.length, buf, 0); 00240 return buf; 00241 } 00242 00243 /** 00244 * To hell with character encodings ;-) 00245 */ 00246 public static byte[] strCharsAsBytes(String s) { 00247 byte[] buf = new byte[s.length() * 2]; 00248 char[] cbuf = s.toCharArray(); 00249 charsToBytes(cbuf, 0, buf, 0, s.length()); 00250 return buf; 00251 } 00252 00253 public static void bytesToChars(byte[] bbuf, int boff, 00254 char[] cbuf, int coff, int clen) { 00255 int clim = coff + clen; 00256 while (coff < clim) { 00257 int c1 = bbuf[boff++] & 0xff; 00258 int c2 = bbuf[boff++] & 0xff; 00259 cbuf[coff++] = (char)((c1 << 8) | c2); 00260 } 00261 } 00262 00263 public static void charsToBytes(char[] cbuf, int coff, 00264 byte[] bbuf, int boff, int clen) { 00265 int clim = coff + clen; 00266 while (coff < clim) { 00267 char c = cbuf[coff++]; 00268 bbuf[boff++] = (byte)(c >> 8); 00269 bbuf[boff++] = (byte)(c & 0xff); 00270 } 00271 } 00272 00273 /** 00274 * Convert an int to a byte array, MSB first 00275 * 00276 * @param i the int value 00277 */ 00278 public static byte[] bytes(int i) { 00279 byte[] buf = new byte[4]; 00280 buf[0] = (byte)((i >> 24) & 0xff); 00281 buf[1] = (byte)((i >> 16) & 0xff); 00282 buf[2] = (byte)((i >> 8) & 0xff); 00283 buf[3] = (byte)((i >> 0) & 0xff); 00284 return buf; 00285 } 00286 00287 /** 00288 * Convert a long to a byte array, MSB first. 00289 * 00290 * @param i the long value 00291 */ 00292 public static byte[] bytes(long i) { 00293 byte[] buf = new byte[8]; 00294 buf[0] = (byte)((i >> 56) & 0xff); 00295 buf[1] = (byte)((i >> 48) & 0xff); 00296 buf[2] = (byte)((i >> 40) & 0xff); 00297 buf[3] = (byte)((i >> 32) & 0xff); 00298 buf[4] = (byte)((i >> 24) & 0xff); 00299 buf[5] = (byte)((i >> 16) & 0xff); 00300 buf[6] = (byte)((i >> 8) & 0xff); 00301 buf[7] = (byte)((i >> 0) & 0xff); 00302 return buf; 00303 } 00304 00305 /** 00306 * Convert a byte array which represents an integer into an integer. 00307 * 00308 * @param buf the byte array, MSB first. 00309 * @return the integer value stored in the byte array. 00310 */ 00311 public static int integer(byte[] buf) { 00312 int ret = 0; 00313 for (int i = 0; i < buf.length; i++) { 00314 ret <<= 8; 00315 ret |= (buf[i] & 0xff); 00316 } 00317 return ret; 00318 } 00319 00320 /** 00321 * Extract an integer from four bytes in a byte array. 00322 * 00323 * @param buf the byte array 00324 * @param pos the offset in the array of the first (MSB) byte of the int 00325 * @return the integer value stored in the byte array. 00326 */ 00327 public static int integer(byte[] buf, int pos) { 00328 int b1 = buf[pos++] & 0xff; 00329 int b2 = buf[pos++] & 0xff; 00330 int b3 = buf[pos++] & 0xff; 00331 int b4 = buf[pos++] & 0xff; 00332 int val = (b1 << 24) + (b2 << 16) + (b3 << 8) + (b4 << 0) ; 00333 return val; 00334 } 00335 00336 public static void putInt(byte[] buf, int pos, int val) { 00337 buf[pos++] = (byte)((val >>> 24) & 0xff); 00338 buf[pos++] = (byte)((val >>> 16) & 0xff); 00339 buf[pos++] = (byte)((val >>> 8) & 0xff); 00340 buf[pos] = (byte)((val ) & 0xff); 00341 } 00342 00343 public static void putLong(byte[] buf, int pos, long val) { 00344 buf[pos++] = (byte)((val >>> 56) & 0xff); 00345 buf[pos++] = (byte)((val >>> 48) & 0xff); 00346 buf[pos++] = (byte)((val >>> 40) & 0xff); 00347 buf[pos++] = (byte)((val >>> 32) & 0xff); 00348 buf[pos++] = (byte)((val >>> 24) & 0xff); 00349 buf[pos++] = (byte)((val >>> 16) & 0xff); 00350 buf[pos++] = (byte)((val >>> 8) & 0xff); 00351 buf[pos] = (byte)((val ) & 0xff); 00352 } 00353 00354 /** 00355 * Convert a byte array which represents a long into a long. 00356 * 00357 * @param buf the byte array, MSB first. 00358 * @return the long value stored in the byte array. 00359 */ 00360 public final static long bytesToLong(byte[] buf) { 00361 return bytesToLong(buf, 0); 00362 } 00363 00364 /** 00365 * Convert a byte array which represents a long into a long. 00366 * 00367 * @param buf the byte array, MSB first. 00368 * @return the long value stored in the byte array. 00369 */ 00370 public final static long bytesToLong(byte[] buf, int offset) { 00371 long ret = 0; 00372 int lim = offset + 8; 00373 for (int i = offset; i < buf.length && i < lim; i++) { 00374 ret <<= 8; 00375 ret |= (buf[i] & 0xff); 00376 } 00377 return ret; 00378 } 00379 00380 /** 00381 * Byte-array comparison. 00382 * 00383 * @param k1 the byte array containing key 1. 00384 * @param s1 the starting offset of key 1 in <code>k1</code>. 00385 * @param c1 the length of key 1. 00386 * @param k2 the byte array containing key 2. 00387 * @param s2 the starting offset of key 2 in <code>k2</code>. 00388 * @param c2 the length of key 2. 00389 * @return<p><table cellspacing=2 border=2> 00390 * <tr><td>&lt; zero<td>if key1 is less than key2 00391 * <tr><td>zero<td>if key1 is equal to key2 00392 * <tr><td>&gt; zero<td>if key1 is greater than key2</table> 00393 */ 00394 public static int compareBytes(byte[] k1, int s1, int c1, 00395 byte[] k2, int s2, int c2) 00396 { 00397 int l1 = s1 + c1; 00398 int l2 = s2 + c2; 00399 while (s1 < l1 && s2 < l2) { 00400 if (k1[s1] < k2[s2]) return -1; 00401 if (k1[s1] > k2[s2]) return 1; 00402 s1++; 00403 s2++; 00404 } 00405 if (c1 < c2) return -1; 00406 if (c1 > c2) return 1; 00407 return 0; 00408 } 00409 00410 public static int compareBytes(byte[] b1, byte[] b2) { 00411 return compareBytes(b1, 0, b1.length, b2, 0, b2.length); 00412 } 00413 00414 /** 00415 * Return a File object corresponding to the specified file name. 00416 * If the name is relative, it is located relative to the user's 00417 * current directory. This is helpful for the case when we run 00418 * as a service from the /winnt/system32 directory and want to 00419 * open files relative to our install root. 00420 * 00421 * @param name the file name 00422 * @return the file 00423 */ 00424 public static File userFile(String name) { 00425 File f = new File(name); 00426 f = new File(f.getAbsolutePath()); 00427 return f; 00428 } 00429 00430 /** 00431 * Like File.list(), but returns directories first, and sorts alpha 00432 */ 00433 public static String[] listFiles(final File f) { 00434 String[] s = f.list(); 00435 if (s != null) { 00436 final Collator col = Collator.getInstance(); 00437 Comparator c = new Comparator() { 00438 public int compare(Object a, Object b) { 00439 File fa = new File(f, a.toString()); 00440 File fb = new File(f, b.toString()); 00441 if (fa.isDirectory() && !fb.isDirectory()) return -1; 00442 if (!fa.isDirectory() && fb.isDirectory()) return 1; 00443 return col.compare(a.toString(), b.toString()); 00444 } 00445 public boolean equals(Object obj) { return false; } 00446 }; 00447 ArrayList a = new ArrayList(); 00448 for (int i = 0; i < s.length; i++) a.add(s[i]); 00449 Collections.sort(a, c); 00450 for (int i = 0; i < s.length; i++) s[i] = (String)a.get(i); 00451 } 00452 return s; 00453 } 00454 00455 public static String getStackTrace(Throwable t) { 00456 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 00457 PrintStream ps = new PrintStream(bos); 00458 t.printStackTrace(ps); 00459 ps.flush(); 00460 return bos.toString(); 00461 } 00462 00463 static HashMap traces = new HashMap(); 00464 static int lastTrace = 0; 00465 00466 /** 00467 * Return a string showing the current stack trace. 00468 */ 00469 public static String stackTrace() { 00470 return stackTrace(new Exception(""), true); 00471 } 00472 00473 public static String stackTrace(boolean condense) { 00474 return stackTrace(new Exception(""), condense); 00475 } 00476 00477 /** 00478 * Return a string showing the current stack trace. 00479 */ 00480 public static String stackTrace(Throwable e, boolean condense) { 00481 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 00482 PrintStream ps = new PrintStream(bos); 00483 e.printStackTrace(ps); 00484 ps.flush(); 00485 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 00486 StringBuffer sb = new StringBuffer(); 00487 int state = 1; 00488 while (state >= 0) { 00489 int c = bis.read(); 00490 if (c < 0) state = -1; 00491 switch (state) { 00492 case -1: 00493 break; 00494 case 0: 00495 if (c == '\n') state++; 00496 break; 00497 case 1: 00498 if (c == '\n') state++; 00499 break; 00500 case 2: 00501 if (c == 'a') state++; 00502 break; 00503 case 3: 00504 if (c == 't') state++; 00505 break; 00506 case 4: 00507 if (c == ' ') state++; 00508 break; 00509 case 5: 00510 sb.append((char)c); 00511 if (c == '\n') state = 2; 00512 break; 00513 } 00514 } 00515 String s = sb.toString(); 00516 Integer num = (Integer)traces.get(s); 00517 if (num == null) { 00518 num = new Integer(++lastTrace); 00519 traces.put(s, num); 00520 s = "Trace " + num + ": " + s; 00521 } else { 00522 s = "Trace " + num + (condense ? "" : (": " + s)); 00523 } 00524 return s; 00525 } 00526 00527 public static void copyStream(InputStream in, OutputStream out) 00528 throws IOException 00529 { 00530 byte[] buf = new byte[4096]; 00531 int cnt; 00532 while ((cnt = in.read(buf)) > 0) out.write(buf, 0, cnt); 00533 } 00534 00535 public static int execCommand(String cmd, 00536 OutputStream out, OutputStream err) { 00537 int ret = -1; 00538 try { 00539 Runtime r = Runtime.getRuntime(); 00540 Process p = r.exec(cmd); 00541 return waitFor(p, out, err); 00542 } catch (IOException e) { 00543 Debug.print(e); 00544 ret = -1; 00545 } 00546 return ret; 00547 } 00548 00549 public static int execCommand(String[] cmdarray, 00550 OutputStream out, OutputStream err) { 00551 int ret = -1; 00552 try { 00553 Runtime r = Runtime.getRuntime(); 00554 Process p = r.exec(cmdarray); 00555 return waitFor(p, out, err); 00556 } catch (IOException e) { 00557 Debug.print(e); 00558 ret = -1; 00559 } 00560 return ret; 00561 } 00562 00563 public static int waitFor(Process p, OutputStream out, 00564 OutputStream err) throws IOException { 00565 Thread it = makeCopyThread(p.getInputStream(), out); 00566 Thread et = makeCopyThread(p.getErrorStream(), err); 00567 it.start(); 00568 et.start(); 00569 int ret = Util.waitFor(p); 00570 Util.join(it); 00571 Util.join(et); 00572 return ret; 00573 } 00574 00575 00576 00577 public static int execCommand(String cmd, OutputStream out) { 00578 return execCommand(cmd, out, out); 00579 } 00580 00581 public static String execCommand(String cmd) { 00582 ByteArrayOutputStream b = new ByteArrayOutputStream(); 00583 execCommand(cmd, b); 00584 return b.toString(); 00585 } 00586 00587 public static String execCommand(String[] cmd) { 00588 ByteArrayOutputStream b = new ByteArrayOutputStream(); 00589 execCommand(cmd, b, b); 00590 return b.toString(); 00591 } 00592 00593 public static String execCommand(String a, String b) { 00594 return execCommand(new String[]{a, b}); 00595 } 00596 public static String execCommand(String a, String b, String c) { 00597 return execCommand(new String[]{a, b, c}); 00598 } 00599 00600 /** 00601 * Create a thread which copies bytes from an input stream to 00602 * an output stream until end of file is reached. 00603 */ 00604 public static Thread makeCopyThread(final InputStream in, 00605 final OutputStream out) { 00606 Thread t = new Thread() { 00607 boolean terminate = false; 00608 public void run() { 00609 int c; 00610 try { 00611 while (!terminate && (c = in.read()) >= 0) out.write(c); 00612 } catch (IOException e) { 00613 Debug.print(e); 00614 } 00615 } 00616 public void terminate() { 00617 this.terminate = true; 00618 } 00619 }; 00620 return t; 00621 } 00622 00623 /** 00624 * Utility to sleep without having to worry about catching 00625 * InterruptedException. 00626 * 00627 * @param ms milliseconds to sleep. 00628 */ 00629 public static final void sleep(long ms) { 00630 try { 00631 Thread.sleep(ms); 00632 } catch (InterruptedException e) { 00633 Debug.print(e); 00634 } 00635 } 00636 00637 /** 00638 * Utility to join without having to worry about catching 00639 * InterruptedException. 00640 * 00641 * @param t the thread to wait for 00642 */ 00643 public static final void join(Thread t) { 00644 try { 00645 t.join(); 00646 } catch (InterruptedException e) { 00647 Debug.print(e); 00648 } 00649 } 00650 00651 /** 00652 * Utility to wait for a process without having to worry about catching 00653 * InterruptedException 00654 * 00655 * @param p the process to wait for 00656 */ 00657 public static final int waitFor(Process p) { 00658 try { 00659 return p.waitFor(); 00660 } catch (InterruptedException e) { 00661 Debug.print(e); 00662 return -1; 00663 } 00664 } 00665 00666 /** 00667 * Parse a semicolon-separated property list: 00668 * 00669 * prop1=val1;prop2=val2 00670 */ 00671 public static final Properties parsePropsString(String extraProps) { 00672 Properties props = new Properties(); 00673 Vector v = Util.split(extraProps, ';'); 00674 for (int i = 0; i < v.size(); i++) { 00675 String prop = v.elementAt(i).toString(); 00676 int idx = prop.indexOf('='); 00677 if (idx > 0) { 00678 props.setProperty(prop.substring(0, idx), 00679 prop.substring(idx+1)); 00680 } 00681 } 00682 return props; 00683 } 00684 00685 /** 00686 * Generic array resizer 00687 */ 00688 public static Object checkCapacity(Object array, int desiredcap) { 00689 int len = Array.getLength(array); 00690 if (len < desiredcap) { 00691 Class c = array.getClass(); 00692 Class t = c.getComponentType(); 00693 Object n = Array.newInstance(t, desiredcap); 00694 System.arraycopy(array, 0, n, 0, len); 00695 array = n; 00696 } 00697 return array; 00698 } 00699 00700 /** 00701 * Parse a comma-separated list of integers or integer ranges. 00702 * 00703 * Example: 1,2 00704 * Example: 1,3-5,77 00705 * 00706 * @return a List of Integers 00707 */ 00708 public static List parseIntList(String s) { 00709 List ret = new ArrayList(); 00710 List tests = Util.split(s, ','); 00711 00712 for (int i = 0; i < tests.size(); i++) { 00713 int first, last; 00714 final String t = tests.get(i).toString(); 00715 final int idx = t.indexOf('-'); 00716 if (idx > 0) { 00717 first = Integer.parseInt(t.substring(0, idx)); 00718 last = Integer.parseInt(t.substring(idx+1)); 00719 if (last < first) last = first; 00720 } else { 00721 first = last = Integer.parseInt(t); 00722 } 00723 for (int test = first; test <= last; test++) { 00724 ret.add(new Integer(test)); 00725 } 00726 } 00727 return ret; 00728 } 00729 00730 public static int compareObjects(Object a, Object b) { 00731 if (a == null) { 00732 return (b == null) ? 0 : -1; 00733 } else if (b == null) { 00734 return 1; 00735 } else if (a instanceof Comparable) { 00736 return ((Comparable)a).compareTo(b); 00737 } else if (b instanceof Comparable) { 00738 return 0 - ((Comparable)b).compareTo(a); 00739 } else { 00740 return String.valueOf(a).compareTo(String.valueOf(b)); 00741 } 00742 } 00743 00744 public static String htmlEscape(String s) { 00745 StringBuffer sb = new StringBuffer(); 00746 for (int i = 0; i < s.length(); i++) { 00747 char c = s.charAt(i); 00748 switch (c) { 00749 case '<': sb.append("&lt;"); break; 00750 case '>': sb.append("&gt;"); break; 00751 case '&': sb.append("&amp;"); break; 00752 default: sb.append(c); break; 00753 } 00754 } 00755 return sb.toString(); 00756 } 00757 00758 }