| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
| At |
|
| 5.052631578947368;5.053 |
| 1 | /*---------------------------------------------------------------- |
|
| 2 | * $Id: At.java,v 1.1.1.1 2005/06/08 00:33:07 pkb Exp $ |
|
| 3 | * |
|
| 4 | * (c)2000 - Paul Blankenbaker |
|
| 5 | * |
|
| 6 | * Revision Log |
|
| 7 | * |
|
| 8 | * 2000-11-16 13:10:56 Paul Blankenbaker |
|
| 9 | * |
|
| 10 | * Created initial version |
|
| 11 | */ |
|
| 12 | //---------------------------------------------------------------- |
|
| 13 | ||
| 14 | package com.ccg.macros; |
|
| 15 | ||
| 16 | import com.ccg.util.*; |
|
| 17 | import com.ccg.io.*; |
|
| 18 | ||
| 19 | import java.io.*; // needed for I/O operations |
|
| 20 | import java.util.*; // handy utility classes |
|
| 21 | ||
| 22 | ||
| 23 | //---------------------------------------------------------------- |
|
| 24 | /** A command line implementation of "@macros". |
|
| 25 | * |
|
| 26 | * <p>This is a full working "filter" type of program which is capable |
|
| 27 | * of processing macros. It comes with a built in set of macros (see |
|
| 28 | * the method defintions for the built in macros. |
|
| 29 | * |
|
| 30 | * <p>This program works as a standard Unix filter. It reads in a |
|
| 31 | * ASCII text file, interprets (processes) any contained macros and |
|
| 32 | * outputs the resulting text file. As an example, try feeding in the |
|
| 33 | * following contents to a invocation of "java com.ccg.macros.At": |
|
| 34 | * |
|
| 35 | * <pre> |
|
| 36 | @define(pkb_email,"@quote(paul@mekwin.com)") |
|
| 37 | @define(pkb,"Paul Blankenbaker (@pkb_email)") |
|
| 38 | ||
| 39 | Hello @pkb, looks like your |
|
| 40 | email is "@pkb_email". Today is @now. |
|
| 41 | ||
| 42 | @define(pkb_email,"@quote(paul_blankenbaker@yahoo.com)") |
|
| 43 | Did the email address in the @quote(@pkb) macro change? |
|
| 44 | @quote(@pkb)=@pkb |
|
| 45 | ||
| 46 | Currently, the @quote(@pkb) macro is defined as |
|
| 47 | "@definition(pkb)". The built-in @quote(@now) macro |
|
| 48 | is defined as a Java method invocation which looks like: |
|
| 49 | "@definition(now)". |
|
| 50 | ||
| 51 | Here is a list of ALL available definitions. |
|
| 52 | ||
| 53 | @dumpDefinitions |
|
| 54 | * </pre> |
|
| 55 | * |
|
| 56 | * <p>You can use many of the standard command line options which the |
|
| 57 | * {@link CommandLineUtility CommandLineUtility} class recognizes. In |
|
| 58 | * addtion, the following command line options are recognized: |
|
| 59 | * |
|
| 60 | * <dl> |
|
| 61 | * |
|
| 62 | * <dt><b>-Dname=val</b></dt><dd>This allows one to define macros on |
|
| 63 | * the command line. You may include zero or more definitions. For |
|
| 64 | * example "-Dfirst=Paul -Dlast=Blankenbaker" on the command line is |
|
| 65 | * equivalent to |
|
| 66 | * '@define("first","Paul")@define("last","Blankenbaker")' in a source |
|
| 67 | * file. This allows one to pass/define values outside of the source |
|
| 68 | * files.</dd> |
|
| 69 | * |
|
| 70 | * <dt><b>-nodefaults [true|false]</b></dt><dd>Specify this option to |
|
| 71 | * turn off the loading of the user's default macro definitions. By |
|
| 72 | * default, this application first tries to load the file |
|
| 73 | * "$HOME/.etc/atmacros/default.atmacros" (discarding all output) to |
|
| 74 | * allow one to load a set of custom definitions (if this file isn't |
|
| 75 | * found, it isn't loaded). Use the "-nodefaults" option to disable |
|
| 76 | * this feature.</dd> |
|
| 77 | * |
|
| 78 | * </dl> |
|
| 79 | * |
|
| 80 | * @version $Revision: 1.1.1.1 $ |
|
| 81 | * |
|
| 82 | * @since 1.0 |
|
| 83 | * |
|
| 84 | * @author $Author: pkb $ |
|
| 85 | * |
|
| 86 | * @see #run */ |
|
| 87 | //---------------------------------------------------------------- |
|
| 88 | ||
| 89 | public class At extends CommandLineUtility { |
|
| 90 | ||
| 91 | //---------------------------------------------------------------- |
|
| 92 | /** Initializes object with an array of command line arguments. |
|
| 93 | * |
|
| 94 | * <p>This constructor initializes the object with an array of |
|
| 95 | * command line arguments. Once constructed one, can use the {@link |
|
| 96 | * #run} method to cause the interpreter to run. |
|
| 97 | * |
|
| 98 | * @param args |
|
| 99 | * |
|
| 100 | * Array of command line arguments (typically the what the {@link |
|
| 101 | * #main} method would be passed at startup). |
|
| 102 | * |
|
| 103 | * @since 1.0 |
|
| 104 | * |
|
| 105 | * @see #run */ |
|
| 106 | //---------------------------------------------------------------- |
|
| 107 | ||
| 108 | public At(String[] args) { |
|
| 109 | 0 | super(args); |
| 110 | ||
| 111 | 0 | setLineSeparator(null); |
| 112 | ||
| 113 | 0 | AtMacros am = new AtMacros(); |
| 114 | ||
| 115 | //---------------------------------------------------------------- |
|
| 116 | // See if any -Dmacro=val values on command line |
|
| 117 | //---------------------------------------------------------------- |
|
| 118 | ||
| 119 | 0 | for (int i = 0; i < args.length; i++) { |
| 120 | 0 | String a = args[i]; |
| 121 | 0 | if ((a.length() > 2) && a.startsWith("-D")) { |
| 122 | 0 | int epos = a.indexOf('='); |
| 123 | 0 | if (epos < 0) { |
| 124 | 0 | am.addMacro(a.substring(2),""); |
| 125 | 0 | } |
| 126 | else { |
|
| 127 | 0 | String mname = a.substring(2,epos); |
| 128 | 0 | String mval = a.substring(epos+1); |
| 129 | 0 | am.addMacro(mname,mval); |
| 130 | } |
|
| 131 | } |
|
| 132 | } |
|
| 133 | ||
| 134 | 0 | setAtMacros(am); |
| 135 | 0 | } |
| 136 | ||
| 137 | ||
| 138 | //---------------------------------------------------------------- |
|
| 139 | /** Holds the string used to separate lines on the current platform. |
|
| 140 | * |
|
| 141 | * @serial |
|
| 142 | * |
|
| 143 | * @since 1.0 */ |
|
| 144 | //---------------------------------------------------------------- |
|
| 145 | ||
| 146 | private String _LineSeparator; |
|
| 147 | ||
| 148 | ||
| 149 | //---------------------------------------------------------------- |
|
| 150 | /** Set the string used to separate lines on the current platform. |
|
| 151 | * |
|
| 152 | * @param val |
|
| 153 | * |
|
| 154 | * New String value to assign - note, if you pass null, we will |
|
| 155 | * attempt to reset it based on the "line.separator" system |
|
| 156 | * property. |
|
| 157 | * |
|
| 158 | * @see #getLineSeparator */ |
|
| 159 | //---------------------------------------------------------------- |
|
| 160 | ||
| 161 | public void setLineSeparator(String val) { |
|
| 162 | 0 | if (val == null) { |
| 163 | 0 | val = System.getProperty("line.separator"); |
| 164 | 0 | if (val == null) val = "\n"; |
| 165 | } |
|
| 166 | 0 | _LineSeparator = val; |
| 167 | 0 | } |
| 168 | ||
| 169 | ||
| 170 | //---------------------------------------------------------------- |
|
| 171 | /** Get the string used to separate lines on the current platform. |
|
| 172 | * |
|
| 173 | * @return |
|
| 174 | * |
|
| 175 | * Current String value assigned. |
|
| 176 | * |
|
| 177 | * @see #setLineSeparator */ |
|
| 178 | //---------------------------------------------------------------- |
|
| 179 | ||
| 180 | public String getLineSeparator() { |
|
| 181 | 0 | return _LineSeparator; |
| 182 | } |
|
| 183 | ||
| 184 | ||
| 185 | //---------------------------------------------------------------- |
|
| 186 | /** Holds the "@macro" interpreter to use. |
|
| 187 | * |
|
| 188 | * @serial |
|
| 189 | * |
|
| 190 | * @since 1.0 */ |
|
| 191 | //---------------------------------------------------------------- |
|
| 192 | ||
| 193 | private AtMacros _AtMacros; |
|
| 194 | ||
| 195 | ||
| 196 | //---------------------------------------------------------------- |
|
| 197 | /** Process a set of well known user files. |
|
| 198 | * |
|
| 199 | * <p>This method will attempt to load definitions from file(s) in |
|
| 200 | * some well known (or expected locations). All files are optional |
|
| 201 | * (if not found nothing is done). Also, no output is produced while |
|
| 202 | * interpretting these files (they are purely for the purpose of |
|
| 203 | * adding standard definitions). |
|
| 204 | * |
|
| 205 | * <p>Refer to the {@link ConfigSource} class and in particular the |
|
| 206 | * {@link ConfigSource#getFile} method to see how the path to the |
|
| 207 | * default file is determined. |
|
| 208 | * |
|
| 209 | * @since 1.0 */ |
|
| 210 | //---------------------------------------------------------------- |
|
| 211 | ||
| 212 | public void loadDefaultDefinitions() { |
|
| 213 | 0 | File ifile = null; |
| 214 | 0 | InputReader in = null; |
| 215 | ||
| 216 | try { |
|
| 217 | 0 | ConfigSource cs = new ConfigSource(At.class); |
| 218 | 0 | ifile = cs.getFile(); |
| 219 | ||
| 220 | 0 | Interpreter amacs = getAtMacros(); |
| 221 | ||
| 222 | 0 | if (ifile.exists() && (amacs != null)) { |
| 223 | 0 | in = new InputReader(ifile); |
| 224 | 0 | amacs.interpret(new InputReader(ifile),new OutputNull()); |
| 225 | 0 | System.err.println("loaded file:"+ifile); |
| 226 | 0 | } |
| 227 | 0 | else System.err.println("didn't find file:"+ifile); |
| 228 | 0 | } catch (Exception e) { |
| 229 | 0 | Log.error("problem processing \""+in+"\"",e); |
| 230 | 0 | } |
| 231 | ||
| 232 | 0 | if (in != null) try { in.close(); } catch (IOException ioe) { } |
| 233 | ||
| 234 | 0 | } |
| 235 | ||
| 236 | ||
| 237 | //---------------------------------------------------------------- |
|
| 238 | /** Set the "@macro" interpreter to use. |
|
| 239 | * |
|
| 240 | * @param val |
|
| 241 | * |
|
| 242 | * New AtMacros value to assign. |
|
| 243 | * |
|
| 244 | * @see #getAtMacros */ |
|
| 245 | //---------------------------------------------------------------- |
|
| 246 | ||
| 247 | public void setAtMacros(AtMacros val) { |
|
| 248 | 0 | if (val != null) { |
| 249 | 0 | _AtMacros = val; |
| 250 | 0 | _AtMacros.addMacros(this); |
| 251 | } |
|
| 252 | 0 | } |
| 253 | ||
| 254 | ||
| 255 | //---------------------------------------------------------------- |
|
| 256 | /** Get the "@macro" interpreter to use. |
|
| 257 | * |
|
| 258 | * @return |
|
| 259 | * |
|
| 260 | * Current AtMacros value assigned. |
|
| 261 | * |
|
| 262 | * @see #setAtMacros */ |
|
| 263 | //---------------------------------------------------------------- |
|
| 264 | ||
| 265 | public AtMacros getAtMacros() { |
|
| 266 | 0 | return _AtMacros; |
| 267 | } |
|
| 268 | ||
| 269 | ||
| 270 | //---------------------------------------------------------------- |
|
| 271 | /** Runs the interpreter reading from the input source and writing |
|
| 272 | * the output. |
|
| 273 | * |
|
| 274 | * This method interprets the contents of the input file and |
|
| 275 | * produces the resulting ASCII output file. By default, the |
|
| 276 | * standard input will be used for input, and the standard output |
|
| 277 | * will be used for output. However, one can adjust these via |
|
| 278 | * command line arguments or the methods of the {@link |
|
| 279 | * CommandLineUtility parent} class. |
|
| 280 | * |
|
| 281 | * @since 1.0 */ |
|
| 282 | //---------------------------------------------------------------- |
|
| 283 | ||
| 284 | public void run() { |
|
| 285 | ||
| 286 | 0 | OutputWriter o = null; |
| 287 | ||
| 288 | try { |
|
| 289 | 0 | AtMacros interpreter = getAtMacros(); |
| 290 | // interpreter.addMacro("pkb_email","paul@mekwin.com"); |
|
| 291 | // interpreter.addMacro("pkb","Paul Blankenbaker "+ |
|
| 292 | // "(@email(@pkb_email))"); |
|
| 293 | ||
| 294 | 0 | o = new OutputWriter(getOutputStream()); |
| 295 | // Input isb = new Input("@define(paul,@pkb)Hello \"@paul\"!\n\n"); |
|
| 296 | // interpreter.interpret(isb,o); |
|
| 297 | ||
| 298 | 0 | if (!getBoolean("nodefaults",Boolean.FALSE).booleanValue()) { |
| 299 | 0 | loadDefaultDefinitions(); |
| 300 | } |
|
| 301 | ||
| 302 | 0 | interpreter.interpret(new InputReader(getInputStream()),o); |
| 303 | ||
| 304 | 0 | } catch (Exception e) { |
| 305 | 0 | e.printStackTrace(); |
| 306 | } finally { |
|
| 307 | 0 | if (o != null) try { o.close(); } catch (Throwable t) { } |
| 308 | 0 | } |
| 309 | 0 | } |
| 310 | ||
| 311 | ||
| 312 | //---------------------------------------------------------------- |
|
| 313 | /** @param(N) macro - get parameter value. |
|
| 314 | * |
|
| 315 | * This macro is typically used in the definition of run time macros |
|
| 316 | * (in the VAL parameter of "@define(NAME,VAL)". It allows a user |
|
| 317 | * defined macro (run time defined) to reference the parameter |
|
| 318 | * passed to its invocation. Take a look at the following: |
|
| 319 | * |
|
| 320 | * <pre> |
|
| 321 | * @define(email,"<a href=\"mailto:@param(0)\">@param(0)</a>") |
|
| 322 | * @email("@("paul@mekwin.com")") |
|
| 323 | * </pre> |
|
| 324 | * |
|
| 325 | * <p>The above defines a new run time macro "@email", the new |
|
| 326 | * "@email" macro allows the user to pass an argument which is |
|
| 327 | * subsitutes in two places. This provides a means to make some |
|
| 328 | * pretty powerful run time macros. |
|
| 329 | * |
|
| 330 | * @param out |
|
| 331 | * |
|
| 332 | * The {@link Output output device} to write the results of |
|
| 333 | * processing the argument to. |
|
| 334 | * |
|
| 335 | * @param args |
|
| 336 | * |
|
| 337 | * A {@link Vector vector} of arguments which were passed to the macro. |
|
| 338 | * |
|
| 339 | * @throws IOException |
|
| 340 | * |
|
| 341 | * If there is a problem writing to the {@link Output output device} |
|
| 342 | * |
|
| 343 | * @throws InterpretException |
|
| 344 | * |
|
| 345 | * If a problem is encountered interpretting the arguments passed. |
|
| 346 | * |
|
| 347 | * @since 1.0 */ |
|
| 348 | //---------------------------------------------------------------- |
|
| 349 | ||
| 350 | public void param(Output out, Vector args) |
|
| 351 | throws IOException, InterpretException { |
|
| 352 | ||
| 353 | 0 | if ((args != null) && (args.size() >= 1)) { |
| 354 | 0 | Object o = args.elementAt(0); |
| 355 | 0 | int idx = -1; |
| 356 | try { |
|
| 357 | 0 | idx = Integer.parseInt(_AtMacros.interpretCheck(o.toString())); |
| 358 | 0 | } catch (Throwable t) { |
| 359 | 0 | throw new InterpretException("@param("+o+") - "+t.getMessage()); |
| 360 | 0 | } |
| 361 | ||
| 362 | 0 | out.write(_AtMacros.getParameter(idx)); |
| 363 | } |
|
| 364 | 0 | } |
| 365 | ||
| 366 | ||
| 367 | //---------------------------------------------------------------- |
|
| 368 | /** @quote(TEXT) macro - output text verbatim. |
|
| 369 | * |
|
| 370 | * This macro is invoked in the form "@quote(TEXT)". This macro only |
|
| 371 | * looks at the first argument (additional arguments are |
|
| 372 | * ignored). The text of the first argument is written verbatim to |
|
| 373 | * the output device. This allows one to output macro names. For |
|
| 374 | * example: <b>@quote("@quote(TEXT)")</b> would result in |
|
| 375 | * <b>@quote(TEXT)</b> in the output stream. |
|
| 376 | * |
|
| 377 | * @param out |
|
| 378 | * |
|
| 379 | * The {@link Output output device} to write the results of |
|
| 380 | * processing the argument to. |
|
| 381 | * |
|
| 382 | * @param args |
|
| 383 | * |
|
| 384 | * A {@link Vector vector} of arguments which were passed to the macro. |
|
| 385 | * |
|
| 386 | * @throws IOException |
|
| 387 | * |
|
| 388 | * If there is a problem writing to the {@link Output output device} |
|
| 389 | * |
|
| 390 | * @throws InterpretException |
|
| 391 | * |
|
| 392 | * If a problem is encountered interpretting the arguments passed. |
|
| 393 | * |
|
| 394 | * @since 1.0 */ |
|
| 395 | //---------------------------------------------------------------- |
|
| 396 | ||
| 397 | public void quote(Output out, Vector args) |
|
| 398 | throws IOException, InterpretException { |
|
| 399 | ||
| 400 | 0 | if ((args != null) && (args.size() >= 1)) { |
| 401 | 0 | Object o = args.elementAt(0); |
| 402 | 0 | if (o != null) out.write(o.toString()); |
| 403 | } |
|
| 404 | 0 | } |
| 405 | ||
| 406 | ||
| 407 | //---------------------------------------------------------------- |
|
| 408 | /** @now() macro - dumps current time. |
|
| 409 | * |
|
| 410 | * This macro is invoked in the form "@now()". This macro has no |
|
| 411 | * arguments (currently) and simply dumps the current time in the |
|
| 412 | * default date format of the JVM. |
|
| 413 | * |
|
| 414 | * @param out |
|
| 415 | * |
|
| 416 | * The {@link Output output device} to write the results of |
|
| 417 | * processing the argument to. |
|
| 418 | * |
|
| 419 | * @param args |
|
| 420 | * |
|
| 421 | * A {@link Vector vector} of arguments which were passed to the macro. |
|
| 422 | * |
|
| 423 | * @throws IOException |
|
| 424 | * |
|
| 425 | * If there is a problem writing to the {@link Output output device} |
|
| 426 | * |
|
| 427 | * @throws InterpretException |
|
| 428 | * |
|
| 429 | * If a problem is encountered interpretting the arguments passed. |
|
| 430 | * |
|
| 431 | * @since 1.0 */ |
|
| 432 | //---------------------------------------------------------------- |
|
| 433 | ||
| 434 | public void now(Output out, Vector args) |
|
| 435 | throws IOException, InterpretException { |
|
| 436 | ||
| 437 | 0 | out.write(getDateFormat().format(new Date())); |
| 438 | 0 | } |
| 439 | ||
| 440 | ||
| 441 | //---------------------------------------------------------------- |
|
| 442 | /** @define(NAME,VAL[,OPT]) macro - define a new macro. |
|
| 443 | * |
|
| 444 | * This macro is invoked in the form |
|
| 445 | * "@define(NAME,VAL[,OPT])". This macro is used to define new |
|
| 446 | * text replacement macros. The first argument NAME is the name of |
|
| 447 | * the new macro to define (do not include the leading "@" |
|
| 448 | * sign). The second argument VAL is the text which is to be |
|
| 449 | * subsituted. The third arguments allows for some specialized |
|
| 450 | * options during the definition. For example: |
|
| 451 | * |
|
| 452 | * <pre> |
|
| 453 | * @define(pkb_email,"@quote("paul@mekwin.com")") |
|
| 454 | * </pre> |
|
| 455 | * |
|
| 456 | * <p>After interpretting the above, one could then use |
|
| 457 | * "@pkb_email()" in the document and have "paul@mekwin.com" |
|
| 458 | * appear. It should be noted, that the "VAL" area can contain |
|
| 459 | * references to other macros. For example: |
|
| 460 | * |
|
| 461 | * <pre> |
|
| 462 | * @define(pkb,"Paul Blankenbaker (@pkb_email)") |
|
| 463 | * </pre> |
|
| 464 | * |
|
| 465 | * <p>There are two important concepts to understand with the |
|
| 466 | * above. One is that the @pkb macro just defined contains a |
|
| 467 | * reference to another macro. This is handled properly and the |
|
| 468 | * contained @pkb_email reference will be expanded each time the |
|
| 469 | * @pkb macro is used. The second concept is that the expansion |
|
| 470 | * occurs at the time the @pkb macro is used, not at the time it is |
|
| 471 | * defined. In other words, if someone changed the definition of the |
|
| 472 | * @pkb_email macro, then it would affect subsequent invocations of |
|
| 473 | * the @pkb macro. |
|
| 474 | * |
|
| 475 | * <p>The third parameter to this macro is optional, and can be |
|
| 476 | * extremely useful in some circumstances. The third parameter can |
|
| 477 | * be one of the following: |
|
| 478 | * |
|
| 479 | * <dl> |
|
| 480 | * |
|
| 481 | * <dt><b>ifnew</b></dt><dd>The "ifnew" option means that the |
|
| 482 | * definition should only be accepted if a definition does not |
|
| 483 | * already exist. This can be a very handy way to provide default |
|
| 484 | * values.</dd> |
|
| 485 | * |
|
| 486 | * <dt><b>now</b></dt><dd>The "now" option means that the value |
|
| 487 | * should be interpretted immediately (right now). This can be more |
|
| 488 | * efficient and prevents future changes from having affects.</dd> |
|
| 489 | * |
|
| 490 | * </dl> |
|
| 491 | * |
|
| 492 | * <p>To get an idea of how these behave, try running the the |
|
| 493 | * following through to see what comes out: |
|
| 494 | * |
|
| 495 | * <pre> |
|
| 496 | * @define("name","Joe Schmoe") |
|
| 497 | * @define("phone","333-333-3333") |
|
| 498 | * @define("pname","@name @phone") |
|
| 499 | * @define("nname","@name @phone","now") |
|
| 500 | * @define("phone","444-444-4444") |
|
| 501 | * @define("phone","555-555-5555","ifnew") |
|
| 502 | * @quote("@pname=")@pname |
|
| 503 | * @quote("@nname=")@nname |
|
| 504 | * </pre> |
|
| 505 | * |
|
| 506 | * @param out |
|
| 507 | * |
|
| 508 | * The {@link Output output device} to write the results of |
|
| 509 | * processing the argument to. |
|
| 510 | * |
|
| 511 | * @param args |
|
| 512 | * |
|
| 513 | * A {@link Vector vector} of arguments which were passed to the macro. |
|
| 514 | * |
|
| 515 | * @throws IOException |
|
| 516 | * |
|
| 517 | * If there is a problem writing to the {@link Output output device} |
|
| 518 | * |
|
| 519 | * @throws InterpretException |
|
| 520 | * |
|
| 521 | * If a problem is encountered interpretting the arguments passed. |
|
| 522 | * |
|
| 523 | * @since 1.0 */ |
|
| 524 | //---------------------------------------------------------------- |
|
| 525 | ||
| 526 | public void define(Output out, Vector args) |
|
| 527 | throws IOException, InterpretException { |
|
| 528 | ||
| 529 | 0 | if ((args != null) && (args.size() >= 2)) { |
| 530 | 0 | Object n = args.elementAt(0); |
| 531 | 0 | Object v = args.elementAt(1); |
| 532 | 0 | if ((n != null) && (v != null)) { |
| 533 | 0 | String name = n.toString(); |
| 534 | 0 | String val = v.toString(); |
| 535 | ||
| 536 | // see if any special options specified |
|
| 537 | 0 | if (args.size() > 2) { |
| 538 | 0 | Object op = args.elementAt(2); |
| 539 | 0 | String opStr = null; |
| 540 | 0 | if (op != null) opStr = op.toString(); |
| 541 | ||
| 542 | 0 | if (opStr != null) { |
| 543 | // "now" option requires us to evaluate now |
|
| 544 | 0 | if (opStr.equals("now")) { val = _AtMacros.interpret(val); } |
| 545 | // "ifnew" option means to skip |
|
| 546 | // definition if already defined |
|
| 547 | 0 | else if (opStr.equals("ifnew")) { |
| 548 | 0 | if (_AtMacros.getMacro(name) != null) return; |
| 549 | } |
|
| 550 | } |
|
| 551 | } |
|
| 552 | 0 | _AtMacros.addMacro(name,val); |
| 553 | } |
|
| 554 | } |
|
| 555 | 0 | } |
| 556 | ||
| 557 | ||
| 558 | //---------------------------------------------------------------- |
|
| 559 | /** @definition(NAME) macro - fetch definition of a macro. |
|
| 560 | * |
|
| 561 | * This macro is mainly used for debugging purposes, it returns the |
|
| 562 | * current definition of a macro. You pass the NAME of the macro |
|
| 563 | * (without the leading "@" symbol) which you want to retrieve the |
|
| 564 | * definition for. The current definition of the macro is returned |
|
| 565 | * as a text string. If the macro was created with the |
|
| 566 | * "@define(NAME,VAL)" macro, then the returned text will be |
|
| 567 | * "VAL". If the macro is a built-in macro (such as |
|
| 568 | * "@definition(NAME)", then the returned value will be the name of |
|
| 569 | * the Java class/method used to handle the macro. |
|
| 570 | * |
|
| 571 | * @param out |
|
| 572 | * |
|
| 573 | * The {@link Output output device} to write the results of |
|
| 574 | * processing the argument to. |
|
| 575 | * |
|
| 576 | * @param args |
|
| 577 | * |
|
| 578 | * A {@link Vector vector} of arguments which were passed to the macro. |
|
| 579 | * |
|
| 580 | * @throws IOException |
|
| 581 | * |
|
| 582 | * If there is a problem writing to the {@link Output output device} |
|
| 583 | * |
|
| 584 | * @throws InterpretException |
|
| 585 | * |
|
| 586 | * If a problem is encountered interpretting the arguments passed. |
|
| 587 | * |
|
| 588 | * @since 1.0 */ |
|
| 589 | //---------------------------------------------------------------- |
|
| 590 | ||
| 591 | public void definition(Output out, Vector args) |
|
| 592 | throws IOException, InterpretException { |
|
| 593 | ||
| 594 | 0 | if ((args != null) && (args.size() >= 1)) { |
| 595 | 0 | Object n = args.elementAt(0); |
| 596 | 0 | if (n != null) { |
| 597 | 0 | Object o = _AtMacros.getMacro(n.toString()); |
| 598 | 0 | out.write(o); |
| 599 | } |
|
| 600 | } |
|
| 601 | 0 | } |
| 602 | ||
| 603 | ||
| 604 | //---------------------------------------------------------------- |
|
| 605 | /** @htmlEscape(TEXT) - escape special HTML characters '<', '>' and '&'. |
|
| 606 | * |
|
| 607 | * <p>This should probably be relocated to a special HTML version of |
|
| 608 | * the {@link At At} class. However, I needed something that would |
|
| 609 | * translate '<' into "<", '>' into ">" and '&' into "&" |
|
| 610 | * so that HTML examples would appear as the expected when viewed by |
|
| 611 | * a browser. |
|
| 612 | * |
|
| 613 | * <p>This macro simply replaces HTML special characters, with the |
|
| 614 | * HTML escape codes. |
|
| 615 | * |
|
| 616 | * @param out |
|
| 617 | * |
|
| 618 | * The {@link Output output device} to write the results of |
|
| 619 | * processing the argument to. |
|
| 620 | * |
|
| 621 | * @param args |
|
| 622 | * |
|
| 623 | * A {@link Vector vector} of arguments which were passed to the macro. |
|
| 624 | * |
|
| 625 | * @throws IOException |
|
| 626 | * |
|
| 627 | * If there is a problem writing to the {@link Output output device} |
|
| 628 | * |
|
| 629 | * @throws InterpretException |
|
| 630 | * |
|
| 631 | * If a problem is encountered interpretting the arguments passed. |
|
| 632 | * |
|
| 633 | * @since 1.0 */ |
|
| 634 | //---------------------------------------------------------------- |
|
| 635 | ||
| 636 | public void htmlEscape(Output out, Vector args) |
|
| 637 | throws IOException, InterpretException { |
|
| 638 | ||
| 639 | // exit if nothing to do |
|
| 640 | 0 | if ((args == null) || (args.size() != 1)) return; |
| 641 | ||
| 642 | // see if there is anything to do |
|
| 643 | 0 | Object f = args.elementAt(0); |
| 644 | 0 | if (f == null) return; |
| 645 | ||
| 646 | 0 | String text = _AtMacros.interpretCheck(f.toString()); |
| 647 | ||
| 648 | 0 | if ((text == null) || (text.length() == 0)) return; |
| 649 | ||
| 650 | 0 | int tlen = text.length(); |
| 651 | ||
| 652 | // now, replace special HTML |
|
| 653 | // characters with their escape codes |
|
| 654 | 0 | StringBuffer sb = new StringBuffer(tlen*2); |
| 655 | ||
| 656 | 0 | for (int i = 0; i < tlen; i++) { |
| 657 | 0 | char c = text.charAt(i); |
| 658 | 0 | if (c == '<') sb.append("<"); |
| 659 | 0 | else if (c == '&') sb.append("&"); |
| 660 | 0 | else sb.append(c); |
| 661 | } |
|
| 662 | ||
| 663 | 0 | out.write(sb); |
| 664 | ||
| 665 | 0 | } |
| 666 | ||
| 667 | ||
| 668 | //---------------------------------------------------------------- |
|
| 669 | /** @dumpDefinitions() macro - dump definition of all macros. |
|
| 670 | * |
|
| 671 | * <p>This macro is mainly used for debugging purposes. It dumps the |
|
| 672 | * definition of ALL defined macros. |
|
| 673 | * |
|
| 674 | * <p>NOTE: You may optionally pass a single argument to this |
|
| 675 | * method. If passed, the argument will be expanded for each |
|
| 676 | * definition in our macro dictionary. The following macros will be |
|
| 677 | * available: |
|
| 678 | * |
|
| 679 | * <dl> |
|
| 680 | * |
|
| 681 | * <dt>@dumpDefName()</dt><dd>The name of the macro the |
|
| 682 | * definition refers to. |
|
| 683 | * |
|
| 684 | * <dt>@dumpDefValue()</dt><dd>The string value of the macro |
|
| 685 | * (this may be the name of the Java method used to evaluate |
|
| 686 | * it.</dd> |
|
| 687 | * |
|
| 688 | * </dl> |
|
| 689 | * |
|
| 690 | * <p>Here is an example which produces the same results as the |
|
| 691 | * default output: |
|
| 692 | * |
|
| 693 | * <pre> |
|
| 694 | * @dumpDefinitions("@dumpDefName()=@dumpDefValue() |
|
| 695 | * ") |
|
| 696 | * </pre> |
|
| 697 | * |
|
| 698 | * <p>Here's an example which provides a little fancier output in |
|
| 699 | * HTML: |
|
| 700 | * |
|
| 701 | * <pre> |
|
| 702 | * @dumpDefinitions("<h2>@quote(@)@dumpDefName()</h2> |
|
| 703 | * <pre> |
|
| 704 | * @htmlEscape("@dumpDefValue()") |
|
| 705 | * </pre> |
|
| 706 | * ") |
|
| 707 | * </pre> |
|
| 708 | * |
|
| 709 | * @param out |
|
| 710 | * |
|
| 711 | * The {@link Output output device} to write the results of |
|
| 712 | * processing the argument to. |
|
| 713 | * |
|
| 714 | * @param args |
|
| 715 | * |
|
| 716 | * A {@link Vector vector} of arguments which were passed to the macro. |
|
| 717 | * |
|
| 718 | * @throws IOException |
|
| 719 | * |
|
| 720 | * If there is a problem writing to the {@link Output output device} |
|
| 721 | * |
|
| 722 | * @throws InterpretException |
|
| 723 | * |
|
| 724 | * If a problem is encountered interpretting the arguments passed. |
|
| 725 | * |
|
| 726 | * @since 1.0 */ |
|
| 727 | //---------------------------------------------------------------- |
|
| 728 | ||
| 729 | public void dumpDefinitions(Output out, Vector args) |
|
| 730 | throws IOException, InterpretException { |
|
| 731 | ||
| 732 | // default dump ouput |
|
| 733 | 0 | String format = "@dumpDefName()=@dumpDefValue()"+_LineSeparator; |
| 734 | // see if user overrode format |
|
| 735 | 0 | if ((args != null) && (args.size() > 0)) { |
| 736 | 0 | Object o = args.elementAt(0); |
| 737 | 0 | if (o != null) format = o.toString(); |
| 738 | } |
|
| 739 | // get and sort macro names that are defined |
|
| 740 | 0 | Vector allNames = new Vector(500); |
| 741 | 0 | Enumeration keys = _AtMacros.getMacroNames(); |
| 742 | 0 | while (keys.hasMoreElements()) { |
| 743 | 0 | String name = keys.nextElement().toString(); |
| 744 | 0 | allNames.addElement(name); |
| 745 | 0 | } |
| 746 | ||
| 747 | 0 | String[] mnames = new String[allNames.size()]; |
| 748 | 0 | for (int i = 0; i < mnames.length; i++) { |
| 749 | 0 | mnames[i] = (String) allNames.elementAt(i); |
| 750 | } |
|
| 751 | 0 | Arrays.sort(mnames,new com.ccg.util.CompareStrings()); |
| 752 | ||
| 753 | 0 | class Verbatim implements MacroHandler { |
| 754 | String _Text; |
|
| 755 | public void process(Output ov, Vector av) |
|
| 756 | throws IOException, InterpretException { |
|
| 757 | 0 | ov.write(_Text); |
| 758 | 0 | } |
| 759 | } |
|
| 760 | ||
| 761 | 0 | Verbatim v = new Verbatim(); |
| 762 | 0 | _AtMacros.addMacro("dumpDefValue",v); |
| 763 | ||
| 764 | // now, go process each macro definition |
|
| 765 | 0 | for (int i = 0; i < mnames.length; i++) { |
| 766 | 0 | _AtMacros.addMacro("dumpDefName",mnames[i]); |
| 767 | 0 | v._Text = _AtMacros.getMacro(mnames[i]).toString(); |
| 768 | 0 | out.write(_AtMacros.interpretCheck(format)); |
| 769 | } |
|
| 770 | ||
| 771 | // reset to blank definitions - not |
|
| 772 | // sure if we need to do this |
|
| 773 | // _AtMacros.addMacro("dumpDefName",null); |
|
| 774 | // _AtMacros.addMacro("dumpDefValue",null); |
|
| 775 | /* |
|
| 776 | String beforeAll = null; |
|
| 777 | // String beforeEach = ""+_AtMacros.getStartMacroChar()+"define(\""; |
|
| 778 | // String betweenEach = "\",\""; |
|
| 779 | // String afterEach = "\")\n"; |
|
| 780 | String beforeEach = null; |
|
| 781 | String betweenEach = "="; |
|
| 782 | String afterEach = "\n"; |
|
| 783 | String afterAll = null; |
|
| 784 | ||
| 785 | Enumeration keys = _AtMacros.getMacroNames(); |
|
| 786 | while (keys.hasMoreElements()) { |
|
| 787 | String name = keys.nextElement().toString(); |
|
| 788 | Object o = _AtMacros.getMacro(name); |
|
| 789 | ||
| 790 | if (beforeEach != null) out.write(beforeEach); |
|
| 791 | out.write(name); |
|
| 792 | out.write(betweenEach); |
|
| 793 | out.write(o); |
|
| 794 | out.write(afterEach); |
|
| 795 | } |
|
| 796 | */ |
|
| 797 | 0 | } |
| 798 | ||
| 799 | ||
| 800 | //---------------------------------------------------------------- |
|
| 801 | /** @loadTSV(NAME,SOURCE) load a tab separated table. |
|
| 802 | * |
|
| 803 | * <p>This macro is used to load the definition of a tab separated |
|
| 804 | * table. It doesn't actually read the contents of the database |
|
| 805 | * immediately, instead it defines a new macro named "NAME" and |
|
| 806 | * associates a SOURCE (typically a file or URL) where we should |
|
| 807 | * fetch the data from. |
|
| 808 | * |
|
| 809 | * <p>When you want to insert the data of the table into your |
|
| 810 | * output, you then use the "@NAME(FORMAT)" macro to read each line |
|
| 811 | * from the table and FORMAT the output of the table. |
|
| 812 | * |
|
| 813 | * <p>For example, if one created a table named {@link |
|
| 814 | * <a href=doc-files/phone.tsv>phone.tsv</a>} like the following: |
|
| 815 | * |
|
| 816 | <pre> |
|
| 817 | Last First Phone |
|
| 818 | Blankenbaker Paul 555-555-5555 |
|
| 819 | Brown Megan 555-555-5555 |
|
| 820 | </pre> |
|
| 821 | * |
|
| 822 | * <p>And you used the following macros: |
|
| 823 | * |
|
| 824 | <pre> |
|
| 825 | @loadTSV("phoneTable","{@link <a href=doc-files/phone.tsv>phone.tsv</a>}") |
|
| 826 | @phoneTable("@param(1),@param(0),@param(2)\n") |
|
| 827 | </pre> |
|
| 828 | * |
|
| 829 | * <p>This will result in the output of one blank line followed by a |
|
| 830 | * comma seaparated list of just the data fields. This is shown below: |
|
| 831 | * |
|
| 832 | <pre> |
|
| 833 | ||
| 834 | Paul,Blankenbaker,555-555-5555 |
|
| 835 | Megan,Brown,555-555-5555 |
|
| 836 | </pre> |
|
| 837 | * |
|
| 838 | * <p>If you are producing HTML, you can use the table formatting |
|
| 839 | * tags to nicely format your table data. |
|
| 840 | * |
|
| 841 | * @param out |
|
| 842 | * |
|
| 843 | * The {@link Output output device} to write the results of |
|
| 844 | * processing the argument to. |
|
| 845 | * |
|
| 846 | * @param args |
|
| 847 | * |
|
| 848 | * A {@link Vector vector} of arguments which were passed to the macro. |
|
| 849 | * |
|
| 850 | * @throws IOException |
|
| 851 | * |
|
| 852 | * If there is a problem writing to the {@link Output output device} |
|
| 853 | * |
|
| 854 | * @throws InterpretException |
|
| 855 | * |
|
| 856 | * If a problem is encountered interpretting the arguments passed. |
|
| 857 | * |
|
| 858 | * @since 1.0 */ |
|
| 859 | //---------------------------------------------------------------- |
|
| 860 | ||
| 861 | public void loadTSV(Output out, Vector args) |
|
| 862 | throws IOException, InterpretException { |
|
| 863 | ||
| 864 | 0 | if (args.size() < 2) { |
| 865 | 0 | throw new InterpretException("@loadTSV(NAME,SOURCE) requires "+ |
| 866 | "two arguments."); |
|
| 867 | } |
|
| 868 | ||
| 869 | 0 | String name = args.elementAt(0).toString(); |
| 870 | 0 | String source = args.elementAt(1).toString(); |
| 871 | ||
| 872 | 0 | if ((name == null) || (source == null) || |
| 873 | (name.length() == 0) || (source.length() == 0)) { |
|
| 874 | 0 | throw new InterpretException("null argument passed to "+ |
| 875 | "@loadTSV(NAME,SOURCE)"); |
|
| 876 | } |
|
| 877 | ||
| 878 | 0 | _AtMacros.addMacro(name,new TableInsert(_AtMacros,name,source)); |
| 879 | 0 | } |
| 880 | ||
| 881 | ||
| 882 | //---------------------------------------------------------------- |
|
| 883 | /** @include(SOURCE,[IGNERR],[NOOUT]) insert and process other file(s). |
|
| 884 | * |
|
| 885 | * <p>This macro is used to load and process the contents of another |
|
| 886 | * file. Currently the full or relative path to the source must be |
|
| 887 | * specified (in the future, path searching may be added). |
|
| 888 | * |
|
| 889 | * <p>For example, to include the file |
|
| 890 | * "/opt/include/atmacros/companies.atmacros", one could use the |
|
| 891 | * following command: |
|
| 892 | * |
|
| 893 | <pre> |
|
| 894 | @include("/etc/hosts") |
|
| 895 | </pre> |
|
| 896 | * |
|
| 897 | * <p>The second parameter IGNERR is optional. It may be set to |
|
| 898 | * either "true" or "false" (only first letter is checked). If |
|
| 899 | * omitted, it defaults to a value of "false". When set to "true", |
|
| 900 | * then no error will be thrown if the file is not found. If set to |
|
| 901 | * "false" (or omitted), then an error will be thrown if the desired |
|
| 902 | * SOURCE could not be found. |
|
| 903 | * |
|
| 904 | * <p>The third parameter DISOUT is optional. It may be set to |
|
| 905 | * either "true" or "false" (only first letter is checked). If |
|
| 906 | * omitted, it defaults to a value of "false". When set to "true", |
|
| 907 | * then no output will be produced while interpretting the file |
|
| 908 | * included (this allows one to load definition files). When set to |
|
| 909 | * "false" (or omitted), any output produced as a result of |
|
| 910 | * interpretting the file will be written to the current output |
|
| 911 | * device. |
|
| 912 | * |
|
| 913 | * <p>When using this directive to include definition files, it is |
|
| 914 | * often handy to set the DISOUT value to "true" to disable any |
|
| 915 | * output as a result of interpretting the definition file (this |
|
| 916 | * allows one to enter comments in their definition files). |
|
| 917 | * |
|
| 918 | * @param out |
|
| 919 | * |
|
| 920 | * The {@link Output output device} to write the results of |
|
| 921 | * processing the argument to. |
|
| 922 | * |
|
| 923 | * @param args |
|
| 924 | * |
|
| 925 | * A {@link Vector vector} of arguments which were passed to the macro. |
|
| 926 | * |
|
| 927 | * @throws IOException |
|
| 928 | * |
|
| 929 | * If there is a problem writing to the {@link Output output device} |
|
| 930 | * |
|
| 931 | * @throws InterpretException |
|
| 932 | * |
|
| 933 | * If a problem is encountered interpretting the arguments passed. |
|
| 934 | * |
|
| 935 | * @since 1.0 */ |
|
| 936 | //---------------------------------------------------------------- |
|
| 937 | ||
| 938 | public void include(Output out, Vector args) |
|
| 939 | throws IOException, InterpretException { |
|
| 940 | ||
| 941 | 0 | int argc = args.size(); |
| 942 | 0 | if (argc < 1) return; |
| 943 | ||
| 944 | 0 | String source = _AtMacros.interpretCheck(args.elementAt(0).toString()); |
| 945 | ||
| 946 | try { |
|
| 947 | // get source file to process |
|
| 948 | 0 | Reader in = com.ccg.io.Utility.getReader(source); |
| 949 | ||
| 950 | 0 | if (argc > 2) { // turn off output if necessary |
| 951 | 0 | String disout = _AtMacros.interpretCheck(args.elementAt(2).toString()); |
| 952 | 0 | if (disout.length() > 0 && |
| 953 | (Character.toLowerCase(disout.charAt(0)) == 't')) { |
|
| 954 | 0 | out = new OutputNull(); |
| 955 | } |
|
| 956 | } |
|
| 957 | ||
| 958 | // go interpret the contents of the file |
|
| 959 | 0 | _AtMacros.interpretCheck(new InputReader(in),out); |
| 960 | ||
| 961 | 0 | } catch (IOException ioe) { |
| 962 | 0 | if (argc > 1) { |
| 963 | 0 | String cont = _AtMacros.interpretCheck(args.elementAt(1).toString()); |
| 964 | 0 | if (cont.length() > 0 && |
| 965 | Character.toLowerCase(cont.charAt(0)) == 't') { |
|
| 966 | 0 | Log.warning("Warning: source \""+source+ |
| 967 | "\" skipped:"+ioe.toString()); |
|
| 968 | 0 | ioe = null; // OK to continue |
| 969 | } |
|
| 970 | } |
|
| 971 | 0 | if (ioe != null) throw ioe; |
| 972 | 0 | } |
| 973 | ||
| 974 | 0 | } |
| 975 | ||
| 976 | ||
| 977 | //---------------------------------------------------------------- |
|
| 978 | /** @copyToDir(MATCH0,MATCH1,&02e;&02e;&02e;,DIR) copy one or |
|
| 979 | * more files to directory. |
|
| 980 | * |
|
| 981 | * <p>This macro is used to copy 0 or more existing files to a |
|
| 982 | * output directory. If the directory doesn't exist, it will be |
|
| 983 | * created. You may use the "*" as a wildcard in each of the file |
|
| 984 | * name strings to match more than one file. |
|
| 985 | * |
|
| 986 | * <p>For example, to copy the ".at" and "*.properties" files from |
|
| 987 | * the "/etc/macros" directory to the "/home/user/etc/macros" |
|
| 988 | * directory, one could use the following: |
|
| 989 | * |
|
| 990 | <pre> |
|
| 991 | @defnow("sdir","/etc/macros") |
|
| 992 | @copyToDir("@sdir()/*.at","@sdir()/*.properties","/home/user/etc/macros") |
|
| 993 | </pre> |
|
| 994 | * |
|
| 995 | * @param out |
|
| 996 | * |
|
| 997 | * The {@link Output output device} to write the results of |
|
| 998 | * processing the argument to. |
|
| 999 | * |
|
| 1000 | * @param args |
|
| 1001 | * |
|
| 1002 | * A {@link Vector vector} of arguments which were passed to the macro. |
|
| 1003 | * |
|
| 1004 | * @throws IOException |
|
| 1005 | * |
|
| 1006 | * If there is a problem writing to the {@link Output output device} |
|
| 1007 | * |
|
| 1008 | * @throws InterpretException |
|
| 1009 | * |
|
| 1010 | * If a problem is encountered interpretting the arguments passed. |
|
| 1011 | * |
|
| 1012 | * @since 1.0 */ |
|
| 1013 | //---------------------------------------------------------------- |
|
| 1014 | ||
| 1015 | public void copyToDir(Output out, Vector args) |
|
| 1016 | throws IOException, InterpretException { |
|
| 1017 | ||
| 1018 | 0 | int argc = args.size(); |
| 1019 | 0 | if (argc < 2) return; // must have at least two arguments |
| 1020 | ||
| 1021 | 0 | argc--; // last argument is the output directory |
| 1022 | ||
| 1023 | // get output directory |
|
| 1024 | 0 | String dstStr = _AtMacros.interpretCheck(args.elementAt(argc).toString()); |
| 1025 | ||
| 1026 | 0 | File dst = new File(FileName.fixSlashes(dstStr)); |
| 1027 | // try to create directory - if it |
|
| 1028 | // doesn't exist |
|
| 1029 | 0 | if (!dst.isDirectory()) { |
| 1030 | 0 | dst.mkdirs(); |
| 1031 | 0 | if (!dst.isDirectory()) { |
| 1032 | 0 | throw new IOException("unable to create directory \""+dst+"\""); |
| 1033 | } |
|
| 1034 | } |
|
| 1035 | ||
| 1036 | 0 | PrintWriterString pws = PrintWriterString.create(); |
| 1037 | ||
| 1038 | // now, process each of the wild-card |
|
| 1039 | // file name strings |
|
| 1040 | 0 | for (int i = 0; i < argc; i++) { |
| 1041 | 0 | String match = _AtMacros.interpretCheck(args.elementAt(i).toString()); |
| 1042 | 0 | String[] list = FilenameFilterWild.list(FileName.fixSlashes(match)); |
| 1043 | 0 | if (list != null) for (int j = 0; j < list.length; j++) { |
| 1044 | 0 | File src = new File(list[j]); |
| 1045 | // only copy existing normal files |
|
| 1046 | 0 | if (src.exists() && src.isFile()) { |
| 1047 | 0 | File ofile = new File(dst,src.getName()); |
| 1048 | ||
| 1049 | 0 | pws.print("Copy:"); |
| 1050 | 0 | pws.print(src); |
| 1051 | 0 | pws.print(" to:"); |
| 1052 | 0 | pws.println(dst); |
| 1053 | 0 | Copy.fileToFile(src,ofile); |
| 1054 | 0 | } |
| 1055 | 0 | else if (Debug.ENABLED && Debug.isEnabledFor(3)) { |
| 1056 | 0 | pws.print("Skip:"); |
| 1057 | 0 | pws.println(src); |
| 1058 | } |
|
| 1059 | } |
|
| 1060 | } |
|
| 1061 | ||
| 1062 | 0 | out.write(pws); |
| 1063 | 0 | } |
| 1064 | ||
| 1065 | ||
| 1066 | //---------------------------------------------------------------- |
|
| 1067 | /** @atCopyToDir(MATCH0,MATCH1,&02e;&02e;&02e;,DIR) copy AND |
|
| 1068 | * interpret one or more files to directory. |
|
| 1069 | * |
|
| 1070 | * <p>This macro is used to copy 0 or more existing files to a |
|
| 1071 | * output directory. If the directory doesn't exist, it will be |
|
| 1072 | * created. You may use the "*" as a wildcard in each of the file |
|
| 1073 | * name strings to match more than one file. |
|
| 1074 | * |
|
| 1075 | * <p>There is a HUGE difference between this command and the |
|
| 1076 | * "@copyToDir". This command interprets each file that it |
|
| 1077 | * copies and evaluates any "@macros" which it contains. This |
|
| 1078 | * can be a VERY useful way to install HTML documents to their final |
|
| 1079 | * location and do some subsitutions during the installation process. |
|
| 1080 | * |
|
| 1081 | * <p>It should be noted that any definitions (or redefinitions) |
|
| 1082 | * made by the files processed WILL AFFECT all subsequent files |
|
| 1083 | * processed (I may add a version of this macro which saves/restores |
|
| 1084 | * the macros for each file processed). |
|
| 1085 | * |
|
| 1086 | * <p>To see the power of this function, take a look at the {@link |
|
| 1087 | * <a href=doc-files/atcopy.atmacros>atcopy.atmacros</a>} |
|
| 1088 | * "script". It does the following: |
|
| 1089 | * |
|
| 1090 | * <ul> |
|
| 1091 | * |
|
| 1092 | * <li>Makes some of its own definitions.</li> |
|
| 1093 | * |
|
| 1094 | * <li>Loads a set of definitions ({@link |
|
| 1095 | * <a href=doc-files/htmlmemo.atmacros>htmlmemo.atmacros</a>}).</li> |
|
| 1096 | * |
|
| 1097 | * <li>Then copies a set of HTML documents (both {@link |
|
| 1098 | * <a href=doc-files/memo1.html>memo1.html</a>} and {@link |
|
| 1099 | * <a href=doc-files/memo2.html>memo2.html</a>}) using the defined macros. |
|
| 1100 | * |
|
| 1101 | * </ul> |
|
| 1102 | * |
|
| 1103 | * <p>If you have the source code installed such that the "ccg" top |
|
| 1104 | * level directory can be found under the "$COMHOME" environment |
|
| 1105 | * variable, you should be able to try this out via: |
|
| 1106 | * |
|
| 1107 | * <pre> |
|
| 1108 | * java {@link At com.ccg.macros.At} -Dcomhome=$COMHOME -Dhtmlroot=$HOME/public_html \ |
|
| 1109 | * -in {@link <a href=doc-files/atcopy.atmacros>$COMHOME/ccg/macros/doc-files/atcopy.atmacros</a>} |
|
| 1110 | * </pre> |
|
| 1111 | * |
|
| 1112 | * @param out |
|
| 1113 | * |
|
| 1114 | * The {@link Output output device} to write the results of |
|
| 1115 | * processing the argument to. |
|
| 1116 | * |
|
| 1117 | * @param args |
|
| 1118 | * |
|
| 1119 | * A {@link Vector vector} of arguments which were passed to the macro. |
|
| 1120 | * |
|
| 1121 | * @throws IOException |
|
| 1122 | * |
|
| 1123 | * If there is a problem writing to the {@link Output output device} |
|
| 1124 | * |
|
| 1125 | * @throws InterpretException |
|
| 1126 | * |
|
| 1127 | * If a problem is encountered interpretting the arguments passed. |
|
| 1128 | * |
|
| 1129 | * @since 1.0 */ |
|
| 1130 | //---------------------------------------------------------------- |
|
| 1131 | ||
| 1132 | public void atCopyToDir(Output out, Vector args) |
|
| 1133 | throws IOException, InterpretException { |
|
| 1134 | ||
| 1135 | 0 | int argc = args.size(); |
| 1136 | 0 | if (argc < 2) return; // must have at least two arguments |
| 1137 | ||
| 1138 | 0 | argc--; // last argument is the output directory |
| 1139 | ||
| 1140 | // get output directory |
|
| 1141 | 0 | String dstStr = _AtMacros.interpretCheck(args.elementAt(argc).toString()); |
| 1142 | ||
| 1143 | 0 | File dst = new File(FileName.fixSlashes(dstStr)); |
| 1144 | // try to create directory - if it |
|
| 1145 | // doesn't exist |
|
| 1146 | 0 | if (!dst.isDirectory()) { |
| 1147 | 0 | dst.mkdirs(); |
| 1148 | 0 | if (!dst.isDirectory()) { |
| 1149 | 0 | throw new IOException("unable to create directory \""+dst+"\""); |
| 1150 | } |
|
| 1151 | } |
|
| 1152 | ||
| 1153 | 0 | PrintWriterString pws = PrintWriterString.create(); |
| 1154 | ||
| 1155 | // now, process each of the wild-card |
|
| 1156 | // file name strings |
|
| 1157 | 0 | for (int i = 0; i < argc; i++) { |
| 1158 | 0 | String match = _AtMacros.interpretCheck(args.elementAt(i).toString()); |
| 1159 | 0 | String[] list = FilenameFilterWild.list(FileName.fixSlashes(match)); |
| 1160 | 0 | if (list != null) for (int j = 0; j < list.length; j++) { |
| 1161 | 0 | File src = new File(list[j]); |
| 1162 | // only copy existing normal files |
|
| 1163 | 0 | if (src.exists() && src.isFile()) { |
| 1164 | 0 | File ofile = new File(dst,src.getName()); |
| 1165 | ||
| 1166 | 0 | pws.print("Interpret:"); |
| 1167 | 0 | pws.print(src); |
| 1168 | 0 | pws.print(" to:"); |
| 1169 | 0 | pws.println(dst); |
| 1170 | ||
| 1171 | 0 | OutputWriter ow = new OutputWriter(ofile); |
| 1172 | 0 | InputReader ir = new InputReader(src); |
| 1173 | ||
| 1174 | // and copy/interpret the files |
|
| 1175 | 0 | getAtMacros().interpret(ir,ow); |
| 1176 | 0 | ow.close(); // don't forget to close (to flush out data) |
| 1177 | 0 | } |
| 1178 | 0 | else if (Debug.ENABLED && Debug.isEnabledFor(3)) { |
| 1179 | 0 | pws.print("Skip:"); |
| 1180 | 0 | pws.println(src); |
| 1181 | } |
|
| 1182 | } |
|
| 1183 | } |
|
| 1184 | ||
| 1185 | 0 | out.write(pws); |
| 1186 | 0 | } |
| 1187 | ||
| 1188 | } |
|
| 1189 | ||
| 1190 |