PageRenderTime 66ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main/java/com/extentech/formats/XLS/formulas/InformationCalculator.java

https://bitbucket.org/openxls/openxls
Java | 719 lines | 439 code | 26 blank | 254 comment | 149 complexity | 8d984351509e585cfa751c6fec407073 MD5 | raw file
  1. /*
  2. * --------- BEGIN COPYRIGHT NOTICE ---------
  3. * Copyright 2002-2012 Extentech Inc.
  4. * Copyright 2013 Infoteria America Corp.
  5. *
  6. * This file is part of OpenXLS.
  7. *
  8. * OpenXLS is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as
  10. * published by the Free Software Foundation, either version 3 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * OpenXLS is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with OpenXLS. If not, see
  20. * <http://www.gnu.org/licenses/>.
  21. * ---------- END COPYRIGHT NOTICE ----------
  22. */
  23. package com.extentech.formats.XLS.formulas;
  24. import java.text.DecimalFormat;
  25. import com.extentech.formats.XLS.BiffRec;
  26. import com.extentech.formats.XLS.CellNotFoundException;
  27. import com.extentech.formats.XLS.FormatConstants;
  28. import com.extentech.formats.XLS.FunctionNotSupportedException;
  29. import com.extentech.formats.XLS.Labelsst;
  30. import com.extentech.formats.XLS.WorkSheetNotFoundException;
  31. import com.extentech.formats.XLS.XLSRecord;
  32. import com.extentech.toolkit.Logger;
  33. /*
  34. InformationCalculator is a collection of static methods that operate
  35. as the Microsoft Excel function calls do.
  36. All methods are called with an array of ptg's, which are then
  37. acted upon. A Ptg of the type that makes sense (ie boolean, number)
  38. is returned after each method.
  39. */
  40. public class InformationCalculator
  41. {
  42. /**
  43. *
  44. CELL
  45. Returns information about the formatting, location, or contents of a cell
  46. The CELL function returns information about the formatting, location, or contents of a cell.
  47. CELL(info_type, [reference])
  48. info_type Required. A text value that specifies what type of cell information you want to return. The following list shows the possible values of the info_type argument and the corresponding results.info_type Returns
  49. "address" Reference of the first cell in reference, as text.
  50. "col" Column number of the cell in reference.
  51. "color" The value 1 if the cell is formatted in color for negative values; otherwise returns 0 (zero).
  52. "contents" Value of the upper-left cell in reference; not a formula.
  53. "filename" Filename (including full path) of the file that contains reference, as text. Returns empty text ("") if the worksheet that contains reference has not yet been saved.
  54. "format" Text value corresponding to the number format of the cell. The text values for the various formats are shown in the following table. Returns "-" at the end of the text value if the cell is formatted in color for negative values. Returns "()" at the end of the text value if the cell is formatted with parentheses for positive or all values.
  55. "parentheses" The value 1 if the cell is formatted with parentheses for positive or all values; otherwise returns 0.
  56. "prefix" Text value corresponding to the "label prefix" of the cell. Returns single quotation mark (') if the cell contains left-aligned text, double quotation mark (") if the cell contains right-aligned text, caret (^) if the cell contains centered text, backslash (\) if the cell contains fill-aligned text, and empty text ("") if the cell contains anything else.
  57. "protect" The value 0 if the cell is not locked; otherwise returns 1 if the cell is locked.
  58. "row" Row number of the cell in reference.
  59. "type" Text value corresponding to the type of data in the cell. Returns "b" for blank if the cell is empty, "l" for label if the cell contains a text constant, and "v" for value if the cell contains anything else.
  60. "width" Column width of the cell, rounded off to an integer. Each unit of column width is equal to the width of one character in the default font size.
  61. reference Optional. The cell that you want information about. If omitted, the information specified in the info_type argument is returned for the last cell that was changed. If the reference argument is a range of cells, the CELL function returns the information for only the upper left cell of the range.
  62. */
  63. protected static Ptg calcCell(Ptg[] operands)
  64. throws FunctionNotSupportedException {
  65. String type= operands[0].getValue().toString().toLowerCase();
  66. PtgRef ref= null;
  67. BiffRec cell= null;
  68. if (operands.length > 1) {
  69. ref= (PtgRef) operands[1];
  70. try {
  71. cell= ref.getParentRec().getWorkBook().getCell(ref.getLocationWithSheet());
  72. } catch (CellNotFoundException e) {
  73. try {
  74. String sh= null;
  75. try {
  76. sh= ref.getSheetName();
  77. } catch (WorkSheetNotFoundException we) {; }
  78. if (sh==null) sh= ref.getParentRec().getSheet().getSheetName();
  79. cell= ref.getParentRec().getWorkBook().getWorkSheetByName(sh).addValue(null, ref.getLocation());
  80. } catch (Exception ex) {
  81. return new PtgErr(PtgErr.ERROR_VALUE);
  82. }
  83. } catch (Exception e) {
  84. return new PtgErr(PtgErr.ERROR_VALUE);
  85. }
  86. // If ref param is omitted, the information specified in the info_type argument
  87. // is returned for the last cell that was changed
  88. } else if (!type.equals("filename"))// no ref was passed in and option is not "filename"
  89. // We cannot determine which is the "last cell" they are referencing;
  90. throw new FunctionNotSupportedException("Worsheet function CELL with no reference parameter is not supported");
  91. else // filename option can use any biffrec ...
  92. cell= operands[0].getParentRec();
  93. // at this point both ref (PtgRef) and r (BiffRec) should be valid
  94. try {
  95. if (type.equals("address")) {
  96. PtgRef newref= ref;
  97. newref.clearLocationCache();
  98. newref.fColRel= false; // make absolute
  99. newref.fRwRel= false;
  100. return new PtgStr(newref.getLocation());
  101. } else if (type.equals("col")) {
  102. return new PtgNumber(ref.getIntLocation()[1]+1);
  103. } else if (type.equals("color")) { // The value 1 if the cell is formatted in color for negative values; otherwise returns 0 (zero).
  104. String s= cell.getFormatPattern();
  105. if (s.indexOf(";[Red")>-1)
  106. return new PtgNumber(1);
  107. return new PtgNumber(0);
  108. } else if (type.equals("contents")) {// Value of the upper-left cell in reference; not a formula.
  109. return new PtgStr(cell.getStringVal());
  110. } else if (type.equals("filename")) {
  111. String f= cell.getWorkBook().getFileName();
  112. String sh= cell.getSheet().getSheetName();
  113. int i= f.lastIndexOf(java.io.File.separatorChar);
  114. f= f.substring(0, i+1)+ "[" + f.substring(i+1);
  115. f+= "]" + sh;
  116. return new PtgStr(f);
  117. } else if (type.equals("format")) { // Text value corresponding to the number format of the cell. The text values for the various formats are shown in the following table. Returns "-" at the end of the text value if the cell is formatted in color for negative values. Returns "()" at the end of the text value if the cell is formatted with parentheses for positive or all values.
  118. String s= cell.getFormatPattern();
  119. String ret= "G"; // default?
  120. if (s.equals("General") ||
  121. s.equals("# ?/?") ||
  122. s.equals("# ??/??")) {
  123. ret= "G";
  124. } else if (s.equals("0")) {
  125. ret= "F0";
  126. } else if (s.equals("#,##0")) {
  127. ret= ",0";
  128. } else if (s.equals("0.00")) {
  129. ret= "F2";
  130. } else if (s.equals("#,##0.00")) {
  131. ret= ", 2";
  132. } else if (s.equals("$#,##0_);($#,##0)")) {
  133. ret= "C0";
  134. } else if (s.equals("$#,##0_);[Red]($#,##0)")) {
  135. ret= "C0-";
  136. } else if (s.equals("$#,##0.00_);($#,##0.00)")) {
  137. ret= "C2";
  138. } else if (s.equals("$#,##0.00_);[Red]($#,##0.00)")) {
  139. ret= "C2-";
  140. } else if (s.equals("0%")) {
  141. ret= "P0";
  142. } else if (s.equals("0.00%")) {
  143. ret= "P2";
  144. } else if (s.equals("0.00E+00")) {
  145. ret= "S2";
  146. // m/d/yy or m/d/yy h:mm or mm/dd/yy "D4"
  147. } else if (s.equals("m/d/yy") ||
  148. s.equals("m/d/yy h:mm") ||
  149. s.equals("mm/dd/yy") ||
  150. s.equals("mm-dd-yy")) { // added last to accomodate Excel's regional short date setting (format #14)
  151. ret= "D4";
  152. } else if (s.equals("d-mmm-yy") ||
  153. s.equals("dd-mmm-yy")) {
  154. ret= "D1";
  155. } else if (s.equals("d-mmm") ||
  156. s.equals("dd-mmm")) {
  157. ret= "D2";
  158. } else if (s.equals("mmm-yy")) {
  159. ret= "D3";
  160. } else if (s.equals("mm/dd")) {
  161. ret= "D5";
  162. } else if (s.equals("h:mm AM/PM")) {
  163. ret= "D7";
  164. } else if (s.equals("h:mm:ss AM/PM")) {
  165. ret= "D6";
  166. } else if (s.equals("h:mm")) {
  167. ret= "D9";
  168. } else if (s.equals("h:mm:ss")) {
  169. ret= "D8";
  170. }
  171. return new PtgStr(ret);
  172. } else if (type.equals("parentheses")) {
  173. String s= cell.getFormatPattern();
  174. if (s.startsWith("("))
  175. return new PtgNumber(1);
  176. return new PtgNumber(0);
  177. } else if (type.equals("prefix")) {
  178. // TODO: THIS IS NOT CORRECT - EITHER INFORM USER OR ??
  179. // DOESN'T APPEAR TO MATCH EXCEL
  180. //Text value corresponding to the "label prefix" of the cell.
  181. // Returns single quotation mark (') if the cell contains left-aligned text, double quotation mark (") if the cell contains right-aligned text,
  182. // caret (^) if the cell contains centered text, backslash (\) if the cell contains fill-aligned text, and empty text ("") if the cell contains anything else.
  183. int al= cell.getXfRec().getHorizontalAlignment();
  184. if(al==FormatConstants.ALIGN_LEFT)
  185. return new PtgStr("'");
  186. if(al==FormatConstants.ALIGN_CENTER)
  187. return new PtgStr("^");
  188. if(al==FormatConstants.ALIGN_RIGHT)
  189. return new PtgStr("\"");
  190. if(al==FormatConstants.ALIGN_FILL)
  191. return new PtgStr("\\");
  192. return new PtgStr("");
  193. } else if (type.equals("protect")) {
  194. if (cell.getXfRec().isLocked())
  195. return new PtgNumber(1);
  196. return new PtgNumber(0);
  197. } else if (type.equals("row")) {
  198. return new PtgNumber(ref.getIntLocation()[0]+1);
  199. } else if (type.equals("type")) {
  200. //Text value corresponding to the type of data in the cell.
  201. // Returns "b" for blank if the cell is empty,
  202. //"l" for label if the cell contains a text constant, and
  203. // "v" for value if the cell contains anything else.
  204. if (((XLSRecord) cell).isBlank)
  205. return new PtgStr("b");
  206. if (cell instanceof Labelsst)
  207. return new PtgStr("l");
  208. return new PtgStr("v");
  209. } else if (type.equals("width")) {
  210. int n= 0;
  211. n= cell.getSheet().getColInfo(cell.getColNumber()).getColWidthInChars();
  212. return new PtgNumber(n);
  213. }
  214. } catch (Exception e) {
  215. Logger.logWarn("CELL: unable to calculate: " + e.toString());
  216. }
  217. return new PtgErr(PtgErr.ERROR_VALUE);
  218. }
  219. /**
  220. * ERROR.TYPE
  221. Returns a number corresponding to an error type
  222. If error_val is
  223. ERROR.TYPE returns
  224. #NULL! 1
  225. #DIV/0! 2
  226. #VALUE! 3
  227. #REF! 4
  228. #NAME? 5
  229. #NUM! 6
  230. #N/A 7
  231. Anything else #N/A
  232. */
  233. protected static Ptg calcErrorType(Ptg[] operands){
  234. Object o = operands[0].getValue();
  235. String s = o.toString();
  236. if (s.equalsIgnoreCase("#NULL!")) return new PtgInt(1);
  237. if (s.equalsIgnoreCase("#DIV/0!")) return new PtgInt(2);
  238. if (s.equalsIgnoreCase("#VALUE!")) return new PtgInt(3);
  239. if (s.equalsIgnoreCase("#REF!")) return new PtgInt(4);
  240. if (s.equalsIgnoreCase("#NAME?")) return new PtgInt(5);
  241. if (s.equalsIgnoreCase("#NUM!")) return new PtgInt(6);
  242. if (s.equalsIgnoreCase("#N/A")) return new PtgInt(7);
  243. return new PtgErr(PtgErr.ERROR_NA);
  244. }
  245. /**
  246. INFO
  247. Returns information about the current operating environment
  248. INFO(type_text)
  249. NOTE: Several options are incomplete:
  250. "osversion" -- only valid for Windows versions
  251. "system" -- only valid for Windows and Mac
  252. "release" -- incomplete
  253. "origin" -- does not return R1C1 format
  254. */
  255. protected static Ptg calcInfo(Ptg[] operands) {
  256. // validate
  257. if (operands==null || operands.length==0 || operands[0].getParentRec()==null)
  258. return new PtgErr(PtgErr.ERROR_VALUE);
  259. String type_text= operands[0].getString();
  260. String ret= "";
  261. if (type_text.equals("directory")) // Path of the current directory or folder
  262. return new PtgStr(System.getProperty("user.dir").toLowerCase() + "\\");
  263. else if (type_text.equals("numfile")) // number of active worksheets in the current workbook
  264. // TODO: what is correct definition of "Active Worksheets" - hidden state doesn't seem to affect"
  265. return new PtgNumber(operands[0].getParentRec().getWorkBook().getNumWorkSheets());
  266. else if (type_text.equals("origin")) { /* Returns the absolute cell reference of the top and leftmost
  267. cell visible in the window, based on the current scrolling
  268. position, as text prepended with "$A:".
  269. This value is intended for for Lotus 1-2-3 release 3.x compatibility.
  270. The actual value returned depends on the current reference
  271. style setting. Using D9 as an example, the return value would be:
  272. A1 reference style "$A:$D$9".
  273. R1C1 reference style "$A:R9C4"
  274. */
  275. // TODO: FINISH R1C1 reference style
  276. String cell= operands[0].getParentRec().getSheet().getWindow2().getTopLeftCell();
  277. for (int i= cell.length()-1; i>=0; i--) {
  278. if (!Character.isDigit(cell.charAt(i))) {
  279. cell= cell.substring(0, i+1) + "$" + cell.substring(i+1);
  280. break;
  281. }
  282. }
  283. cell="$A:$" + cell;
  284. return new PtgStr(cell);
  285. } else if (type_text.equals("osversion")){ //Current operating system version, as text.
  286. // see end of file for os info
  287. String osversion = System.getProperty("os.version");
  288. String n= System.getProperty("os.name"); // Windows Vista
  289. String os= "";
  290. // TODO: need a list of osversions to compare to! have know idea for mac, linux ...
  291. if (n.startsWith("Windows")) {
  292. double v= new Double(osversion);
  293. os= "Windows (32-bit) ";
  294. if (v>=5)
  295. os+="NT ";
  296. DecimalFormat df = new DecimalFormat("##.00");
  297. os+= df.format(v);
  298. } // otherwise have NO idea as cannot find any info on net
  299. else os += osversion;
  300. return new PtgStr(os);
  301. } else if (type_text.equals("recalc")) { //Current recalculation mode; returns "Automatic" or "Manual".
  302. if (operands[0].getParentRec().getWorkBook().getRecalculationMode()==0) // manual
  303. return new PtgStr("Manual");
  304. return new PtgStr("Automatic");
  305. }else if (type_text.equals("release")){ //Version of Microsoft Excel, as text.
  306. // TODO: Finish! 97= 8.0, 2000= 9.0, 2002 (XP)= 10.0, 2003= 11.0, 2007= 12.0
  307. Logger.logWarn("Worksheet Function INFO(\"release\") is not supported");
  308. return new PtgStr("");
  309. }else if (type_text.equals("system")) // Name of the operating environment: Macintosh = "mac" Windows = "pcdos"
  310. // TODO: linux? ****************
  311. if (System.getProperty("os.name").indexOf("Windows")>=0)
  312. return new PtgStr("pcdos");
  313. else
  314. return new PtgStr("mac");
  315. // In previous versions of Microsoft Office Excel, the "memavail", "memused", and "totmem" type_text values, returned memory information.
  316. // These type_text values are no longer supported and now return a #N/A error value.
  317. else if (type_text.equals("memavail") ||
  318. type_text.equals("memused") ||
  319. type_text.equals("totmem"))
  320. return new PtgErr(PtgErr.ERROR_NA);
  321. return new PtgErr(PtgErr.ERROR_VALUE);
  322. }
  323. /**
  324. * ISBLANK
  325. * ISBLANK determines if the cell referenced is blank, and returns
  326. * a boolean ptg based off that
  327. */
  328. protected static Ptg calcIsBlank(Ptg[] operands){
  329. Ptg[] allops = PtgCalculator.getAllComponents(operands);
  330. for (int i=0;i<allops.length;i++){
  331. // 20081120 KSC: blanks are handled differently now as Excel counts blank cells as 0's
  332. /*Object o = allops[i].getValue();
  333. if (o != null) return new PtgBool(false);
  334. */
  335. if (!allops[i].isBlank())
  336. return new PtgBool(false);
  337. }
  338. return new PtgBool(true);
  339. }
  340. /**
  341. * ISERROR
  342. Value refers to any error value
  343. (#N/A, #VALUE!, #REF!, #DIV/0!, #NUM!, #NAME?, or #NULL!).
  344. Usage@ ISERROR(value)
  345. Return@ PtgBool
  346. */
  347. protected static Ptg calcIserror(Ptg[] operands){
  348. if (operands[0] instanceof PtgErr){return new PtgBool(true);}
  349. String[] errorstr = {"#N/A", "#VALUE!", "#REF!", "#DIV/0!", "#NUM!", "#NAME?", "#NULL!" };
  350. Object o = operands[0].getValue();
  351. String opval = o.toString();
  352. for (int i=0;i<errorstr.length;i++){
  353. if (opval.equalsIgnoreCase(errorstr[i])){
  354. return new PtgBool(true);
  355. }
  356. }
  357. return new PtgBool(false);
  358. }
  359. /**
  360. * ISERR
  361. Returns TRUE if the value is any error value except #N/A
  362. */
  363. protected static Ptg calcIserr(Ptg[] operands){
  364. String[] errorstr = {"#VALUE!", "#REF!", "#DIV/0!", "#NUM!", "#NAME?", "#NULL!" };
  365. if (operands.length!=1) return new PtgErr(PtgErr.ERROR_VALUE);
  366. Object o = operands[0].getValue();
  367. String opval = o.toString();
  368. for (int i=0;i<errorstr.length;i++){
  369. if (opval.equalsIgnoreCase(errorstr[i])){
  370. return new PtgBool(true);
  371. }
  372. }
  373. return new PtgBool(false);
  374. }
  375. /**
  376. ISEVEN(number)
  377. Number is the value to test. If number is not an integer, it is truncated.
  378. Remarks
  379. If number is nonnumeric, ISEVEN returns the #VALUE! error value.
  380. Examples
  381. ISEVEN(-1) equals FALSE
  382. ISEVEN(2.5) equals TRUE
  383. ISEVEN(5) equals FALSE
  384. author: John
  385. */
  386. protected static Ptg calcIsEven(Ptg[] operands){
  387. if (operands.length < 1) return new PtgErr(PtgErr.ERROR_VALUE);
  388. Ptg[] allops = PtgCalculator.getAllComponents(operands);
  389. if (allops.length > 1) return new PtgBool(false);
  390. Object o = operands[0].getValue();
  391. if (o != null){
  392. try{ // KSC: mod for different number types + mod typo
  393. if (o instanceof Integer) {
  394. int s = ((Integer)o).intValue();
  395. if(s<0)return new PtgBool(false);
  396. return new PtgBool((s%2==0));
  397. } else if (o instanceof Float) {
  398. float s = ((Float)o).floatValue();
  399. if(s<0)return new PtgBool(false);
  400. return new PtgBool((s%2==0));
  401. } else if (o instanceof Double) {
  402. double s = ((Double)o).doubleValue();
  403. if(s<0)return new PtgBool(false);
  404. return new PtgBool((s%2==0));
  405. }
  406. }catch(Exception e){ }
  407. }
  408. return new PtgErr(PtgErr.ERROR_VALUE);
  409. }
  410. /**
  411. * ISLOGICAL
  412. Returns TRUE if the value is a logical value
  413. */
  414. protected static Ptg calcIsLogical(Ptg[] operands){
  415. Ptg[] allops = PtgCalculator.getAllComponents(operands);
  416. if (allops.length > 1) return new PtgBool(false);
  417. Object o = operands[0].getValue();
  418. // unfortunately we need to know the difference between
  419. // "true" and true, if it's a reference this can be difficult
  420. try{
  421. Boolean b = (Boolean)o;
  422. return new PtgBool(true);
  423. }catch(ClassCastException e){};
  424. return new PtgBool(false);
  425. }
  426. /**
  427. ISNUMBER
  428. Returns TRUE if the value is a number
  429. */
  430. protected static Ptg calcIsNumber(Ptg[] operands){
  431. Ptg[] allops = PtgCalculator.getAllComponents(operands);
  432. if (allops.length > 1) return new PtgBool(false);
  433. Object o = operands[0].getValue();
  434. try{
  435. Float f= (Float) o;
  436. return new PtgBool(true);
  437. }catch (ClassCastException e) {
  438. try {
  439. Double d= (Double) o;
  440. return new PtgBool(true);
  441. }catch(ClassCastException ee){
  442. try {
  443. Integer ii= (Integer) o;
  444. return new PtgBool(true);
  445. }catch(ClassCastException eee){ };
  446. };
  447. }
  448. return new PtgBool(false);
  449. }
  450. /**
  451. ISNONTEXT
  452. Returns TRUE if the value is not text
  453. */
  454. protected static Ptg calcIsNonText(Ptg[] operands){
  455. Ptg[] allops = PtgCalculator.getAllComponents(operands);
  456. if (allops.length > 1) return new PtgBool(false);
  457. // blanks return true for this test
  458. if (allops[0].isBlank())
  459. return new PtgBool(true);
  460. Object o = operands[0].getValue();
  461. if (o != null){
  462. try{
  463. String s = (String)o;
  464. return new PtgBool(false);
  465. }catch(ClassCastException e){};
  466. }
  467. return new PtgBool(true);
  468. }
  469. /**
  470. * ISNA
  471. Value refers to the #N/A
  472. (value not available) error value.
  473. usage@ ISNA(value)
  474. return@ PtgBool
  475. */
  476. protected static Ptg calcIsna(Ptg[] operands){
  477. if (operands.length != 1) return PtgCalculator.getError();
  478. if (operands[0] instanceof PtgErr){
  479. PtgErr per = (PtgErr) operands[0];
  480. if (per.getErrorType() == PtgErr.ERROR_NA){
  481. return new PtgBool(true);
  482. }
  483. }else if (operands[0].getIsReference()){
  484. Object o = operands[0].getValue();
  485. if (o.toString().equalsIgnoreCase(new PtgErr(PtgErr.ERROR_NA).toString())){
  486. return new PtgBool(true);
  487. }
  488. }
  489. return new PtgBool(false);
  490. }
  491. /**
  492. NA
  493. Returns the error value #N/A
  494. */
  495. protected static Ptg calcNa(Ptg[] operands){
  496. return new PtgErr(PtgErr.ERROR_NA);
  497. }
  498. /**
  499. ISTEXT
  500. Returns TRUE if the value is text
  501. */
  502. protected static Ptg calcIsText(Ptg[] operands){
  503. Ptg[] allops = PtgCalculator.getAllComponents(operands);
  504. if (allops.length > 1) return new PtgBool(false);
  505. Object o = operands[0].getValue();
  506. if (o != null){
  507. try{
  508. String s = (String)o;
  509. return new PtgBool(true);
  510. }catch(ClassCastException e){};
  511. }
  512. return new PtgBool(false);
  513. }
  514. /**
  515. ISODD
  516. Returns TRUE if the number is odd
  517. author: John
  518. */
  519. protected static Ptg calcIsOdd(Ptg[] operands){
  520. if (operands.length < 1) return new PtgErr(PtgErr.ERROR_VALUE);
  521. Ptg[] allops = PtgCalculator.getAllComponents(operands);
  522. if (allops.length > 1) return new PtgBool(false);
  523. Object o = operands[0].getValue();
  524. if (o != null){
  525. try{ // KSC: mod for different number types + mod typo
  526. if (o instanceof Integer) {
  527. int s = ((Integer)o).intValue();
  528. if(s<0)return new PtgBool(false);
  529. return new PtgBool((s%2!=0));
  530. } else if (o instanceof Float) {
  531. float s = ((Float)o).floatValue();
  532. if(s<0)return new PtgBool(false);
  533. return new PtgBool((s%2!=0));
  534. } else if (o instanceof Double) {
  535. double s = ((Double)o).doubleValue();
  536. if(s<0)return new PtgBool(false);
  537. return new PtgBool((s%2!=0));
  538. }
  539. } catch (Exception e) {}
  540. }
  541. return new PtgErr(PtgErr.ERROR_VALUE);
  542. }
  543. /**
  544. ISREF
  545. Returns TRUE if the value is a reference
  546. */
  547. protected static Ptg calcIsRef(Ptg[] operands){
  548. if (operands[0].getIsReference()){
  549. return new PtgBool(true);
  550. }
  551. return new PtgBool(false);
  552. }
  553. /**
  554. N
  555. Returns a value converted to a number.
  556. Syntax
  557. N(value)
  558. Value is the value you want converted. N converts values listed in the following table.
  559. If value is or refers to
  560. N returns
  561. A number
  562. That number
  563. A date, in one of the built-in date formats available in Microsoft Excel
  564. The serial number of that date --- Note that to us, this is just a number, the date
  565. format is just that, a format.
  566. TRUE
  567. 1
  568. Anything else
  569. 0
  570. */
  571. protected static Ptg calcN(Ptg[] operands){
  572. Object o = operands[0].getValue();
  573. if (o instanceof Double || o instanceof Integer || o instanceof Float || o instanceof Long){
  574. Double d = new Double(o.toString());
  575. return new PtgNumber(d.doubleValue());
  576. }
  577. if (o instanceof Boolean){
  578. Boolean b = (Boolean)o;
  579. boolean bo = b.booleanValue();
  580. if (bo) return new PtgInt(1);
  581. }
  582. return new PtgInt(0);
  583. }
  584. /**
  585. TYPE
  586. Returns a number indicating the data type of a value
  587. Value can be any Microsoft Excel value, such as a number, text, logical value, and so on.
  588. If value is TYPE returns
  589. Number 1
  590. Text 2
  591. Logical value 4
  592. Error value 16
  593. Array 64
  594. */
  595. protected static Ptg calcType(Ptg[] operands) {
  596. if (operands[0] instanceof PtgArray)
  597. return new PtgNumber(64); // avoid value calc for arrays
  598. else if (operands[0] instanceof PtgErr)
  599. return new PtgNumber(16);
  600. // otherwise, test value of operand
  601. Object value = operands[0].getValue();
  602. int type= 0;
  603. if (value instanceof String)
  604. type= 2;
  605. else if (value instanceof Number)
  606. type= 1;
  607. else if (value instanceof Boolean)
  608. type= 4;
  609. return new PtgNumber(type);
  610. }
  611. }
  612. /*
  613. * known INFO function operating systems:
  614. * TODO: need complete list
  615. Windows Vista Windows (32-bit) NT 6.00
  616. Windows XP Windows (32-bit) NT 5.01
  617. Windows2000 Windows (32-bit) NT 5.00
  618. Windows98 Windows (32-bit) 4.10
  619. Windows95 Windows (32-bit) 4.00
  620. */
  621. /*
  622. Linux 2.0.31 x86 IBM Java 1.3
  623. Linux (*) i386 Sun Java 1.3.1, 1.4 or Blackdown Java; (*) os.version depends on Linux Kernel version
  624. Linux (*) x86_64 Blackdown Java; note x86_64 might change to amd64; (*) os.version depends on Linux Kernel version
  625. Linux (*) sparc Blackdown Java; (*) os.version depends on Linux Kernel version
  626. Linux (*) ppc Blackdown Java; (*) os.version depends on Linux Kernel version
  627. Linux (*) armv41 Blackdown Java; (*) os.version depends on Linux Kernel version
  628. Linux (*) i686 GNU Java Compiler (GCJ); (*) os.version depends on Linux Kernel version
  629. Linux (*) ppc64 IBM Java 1.3; (*) os.version depends on Linux Kernel version
  630. Mac OS 7.5.1 PowerPC
  631. Mac OS 8.1 PowerPC
  632. Mac OS 9.0, 9.2.2 PowerPC MacOS 9.0: java.version=1.1.8, mrj.version=2.2.5; MacOS 9.2.2: java.version=1.1.8 mrj.version=2.2.5
  633. Mac OS X 10.1.3 ppc
  634. Mac OS X 10.2.6 ppc Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-39)
  635. Java HotSpot(TM) Client VM (build 1.4.1_01-14, mixed mode)
  636. Mac OS X 10.2.8 ppc using 1.3 JVM: java.vm.version=1.3.1_03-74, mrj.version=3.3.2; using 1.4 JVM: java.vm.version=1.4.1_01-24, mrj.version=69.1
  637. Mac OS X 10.3.1, 10.3.2, 10.3.3, 10.3.4 ppc JDK 1.4.x
  638. Mac OS X 10.3.8 ppc Mac OS X 10.3.8 Server; using 1.3 JVM: java.vm.version=1.3.1_03-76, mrj.version=3.3.3; using 1.4 JVM: java.vm.version=1.4.2-38; mrj.version=141.3
  639. Windows 95 4.0 x86
  640. Windows 98 4.10 x86 Note, that if you run Sun JDK 1.2.1 or 1.2.2 Windows 98 identifies itself as Windows 95.
  641. Windows Me 4.90 x86
  642. Windows NT 4.0 x86
  643. Windows 2000 5.0 x86
  644. Windows XP 5.1 x86 Note, that if you run older Java runtimes Windows XP identifies itself as Windows 2000.
  645. Windows 2003 5.2 x86 java.vm.version=1.4.2_06-b03; Note, that Windows Server 2003 identifies itself only as Windows 2003.
  646. Windows CE 3.0 build 11171 arm Compaq iPAQ 3950 (PocketPC 2002)
  647. OS/2 20.40 x86
  648. Solaris 2.x sparc
  649. SunOS 5.7 sparc Sun Ultra 5 running Solaris 2.7
  650. SunOS 5.8 sparc Sun Ultra 2 running Solaris 8
  651. SunOS 5.9 sparc Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_01-b03)
  652. Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)
  653. MPE/iX C.55.00 PA-RISC
  654. HP-UX B.10.20 PA-RISC JDK 1.1.x
  655. HP-UX B.11.00 PA-RISC JDK 1.1.x
  656. HP-UX B.11.11 PA-RISC JDK 1.1.x
  657. HP-UX B.11.11 PA_RISC JDK 1.2.x/1.3.x; note Java 2 returns PA_RISC and Java 1 returns PA-RISC
  658. HP-UX B.11.00 PA_RISC JDK 1.2.x/1.3.x
  659. HP-UX B.11.23 IA64N JDK 1.4.x
  660. HP-UX B.11.11 PA_RISC2.0 JDK 1.3.x or JDK 1.4.x, when run on a PA-RISC 2.0 system
  661. HP-UX B.11.11 PA_RISC JDK 1.2.x, even when run on a PA-RISC 2.0 system
  662. HP-UX B.11.11 PA-RISC JDK 1.1.x, even when run on a PA-RISC 2.0 system
  663. AIX 5.2 ppc64 sun.arch.data.model=64
  664. AIX 4.3 Power
  665. AIX 4.1 POWER_RS
  666. OS/390 390 02.10.00 J2RE 1.3.1 IBM OS/390 Persistent Reusable VM
  667. FreeBSD 2.2.2-RELEASE x86
  668. Irix 6.3 mips
  669. Digital Unix 4.0 alpha
  670. NetWare 4.11 4.11 x86
  671. OSF1 V5.1 alpha Java 1.3.1 on Compaq (now HP) Tru64 Unix V5.1
  672. OpenVMS V7.2-1 alpha Java 1.3.1_1 on OpenVMS 7.2
  673. */