com.adobe.xfa.formcalc.BuiltinString Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
The newest version!
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2007 Adobe Systems Incorporated All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of
* Adobe Systems Incorporated and its suppliers, if any. The intellectual and
* technical concepts contained herein are proprietary to Adobe Systems
* Incorporated and its suppliers and may be covered by U.S. and Foreign
* Patents, patents in process, and are protected by trade secret or copyright
* law. Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained from
* Adobe Systems Incorporated.
*/
package com.adobe.xfa.formcalc;
import com.adobe.xfa.ut.LcData;
import com.adobe.xfa.ut.PictureFmt;
import com.adobe.xfa.ut.ExFull;
import java.util.UUID;
/**
* This class defines static methods to implement
* the FormCalc string calculations.
*
* S T R I N G F U N C T I O N S
* at, concat, format, left, len, lower, ltrim, parse, replace, right,
* rtrim, space, str, stuff, substr, upper, wordnum.
*
* @author Mike P. Tardif
*
* @exclude from published api.
*/
final class BuiltinString {
/*
* Disallow instances of this class.
*/
private BuiltinString() {
}
static final long QUINTILLION = 1000000000000000000L;
/*
* At
* This function returns the (1-based origin) index of one given string
* in another given string.
*/
static void At(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 2);
Builtins.maxArgs(nArgs, 2);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve arguments.
//
String s1 = oParser.getString(oArgSym[0]);
String s2 = oParser.getString(oArgSym[1]);
int nUniIndex = 0;
int nChrIndex = s1.indexOf(s2);
if (nChrIndex >= 0) {
for (int i = 0; i < s1.length(); i++) {
if (nChrIndex == i)
break;
if (s1.codePointAt(i) <= 0xFFFF)
nUniIndex++;
}
nUniIndex++;
}
oRetSym = new CalcSymbol((double) nUniIndex);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Concat
* This function returns the concatenation of a set of non-null strings.
*/
static void Concat(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check for error-valued and return-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
try {
//
// ensure not all args are null.
//
Builtins.limitAllNullArgs(oParser, oArgSym);
//
// compute the concatenation of the given set.
//
oRetSym = computeCat(oParser, nArgs, oArgSym);
} catch (CalcException e) {
//
// all args are null -- return null.
//
oRetSym = new CalcSymbol();
}
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
static CalcSymbol computeCat(CalcParser oParser, int nArgs, CalcSymbol[] oArgSym) {
CalcSymbol oRetSym = null;
try {
StringBuilder s = new StringBuilder();
for (int i = 0; i < nArgs; i++) {
switch (oArgSym[i].getType()) {
case CalcSymbol.TypeAccessor:
CalcSymbol[] oSym = oParser.moScriptHost.getItemValue(
oArgSym[i].getName(), oArgSym[i].getObjValues());
CalcSymbol pCat = computeCat(oParser, oSym.length, oSym);
s.append(oParser.getString(pCat));
for (int j = oSym.length - 1; j >= 0; j--)
CalcSymbol.delete(oSym[j], oParser);
break;
case CalcSymbol.TypeNull:
break;
default:
s.append(oParser.getString(oArgSym[i]));
break;
}
}
oRetSym = new CalcSymbol(s.toString());
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
return oRetSym;
}
/*
* Format
* This function returns the result of formatting the specified
* source string according to the specified picture.
*/
static void Format(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 2);
Builtins.maxArgs(nArgs, 2);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, 1, oArgSym);
//
// retrieve and normalize arguments. Reversed args to conform
// to published spec -- Mike Tardif, Nov 2003.
//
String m = oParser.getString(oArgSym[0]);
String s = oParser.getString(oArgSym[1]);
//
// Watson 2322019: Runtime error when we assigned the null value to a form variable
// When pArgSym[1].getType() is jfCalcTypeAccessor or jfCalcTypeReference, need to
// get the actual type that is accessed or referred to.
if (oParser.getActualType(oArgSym[1]).getType() == CalcSymbol.TypeNull)
s = null;
String l = oParser.msLocaleName;
//
// optional data sources still not implemented.
//
StringBuilder sFormat = new StringBuilder();
try {
PictureFmt oPict = new PictureFmt(l);
oPict.format(s, m, sFormat);
} catch (ExFull oException) {
String sErr = oException.toString();
if (sErr != null) {
throw new CalcException(sErr);
}
else {
throw new CalcException();
}
}
oRetSym = new CalcSymbol(sFormat.toString());
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Left
* This function returns the specified number of characters from
* the left of the given string.
*/
static void Left(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 2);
Builtins.maxArgs(nArgs, 2);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve and normalize arguments.
//
String s = oParser.getString(oArgSym[0]);
int n = (int) oParser.getNumeric(oArgSym[1]);
if (n < 0)
n = 0;
if (n > s.length())
n = s.length();
int nUniChar = 0;
int i = 0;
for (; i < s.length(); i++) {
if (nUniChar == n)
break;
if (s.codePointAt(i) <= 0xFFFF)
nUniChar++;
}
//
// compute left most part of string.
//
oRetSym = new CalcSymbol(s.substring(0, i));
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Len
* This function returns the length of the given string.
*/
static void Len(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 1);
Builtins.maxArgs(nArgs, 1);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// compute the length of string.
//
String s = oParser.getString(oArgSym[0]);
int nUniChar = 0;
for (int i = 0; i < s.length(); i++) {
if (s.codePointAt(i) <= 0xFFFF)
nUniChar++;
}
oRetSym = new CalcSymbol(nUniChar);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Lower
* This function returns the lowercase equivalent of the given string.
*/
static void Lower(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 1);
Builtins.maxArgs(nArgs, 2);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve arguments, ignoring locale.
//
StringBuilder s = new StringBuilder(oParser.getString(oArgSym[0]));
//
// twiddle bits of all ASCII, Latin1
// and fullwidth lowercase letters.
//
for (int i = 0; i < s.length(); i++) {
char n = s.charAt(i);
if ('\u0040' < n && n < '\u005b')
s.setCharAt(i, (char) (n | 0x20));
else if ('\u00bf' < n && n < '\u00d7'
|| '\u00d7' < n && n < '\u00df')
s.setCharAt(i, (char) (n | 0x20));
else if ('\uff20' < n && n < '\uff3b') {
s.setCharAt(i, (char) ((n & ~0x20) | 0x40));
}
}
oRetSym = new CalcSymbol(s.toString());
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Ltrim
* This function returns the given string with all
* left most spaces trimmed.
*/
static void Ltrim(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 1);
Builtins.maxArgs(nArgs, 1);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve arguments, and trim left-most spaces.
//
String s = oParser.getString(oArgSym[0]);
int i = 0;
while (i < s.length()) {
int cUni = s.codePointAt(i);
if (! Character.isWhitespace(cUni) && ! Character.isSpaceChar(cUni))
break;
i += (cUni <= 0xFFFF) ? 1 : 2;
}
oRetSym = new CalcSymbol(s.substring(i));
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* NumFmt
* This function returns a format number string,
* given a number format style.
*
*/
static void NumFmt(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 0);
Builtins.maxArgs(nArgs, 2);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve and normalize arguments.
//
int n = (nArgs > 0) ? (int) oParser.getNumeric(oArgSym[0]) : 0;
String l = (nArgs > 1) ? oParser.getString(oArgSym[1])
: oParser.msLocaleName;
//
// get the locale's date format style.
//
LcData data = new LcData(l);
int o = LcData.withPrecision(~0) | LcData.WITH_GROUPINGS;
oRetSym = new CalcSymbol(data.getNumberFormat(n, o));
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Parse
* This function returns the result of parsing the specified
* source string according to the specified picture.
*/
static void Parse(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 2);
Builtins.maxArgs(nArgs, 2);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, 1, oArgSym);
//
// retrieve and normalize arguments. Reversed args to conform
// to published spec -- Mike Tardif, Nov 2003.
//
String m = oParser.getString(oArgSym[0]);
String s = oParser.getString(oArgSym[1]);
if (oArgSym[1].getType() == CalcSymbol.TypeNull)
s = null;
String l = oParser.msLocaleName;
String sFormat = null;
try {
PictureFmt oPict = new PictureFmt(l);
sFormat = oPict.parse(s, m, null);
} catch (ExFull oException) {
String sErr = oException.toString();
if (sErr != null) {
throw new CalcException(sErr);
}
else {
throw new CalcException();
}
}
if (sFormat == null)
oRetSym = new CalcSymbol();
else
oRetSym = new CalcSymbol(sFormat);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Replace
* This function returns the given string with all occurences
* of the old string replaced with the new string.
*/
static void Replace(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 2);
Builtins.maxArgs(nArgs, 3);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, 2, oArgSym);
//
// retrieve arguments.
//
String str = oParser.getString(oArgSym[0]);
String old = oParser.getString(oArgSym[1]);
String rep = (nArgs > 2) ? oParser.getString(oArgSym[2]) : "";
StringBuilder s = new StringBuilder();
//
// replace all occurrences of the old string with the replacement
// string in the given string argument.
//
//CL#729807 - jfString.ReplaceAll is now called in C++ code
// but not changing String.replaceAll here as that considers cutStr
// as a regex - this CL was a performance related one - functionality
// wise it was (and remains) same ..
int k = old.length();
if (k > 0 && ! old.equals(rep)) {
int i = 0;
while ((i = str.indexOf(old)) >= 0) {
s.append(str, 0, i);
s.append(rep);
i += k;
str = str.substring(i);
}
}
s.append(str);
//CL#729807
oRetSym = new CalcSymbol(s.toString());
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Right
* This function returns the specified number of characters from
* the right of the given string.
*/
static void Right(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 2);
Builtins.maxArgs(nArgs, 2);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve and normalize arguments.
//
String s = oParser.getString(oArgSym[0]);
int n = (int) oParser.getNumeric(oArgSym[1]);
int len = s.length();
if (n > len)
n = len;
if (n < 0)
n = 0;
//
// compute right most part of string.
//
int nUniChar = 0;
int i = 0;
for (; i < s.length(); i++) {
if (s.codePointAt(i) <= 0xFFFF)
nUniChar++;
}
if (n > nUniChar)
n = nUniChar;
n = nUniChar - n;
nUniChar = 0;
for (i = 0; i < s.length(); i++) {
if (nUniChar == n)
break;
if (s.codePointAt(i) <= 0xFFFF)
nUniChar++;
}
oRetSym = new CalcSymbol(s.substring(i));
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Rtrim
* This function returns the given string with all
* right most spaces trimmed.
*/
static void Rtrim(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 1);
Builtins.maxArgs(nArgs, 1);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve arguments, and trim right-most Unicode spaces.
//
String s = oParser.getString(oArgSym[0]);
for (int i = 0; i < s.length(); ) {
int k = i;
int cUni = s.codePointAt(i);
i += (cUni <= 0xFFFF) ? 1 : 2;
if (Character.isWhitespace(cUni) || Character.isSpaceChar(cUni)) {
int m = i;
for (int j = i; j < s.length(); m = j) {
cUni = s.codePointAt(j);
j += (cUni <= 0xFFFF) ? 1 : 2;
if (Character.isWhitespace(cUni))
continue;
if (Character.isSpaceChar(cUni))
continue;
break;
}
if (m == s.length())
s = s.substring(0, k); // trim it
else
i = m; // advance to next non whitespace.
}
}
oRetSym = new CalcSymbol(s);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Space
* This function returns a string with the given number of spaces.
*/
static void Space(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 1);
Builtins.maxArgs(nArgs, 1);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve arguments, and generate string of spaces.
//
int n = (int) oParser.getNumeric(oArgSym[0]);
if (n < 0)
n = 0;
char[] s = new char[n];
for (int i = 0; i < n; i++)
s[i] = ' ';
oRetSym = new CalcSymbol(new String(s));
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* format a double value n as a string of width w and precision p.
*/
private static String dblToStr(double n, int w, int p) {
StringBuilder oStr = new StringBuilder(FormCalcUtil.dblToStr(n, p));
FormCalcUtil.trimRadix(oStr);
FormCalcUtil.trimSign(oStr);
//
// Blank-pad or null-out result to given width.
//
int k = oStr.length();
if (k < w) {
for (int i = k; i < w; i++)
oStr.insert(0, ' ');
}
else if (k > w) {
oStr.setLength(0);
for (int i = 0; i < w; i++)
oStr.append('*');
}
return oStr.toString();
}
/*
* Str
* This function converts a given number to a string of given width
* and precision.
*/
static void Str(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 1);
Builtins.maxArgs(nArgs, 3);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve and normalize arguments.
//
double n = oParser.getNumeric(oArgSym[0]);
int w = (nArgs > 1) ? (int) oParser.getNumeric(oArgSym[1]) : 10;
int p = (nArgs > 2) ? (int) oParser.getNumeric(oArgSym[2]) : 0;
if (w < 0)
w = 10;
if (p < 0)
p = 0;
//
// format number to string.
//
oRetSym = new CalcSymbol(dblToStr(n, w, p));
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Stuff
* This function replaces a number of characters in a given string
* with a given insert.
*/
static void Stuff(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 3);
Builtins.maxArgs(nArgs, 4);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, 3, oArgSym);
//
// retrieve and normalize arguments.
//
String str = oParser.getString(oArgSym[0]);
int loc = (int) oParser.getNumeric(oArgSym[1]);
loc--;
if (loc < 0)
loc = 0;
int len = (int) oParser.getNumeric(oArgSym[2]);
if (len < 0)
len = 0;
String ins = (nArgs > 3) ? oParser.getString(oArgSym[3]) : "";
//
// compute the starting index.
//
int nUniChar = 0;
int k = 0;
int i;
for (i = 0; i < str.length(); ) {
if (nUniChar++ >= loc)
break;
k = i;
i += (str.codePointAt(i) <= 0xFFFF) ? 1 : 2;
}
loc = (nUniChar <= loc) ? k : i;
//
// compute the length.
//
nUniChar = 0;
for (i = loc; i < str.length(); ) {
if (nUniChar++ >= len)
break;
i += (str.codePointAt(i) <= 0xFFFF) ? 1 : 2;
}
len = i - loc;
//
// stuff everything:
// the left part is str.substring(0, loc).
// the middle part is all of ins.
// the right part, if any, is str.substring(loc + len).
//
StringBuilder s = new StringBuilder(str.substring(0, loc));
s.append(ins);
if (loc + len < str.length())
s.append(str, loc + len, str.length());
oRetSym = new CalcSymbol(s.toString());
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Substr
* This function returns a substring of the given string.
*/
static void Substr(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 3);
Builtins.maxArgs(nArgs, 3);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve and normalize arguments.
//
String str = oParser.getString(oArgSym[0]);
int loc = (int) oParser.getNumeric(oArgSym[1]);
loc--;
if (loc < 0)
loc = 0;
int len = (int) oParser.getNumeric(oArgSym[2]);
if (len < 0)
len = 0;
//
// compute the starting index.
//
int nUniChar = 0;
int k = 0;
int i;
for (i = 0; i < str.length(); ) {
if (nUniChar++ >= loc)
break;
k = i;
i += (str.codePointAt(i) <= 0xFFFF) ? 1 : 2;
}
loc = (nUniChar <= loc) ? k : i;
//
// compute the length.
//
nUniChar = 0;
for (i = loc; i < str.length();) {
if (nUniChar++ >= len)
break;
i += (str.codePointAt(i) <= 0xFFFF) ? 1 : 2;
}
//
// extract the substring.
//
str = str.substring(loc, i);
oRetSym = new CalcSymbol(str);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Uuid
* This function returns uuid.
*
*/
static void Uuid(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 0);
Builtins.maxArgs(nArgs, 1);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve arguments, ignoring locale.
//
int n = (nArgs > 0) ? (int) oParser.getNumeric(oArgSym[0]) : 0;
//
// Generate the uuid string.
//
String u = UUID.randomUUID().toString();
//
// Swallow all dashes if requested.
//
if (n == 0) {
StringBuilder sUuid = new StringBuilder(u);
int nDash = sUuid.indexOf("-");
while (nDash >= 0) {
sUuid.deleteCharAt(nDash);
nDash = sUuid.lastIndexOf("-");
}
u = sUuid.toString();
}
oRetSym = new CalcSymbol(u);
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
/*
* Upper
* This function returns the uppercase equivalent of the given string.
*
*/
static void Upper(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 1);
Builtins.maxArgs(nArgs, 2);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve arguments, ignoring locale.
//
StringBuilder s = new StringBuilder(oParser.getString(oArgSym[0]));
//
// twiddle bits of all ASCII, LATIN1 and fullwidth uppercase letters
// while remembering that we are operating on UTF-8 data!
//
for (int i = 0; i < s.length(); i++) {
char n = s.charAt(i);
if ('\u0060' < n && n < '\u007b')
s.setCharAt(i, (char) (n & ~0x20));
else if ('\u00df' < n && n < '\u00f7'
|| '\u00f7' < n && n < '\u00ff')
s.setCharAt(i, (char) (n & ~0x20));
else if ('\uff40' < n && n < '\uff5b') {
s.setCharAt(i, (char) ((n & ~0x40) | 0x20));
}
}
oRetSym = new CalcSymbol(s.toString());
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
//
// The names of the numbers: 0-9
//
static final String Ones[] = {
"Zero", "One", "Two", "Three", "Four",
"Five", "Six", "Seven", "Eight", "Nine"
};
//
// The names of the numbers: 10-19
//
static final String Teens[] = {
"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen",
"Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"
};
//
// The names of the numbers: 0,10,20,...,90,100.
//
static final String Tens[] = {
"Zero", "Ten", "Twenty", "Thirty", "Forty",
"Fifty", "Sixty", "Seventy", "Eighty", "Ninety", "Hundred"
};
//
// The names of the numbers:
// 1000,1000000,1000000000,...,1000000000000000,1000000000000000000.
//
static final String Thousands[] = {
"Thousand", "Million", "Billion",
"Trillion", "Quadrillion", "Quintillion"
};
//
// The conjunction for the dollar and cent parts of name.
//
static final String Ands[] = {
"", "And " /* used by FF99 */
// "And ", "And " /* used by Filler4.x */
};
//
// The dollar name.
//
static final String Dollars[] = {
"Dollar"
};
//
// The cent name.
//
static final String Cents[] = {
"Cent"
};
//
// The character delimiter used after thousands names,
// e.g. one million, twenty thousand, three hundred thirty-six.
//
static final String Comma[] = {
"" /* used by FF99 */
// "," /* used by Filler4.x */
};
//
// The character delimiter used after teen names,
// e.g., thirty-six.
//
static final String Hyphen = "-";
//
// The character delimiter used after non-teen names,
// e.g., three hundred.
//
static final String Space = " ";
/*
* Convert number to a formatted word equivalent.
*
* Note: there is ABSOLUTELY no point in externalizing the following names
* to a resource file. The grammar that wordum uses is inherently English.
* There's no way, by simply localizing these name in French, for example,
* that you'll be able to get wordnum to generate "mille" instead of
* "un mille" as it would do, or "deux milles" instead of "deux mille",
* or even generate "soixante-onze" or "quatre-vingt-quinze".
* What is required is a mechanism to externalize the grammar. IBM's
* alphaWorks lab has done this; see
* http://www.alphaWorks.ibm.com/tech/rbnf
* This ought to convince everyone that this isn't a trivial exercise, and
* difficult to justify at this time. Better instead to localize all of
* wordnum on an has-needed basis.
*/
private static String wordnum(double n, int f) {
//
// If number is NaN or negative, then return string of asterisks (*).
//
if (Double.isNaN(n) || Double.isInfinite(n) || n < 0.) {
return "*********";
}
//
// If format is invalid, then assume format style 0.
//
if (f < 0 || 2 < f) {
f = 0;
}
//
// Round the number to two decimal places.
//
String sStr = FormCalcUtil.dblToStr(n, 2);
n = FormCalcUtil.strToDbl(sStr, false);
//
// Round off cents, independent of format.
//
long dollars = (long) n;
int cents = (int) ((n - (double) dollars) * 100. + .5);
if (cents > 100) {
dollars += 1;
cents -= 100;
}
//
// If preceding led to nonsense values Then its probably because
// we've reached numbers whose magnitude are beyond arithmetic
// resolution of architecture, so bail out.
//
if (cents > 100) {
return "*********";
}
StringBuilder s = new StringBuilder();
int thousands = Thousands.length;
for (long div = QUINTILLION; div > 0; div /= 1000) {
long number = (long) (dollars / div);
int hundreds = (int) (number / 100);
int tens = (int) ((number - hundreds * 100) / 10);
int ones = (int) (number - hundreds * 100 - tens * 10);
dollars -= number * div;
if (hundreds > 0) {
s.append(Ones[hundreds]);
s.append(Space);
s.append(Tens[10]);
s.append(Space);
if (tens > 0 || ones > 0)
s.append(Ands[0]);
}
if (tens > 0) {
s.append((tens == 1) ? Teens[ones] : Tens[tens]);
s.append((ones > 0 && tens != 1) ? Hyphen : Space);
}
if (ones > 0 && tens != 1) {
if (tens > 0 && ones > 0) {
// safe since Ones contains true literal constants
String o = Ones[ones];
s.append(Character.toLowerCase(o.charAt(0)));
s.append(o, 1, o.length());
}
else {
s.append(Ones[ones]);
}
s.append(Space);
}
thousands--;
if (thousands >= 0 && number > 0) {
s.append(Thousands[thousands]);
s.append(Comma[0]);
s.append(Space);
}
}
//
// If less than one then use zero.
//
if (n < 1.) {
s.append(Ones[0]);
s.append(Space);
}
//
// Factor in format:
// 0 => "One Hundred Twenty-three"
// 1 => "One Hundred Twenty-three Dollars"
// 2 => "One Hundred Twenty-three Dollars And Forty Cents"
//
if (f == 0) {
//
// Remove trailing space.
//
if (s.length() > 0) {
s.setLength(s.length() - Space.length());
}
}
else if (f == 1 || f == 2) {
//
// Append dollar CalcSymbol.
//
s.append(Dollars[0]);
if ((int) n != 1)
s.append('s');
//
// Append cents.
//
if (f == 2) {
s.append(Space);
s.append(Ands[1]);
int tens = (int) (cents / 10);
int ones = (int) (cents - tens * 10);
if (tens > 0) {
s.append((tens == 1) ? Teens[ones] : Tens[tens]);
}
if (tens != 1) {
if (tens > 0 && ones > 0) {
// safe since Ones contains true literal constants
String o = Ones[ones];
s.append(Hyphen);
s.append(Character.toLowerCase(o.charAt(1)));
s.append(o, 1, o.length());
}
else if (tens == 0) {
s.append(Ones[ones]);
}
}
s.append(Space);
s.append(Cents[0]);
if (cents != 1.)
s.append('s');
}
}
return s.toString();
}
static void WordNum(CalcParser oParser, CalcSymbol[] oArgSym) {
final int nArgs = oArgSym.length;
CalcSymbol oRetSym = null;
try {
//
// check the number of args vs the number required.
//
Builtins.minArgs(nArgs, 1);
Builtins.maxArgs(nArgs, 3);
//
// check for error-valued, return-valued and null-valued args.
//
Builtins.limitExceptionArgs(oArgSym);
Builtins.limitNullArgs(oParser, nArgs, oArgSym);
//
// retrieve and normalize arguments, ignoring locale.
//
String s = oParser.getString(oArgSym[0]).trim();
double n = FormCalcUtil.strToDbl(s, true);
int f = (nArgs > 1) ? (int) oParser.getNumeric(oArgSym[1]) : 0;
oRetSym = new CalcSymbol(wordnum(n, f));
} catch (CalcException e) {
oRetSym = e.getSymbol();
if (oRetSym.getType() != CalcSymbol.TypeNull)
oParser.mbInThrow = true;
}
//
// push the result on the stack.
//
oParser.mStack.push(oRetSym);
}
}