2 * fn-information.c: Information built-in functions
5 * Jukka-Pekka Iivonen (iivonen@iki.fi)
6 * Jody Goldberg (jody@gnome.org)
7 * Morten Welinder (terra@gnome.org)
8 * Almer S. Tigelaar (almer@gnome.org)
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses/>.
24 * Many thanks to Harlan Grove for his excellent characterization and writeup
25 * of the multitude of different potential arguments across the various
26 * different spreadsheets. Although neither the code is not his, the set of
27 * attributes, and the comments on their behviour are. Hence he holds partial
28 * copyright on the CELL implementation.
31 #include <gnumeric-config.h>
34 #include <parse-util.h>
39 #include <gnm-format.h>
41 #include <style-font.h>
45 #include <sheet-style.h>
46 #include <number-match.h>
50 #include <goffice/goffice.h>
51 #include <gnm-plugin.h>
54 #include <sys/utsname.h>
60 GNM_PLUGIN_MODULE_HEADER
;
62 /***************************************************************************/
64 static GnmFuncHelp
const help_cell
[] = {
65 { GNM_FUNC_HELP_NAME
, F_("CELL:information of @{type} about @{cell}")},
66 { GNM_FUNC_HELP_ARG
, F_("type:string specifying the type of information requested")},
67 { GNM_FUNC_HELP_ARG
, F_("cell:cell reference")},
68 { GNM_FUNC_HELP_DESCRIPTION
, F_("@{type} specifies the type of information you want to obtain:\n"
69 " address \t\tReturns the given cell reference as text.\n"
70 " col \t\tReturns the number of the column in @{cell}.\n"
71 " color \t\tReturns 0.\n"
72 " contents \t\tReturns the contents of the cell in @{cell}.\n"
73 " column \t\tReturns the number of the column in @{cell}.\n"
74 " columnwidth \tReturns the column width.\n"
75 " coord \t\tReturns the absolute address of @{cell}.\n"
76 " datatype \tsame as type\n"
77 " filename \t\tReturns the name of the file of @{cell}.\n"
78 " format \t\tReturns the code of the format of the cell.\n"
79 " formulatype \tsame as type\n"
80 " locked \t\tReturns 1 if @{cell} is locked.\n"
81 " parentheses \tReturns 1 if @{cell} contains a negative value\n"
82 " \t\tand its format displays it with parentheses.\n"
83 " prefix \t\tReturns a character indicating the horizontal\n"
84 " \t\talignment of @{cell}.\n"
85 " prefixcharacter \tsame as prefix\n"
86 " protect \t\tReturns 1 if @{cell} is locked.\n"
87 " row \t\tReturns the number of the row in @{cell}.\n"
88 " sheetname \tReturns the name of the sheet of @{cell}.\n"
89 " type \t\tReturns \"l\" if @{cell} contains a string, \n"
90 " \t\t\"v\" if it contains some other value, and \n"
91 " \t\t\"b\" if @{cell} is blank.\n"
92 " value \t\tReturns the contents of the cell in @{cell}.\n"
93 " width \t\tReturns the column width.")},
94 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
95 { GNM_FUNC_HELP_EXAMPLES
, "=CELL(\"col\",A1)" },
96 { GNM_FUNC_HELP_EXAMPLES
, "=CELL(\"width\",A1)" },
97 { GNM_FUNC_HELP_SEEALSO
, "INDIRECT"},
105 static const translate_t translate_table
[] = {
110 { "#,##0.00", ",2" },
111 { "\"$\"#,##0_);\\(\"$\"#,##0\\)", "C0" },
112 { "\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)", "C0-" },
113 { "\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)", "C2" },
114 { "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)", "C2-" },
117 { "0.00e+00", "S2" },
119 { "# ?" "?/?" "?", "G" }, /* Don't accidentally use trigraphs here. */
121 { "m/d/yy h:mm", "D4" },
122 { "mm/dd/yy", "D4" },
123 { "d-mmm-yy", "D1" },
124 { "dd-mmm-yy", "D1" },
129 { "h:mm am/pm", "D7" },
130 { "h:mm:ss am/pm", "D6" },
136 translate_cell_format (GOFormat
const *format
)
140 const int translate_table_count
= G_N_ELEMENTS (translate_table
);
143 return value_new_string ("G");
145 fmt
= go_format_as_XL (format
);
148 * TODO : What does this do in different locales ??
150 for (i
= 0; i
< translate_table_count
; i
++) {
151 const translate_t
*t
= &translate_table
[i
];
153 if (!g_ascii_strcasecmp (fmt
, t
->format
)) {
154 return value_new_string (t
->output
);
158 #warning "FIXME: CELL('format',...) isn't right"
160 * 1. The above lookup should be done with respect to just the
161 * first of format alternatives.
162 * 2. I don't think colour should count.
163 * 3. We should add a dash if there are more alternatives.
166 return value_new_string ("G");
169 /* TODO : turn this into a range based routine */
171 gnumeric_cell (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
173 char const *info_type
= value_peek_string (argv
[0]);
174 GnmCellRef
const *ref
= &argv
[1]->v_range
.cell
.a
;
175 const Sheet
*sheet
= eval_sheet (ref
->sheet
, ei
->pos
->sheet
);
178 * CELL translates its keywords (ick)
186 nomfichier - filename
187 parentheses - parentheses
193 /* from CELL - limited usefulness! */
194 if (!g_ascii_strcasecmp(info_type
, "address")) {
196 GnmConventionsOut out
;
197 out
.accum
= g_string_new (NULL
);
198 out
.pp
= parse_pos_init_evalpos (&pp
, ei
->pos
);
199 out
.convs
= gnm_conventions_default
;
200 cellref_as_string (&out
, ref
, TRUE
);
201 return value_new_string_nocopy (g_string_free (out
.accum
, FALSE
));
203 } else if (!g_ascii_strcasecmp(info_type
, "sheetname")) {
204 return value_new_string (sheet
->name_unquoted
);
206 /* from later 123 versions - USEFUL! */
207 } else if (!g_ascii_strcasecmp(info_type
, "coord")) {
209 GnmConventionsOut out
;
210 out
.accum
= g_string_new (NULL
);
211 out
.pp
= parse_pos_init_evalpos (&pp
, ei
->pos
);
212 out
.convs
= gnm_conventions_default
;
213 cellref_as_string (&out
, ref
, TRUE
);
214 return value_new_string_nocopy (g_string_free (out
.accum
, FALSE
));
216 /* from CELL - pointless - use COLUMN instead! */
217 } else if (!g_ascii_strcasecmp (info_type
, "col") ||
218 !g_ascii_strcasecmp (info_type
, "column")) {
219 return value_new_int (ref
->col
+ 1);
221 /* from CELL - pointless - use ROW instead! */
222 } else if (!g_ascii_strcasecmp (info_type
, "row")) {
223 return value_new_int (ref
->row
+ 1);
225 /* from CELL - limited usefulness
226 * NOTE: differences between Excel & 123 - Excel's returns 1 whenever
227 * there's a color specified for EITHER positive OR negative values
228 * in the number format, e.g., 1 for format "[Black]0;-0;0" but not
229 * for format "0;-0;[Green]0"
230 * Another place where Excel doesn't conform to its documentation!
232 * 20180503: and even the above isn't right. What appears to be test
234 * (a) The format must be conditional; "[Red]0" won't do
235 * (b) One of the first two conditional formats must have a color
238 } else if (!g_ascii_strcasecmp (info_type
, "color")) {
239 /* See 1.7.6 for old version. */
240 return value_new_int (0);
242 /* absolutely pointless - compatibility only */
243 } else if (!g_ascii_strcasecmp (info_type
, "contents") ||
244 !g_ascii_strcasecmp (info_type
, "value")) {
245 GnmCell
const *cell
=
246 sheet_cell_get (sheet
, ref
->col
, ref
->row
);
247 if (cell
&& cell
->value
)
248 return value_dup (cell
->value
);
249 return value_new_empty ();
251 /* from CELL - limited usefulness!
252 * A testament to Microsoft's hypocracy! They could include this from
253 * 123R2.2 (it wasn't in 123R2.0x), modify it in Excel 4.0 to include
254 * the worksheet name, but they can't make any other changes to CELL?!
256 } else if (!g_ascii_strcasecmp (info_type
, "filename")) {
257 char const *name
= go_doc_get_uri (GO_DOC (sheet
->workbook
));
260 return value_new_string ("");
262 return value_new_string (name
);
265 /* Backwards compatibility w/123 - unnecessary */
266 } else if (!g_ascii_strcasecmp (info_type
, "format")) {
267 GnmStyle
const *mstyle
=
268 sheet_style_get (sheet
, ref
->col
, ref
->row
);
270 return translate_cell_format (gnm_style_get_format (mstyle
));
273 /* Backwards compatibility w/123 - unnecessary */
274 } else if (!g_ascii_strcasecmp (info_type
, "parentheses")) {
275 /* See 1.7.6 for old version. */
276 return value_new_int (0);
279 /* Backwards compatibility w/123 - unnecessary */
280 } else if (!g_ascii_strcasecmp (info_type
, "prefix") ||
281 !g_ascii_strcasecmp (info_type
, "prefixcharacter")) {
282 GnmStyle
const *mstyle
=
283 sheet_style_get (sheet
, ref
->col
, ref
->row
);
284 GnmCell
const *cell
=
285 sheet_cell_get (sheet
, ref
->col
, ref
->row
);
287 if (cell
&& cell
->value
&& VALUE_IS_STRING (cell
->value
)) {
288 switch (gnm_style_get_align_h (mstyle
)) {
289 case GNM_HALIGN_GENERAL
:
290 case GNM_HALIGN_LEFT
:
291 case GNM_HALIGN_JUSTIFY
:
292 case GNM_HALIGN_DISTRIBUTED
:
293 return value_new_string ("'");
294 case GNM_HALIGN_RIGHT
: return value_new_string ("\"");
295 case GNM_HALIGN_CENTER_ACROSS_SELECTION
:
296 case GNM_HALIGN_CENTER
: return value_new_string ("^");
297 case GNM_HALIGN_FILL
: return value_new_string ("\\");
298 default : return value_new_string ("");
301 return value_new_string ("");
304 } else if (!g_ascii_strcasecmp (info_type
, "locked") ||
305 !g_ascii_strcasecmp (info_type
, "protect")) {
306 GnmStyle
const *mstyle
=
307 sheet_style_get (sheet
, ref
->col
, ref
->row
);
308 return value_new_int (gnm_style_get_contents_locked (mstyle
) ? 1 : 0);
310 /* different characteristics grouped for efficiency
311 * TYPE needed for backward compatibility w/123 but otherwise useless
312 * DATATYPE and FORMULATYPE are options in later 123 versions' @CELL
313 * no need for them but included to make 123 conversion easier
314 Case "datatype", "formulatype", "type"
317 rv = IIf( t = "f" And rng.HasFormula, "f", "" )
319 If rng.formula = "" Then
321 ElseIf IsNumeric("0" & CStr(rng.Value)) _
322 Or (t = "t" And IsError(rng.Value)) Then
324 ElseIf rng.Value = CVErr(xlErrNA) Then
326 ElseIf IsError(rng.Value) Then
334 } else if (!g_ascii_strcasecmp (info_type
, "type") ||
335 !g_ascii_strcasecmp (info_type
, "datatype") ||
336 !g_ascii_strcasecmp (info_type
, "formulatype")) {
337 GnmCell
const *cell
=
338 sheet_cell_get (sheet
, ref
->col
, ref
->row
);
339 if (cell
&& cell
->value
) {
340 if (VALUE_IS_STRING (cell
->value
))
341 return value_new_string ("l");
343 return value_new_string ("v");
345 return value_new_string ("b");
348 } else if (!g_ascii_strcasecmp (info_type
, "width") ||
349 !g_ascii_strcasecmp (info_type
, "columnwidth")) {
350 ColRowInfo
const *info
=
351 sheet_col_get_info (sheet
, ref
->col
);
355 charwidth
= gnm_font_default_width
;
356 cellwidth
= info
->size_pts
;
358 return value_new_int (rint (cellwidth
/ charwidth
));
361 return value_new_error_VALUE (ei
->pos
);
366 *extension to CELL providing 123 @CELL/@CELLPOINTER functionality as
367 *well as access to most Range properties
368 *1st arg determines the property of characteristic being sought
369 *2nd arg [OPTIONAL] specifies cell reference - AcitveCell if missing
370 *3rd arg [OPTIONAL] specifies whether to return an array or not
371 * True = return array result for .Areas(1)
372 * False/missing = return scalar result for .Areas(1).Cells(1, 1)
376 Optional rng As Variant
, _
377 Optional rar As Boolean
= False _
379 Dim ws As Worksheet
, wb As Workbook
, rv As Variant
380 Dim i As Long
, j As Long
, m As Long
, n As Long
, t As String
382 Application
.Volatile True
384 If TypeOf rng Is Range Then
386 Set rng
= rng
.Areas(1)
388 Set rng
= rng
.Areas(1).Cells(1, 1)
390 ElseIf
IsMissing(rng
) Then
393 ExtCell
= CVErr(xlErrRef
)
400 n
= rng
.Columns
.Count
403 Set ws
= rng
.Worksheet
408 Case
"across" /* from later 123 versions - limited usefulness! */
413 rng
.Cells(i
, j
).HorizontalAlignment
= _
414 xlHAlignCenterAcrossSelection _
420 rng
.HorizontalAlignment
= _
421 xlHAlignCenterAcrossSelection _
425 Case
"backgroundcolor" /* from later 123 versions - USEFUL! */
429 rv(i
, j
) = rng
.Cells(i
, j
).Interior
.ColorIndex
433 rv
= rng
.Interior
.ColorIndex
436 Case
"bold" /* from later 123 versions - USEFUL! */
440 rv(i
, j
) = CLng(rng
.Cells(i
, j
).Font
.Bold
)
444 rv
= CLng(rng
.Font
.Bold
)
448 Case
"bottomborder" /* from later 123 versions - USEFUL! */
449 /* Note: many possible return values! wrap inside SIGN to test T/F */
454 rng
.Cells(i
, j
).Borders(xlEdgeBottom
).LineStyle
- _
459 rv
= rng
.Borders(xlEdgeBottom
).LineStyle
- xlLineStyleNone
462 Case
"bottombordercolor" /* from later 123 versions - USEFUL! */
467 rng
.Cells(i
, j
).Borders(xlEdgeBottom
).ColorIndex
471 rv
= rng
.Borders(xlEdgeBottom
).ColorIndex
478 rv(i
, j
) = rng
.Cells(i
, j
).EntireColumn
.Hidden
482 rv
= rng
.EntireColumn
.Hidden
489 If Not rng
.Cells(i
, j
).Comment Is Nothing Then
490 rv(i
, j
) = rng
.Cells(i
, j
).Comment
.text
497 If Not rng
.Comment Is Nothing Then
498 rv
= rng
.Comment
.text
504 Case
"currentarray" /* NOTE: returns Range addresses! */
508 rv(i
, j
) = rng
.Cells(i
, j
).CurrentArray
.Address
512 rv
= rng
.CurrentArray
.Address
515 Case
"currentregion" /* NOTE: returns Range addresses! */
519 rv(i
, j
) = rng
.Cells(i
, j
).CurrentRegion
.Address
523 rv
= rng
.CurrentRegion
.Address
526 Case
"filedate" /* from later 123 versions - limited usefulness! */
527 t
= wb
.BuiltinDocumentProperties("Last Save Time") /* invariant! */
539 Case
"fontface", "fontname", "typeface" /* from later 123 versions */
543 rv(i
, j
) = rng
.Cells(i
, j
).Font
.Name
550 Case
"fontsize", "pitch", "typesize" /* from later 123 versions */
554 rv(i
, j
) = rng
.Cells(i
, j
).Font
.Size
565 rv(i
, j
) = rng
.Cells(i
, j
).formula
572 Case
"formulaarray" /* questionable usefulness */
576 rv(i
, j
) = rng
.Cells(i
, j
).FormulaArray
580 rv
= rng
.FormulaArray
587 rv(i
, j
) = CLng(rng
.Cells(i
, j
).FormulaHidden
)
591 rv
= CLng(rng
.FormulaHidden
)
598 rv(i
, j
) = rng
.Cells(i
, j
).FormulaLocal
602 rv
= rng
.FormulaLocal
609 rv(i
, j
) = rng
.Cells(i
, j
).FormulaR1C1
616 Case
"formular1c1local"
620 rv(i
, j
) = rng
.Cells(i
, j
).FormulaR1C1Local
624 rv
= rng
.FormulaR1C1Local
627 Case
"halign", "horizontalalignment" /* from later 123 versions */
628 /* Note: different return values than 123. 0 = general alignment */
633 rng
.Cells(i
, j
).HorizontalAlignment
- _
638 rv
= rng
.HorizontalAlignment
- xlHAlignGeneral
645 rv(i
, j
) = CLng(rng
.Cells(i
, j
).HasArray
)
649 rv
= CLng(rng
.HasArray
)
656 rv(i
, j
) = CLng(rng
.Cells(i
, j
).HasFormula
)
660 rv
= CLng(rng
.HasFormula
)
663 Case
"hashyperlink", "hashyperlinks"
667 rv(i
, j
) = CLng(rng
.Cells(i
, j
).Hyperlinks
.Count
> 0)
671 rv
= CLng(rng
.Hyperlinks
.Count
> 0)
674 Case
"height", "rowheight" /* from later 123 versions - USEFUL! */
678 rv(i
, j
) = rng
.Cells(i
, j
).Height
685 Case
"hidden" /* see ColumnHidden and RowHidden - this is less useful */
689 rv(i
, j
) = CLng(rng
.Cells(i
, j
).Hidden
)
693 rv
= CLng(rng
.Hidden
)
696 Case
"hyperlinkaddress"
700 rv(i
, j
) = rng
.Cells(i
, j
).Hyperlinks(1).Address
704 rv
= rng
.Hyperlinks(1).Address
711 rv(i
, j
) = rng
.Cells(i
, j
).rng
.IndentLevel
715 rv
= rng
.rng
.IndentLevel
718 Case
"italic" /* from later 123 versions - USEFUL! */
722 rv(i
, j
) = CLng(rng
.Cells(i
, j
).Font
.Italic
)
726 rv
= CLng(rng
.Font
.Italic
)
733 rv(i
, j
) = rng
.Cells(i
, j
).Left
740 Case
"leftborder" /* from later 123 versions */
741 /* Note: many possible return values! wrap inside SIGN to test T/F */
746 rng
.Cells(i
, j
).Borders(xlEdgeLeft
).LineStyle
- _
751 rv
= rng
.Borders(xlEdgeLeft
).LineStyle
- xlLineStyleNone
754 Case
"leftbordercolor" /* from later 123 versions */
759 rng
.Cells(i
, j
).Borders(xlEdgeLeft
).ColorIndex
763 rv
= rng
.Borders(xlEdgeLeft
).ColorIndex
766 Case
"mergearea" /* NOTE: returns Range addresses! */
770 rv(i
, j
) = rng
.Cells(i
, j
).MergeArea
.Address
774 rv
= rng
.MergeArea
.Address
781 rv(i
, j
) = CLng(rng
.Cells(i
, j
).MergeCells
)
785 rv
= CLng(rng
.MergeCells
)
792 rv(i
, j
) = rng
.Cells(i
, j
).Name
803 rv(i
, j
) = rng
.Cells(i
, j
).NumberFormat
807 rv
= rng
.NumberFormat
810 Case
"numberformatlocal"
814 rv(i
, j
) = rng
.Cells(i
, j
).NumberFormatLocal
818 rv
= rng
.NumberFormatLocal
821 Case
"orientation", "rotation" /* from later 123 versions */
825 rv(i
, j
) = rng
.Cells(i
, j
).Orientation
832 Case
"pattern" /* from later 123 versions */
837 rng
.Cells(i
, j
).Interior
.Pattern
- _
842 rv
= rng
.Interior
.Pattern
- xlPatternNone
845 Case
"patterncolor" /* from later 123 versions */
850 rng
.Cells(i
, j
).Interior
.PatternColorIndex
854 rv
= rng
.Interior
.PatternColorIndex
857 Case
"rightborder" /* from later 123 versions */
858 /* Note: many possible return values! wrap inside SIGN to test T/F */
863 rng
.Cells(i
, j
).Borders(xlEdgeRight
).LineStyle
- _
868 rv
= rng
.Borders(xlEdgeRight
).LineStyle
- xlLineStyleNone
871 Case
"rightbordercolor" /* from later 123 versions */
876 rng
.Cells(i
, j
).Borders(xlEdgeRight
).ColorIndex
880 rv
= rng
.Borders(xlEdgeRight
).ColorIndex
887 rv(i
, j
) = CLng(rng
.Cells(i
, j
).EntireRow
.Hidden
)
891 rv
= CLng(rng
.EntireRow
.Hidden
)
895 /* Who needs consistency?! Why doesn't this return a Range object? */
896 t
= ws
.ScrollArea
/* invariant! */
908 Case
"sheet", "worksheet" /* from later 123 versions - USEFUL! */
909 t
= ws
.Index
/* invariant! */
921 Case
"sheetname", "worksheetname" /* from later 123 versions - USEFUL! */
922 t
= ws
.Name
/* invariant */
934 Case
"sheetcount", "sheetscount", "worksheetcount", "worksheetscount"
935 t
= wb
.Worksheets
.Count
/* invariant */
951 rv(i
, j
) = CLng(rng
.Cells(i
, j
).ShrinkToFit
)
955 rv
= CLng(rng
.ShrinkToFit
)
962 rv(i
, j
) = rng
.Cells(i
, j
).Style
.Name
969 Case
"text" /* USEFUL! */
973 rv(i
, j
) = rng
.Cells(i
, j
).text
980 Case
"textcolor" /* from later 123 versions - USEFUL! */
984 rv(i
, j
) = rng
.Cells(i
, j
).Font
.ColorIndex
988 rv
= rng
.Font
.ColorIndex
995 rv(i
, j
) = rng
.Cells(i
, j
).Top
1002 Case
"topborder" /* from later 123 versions */
1003 /* Note: many possible return values! wrap inside SIGN to test T/F */
1008 rng
.Cells(i
, j
).Borders(xlEdgeTop
).LineStyle
- _
1013 rv
= rng
.Borders(xlEdgeTop
).LineStyle
- xlLineStyleNone
1016 Case
"topbordercolor" /* from later 123 versions */
1021 rng
.Cells(i
, j
).Borders(xlEdgeTop
).ColorIndex
1025 rv
= rng
.Borders(xlEdgeTop
).ColorIndex
1028 Case
"underline" /* from later 123 versions - USEFUL! */
1029 /* Note: many possible return values! wrap inside SIGN to test T/F */
1034 rng
.Cells(i
, j
).Font
.Underline
- _
1035 xlUnderlineStyleNone
1039 rv
= rng
.Font
.Underline
- xlUnderlineStyleNone
1042 Case
"usedrange" /* NOTE: returns Range addresses! */
1043 t
= ws
.UsedRange
.Address
/* invariant */
1055 Case
"usestandardheight"
1059 rv(i
, j
) = CLng(rng
.Cells(i
, j
).UseStandardHeight
)
1063 rv
= CLng(rng
.UseStandardHeight
)
1066 Case
"usestandardwidth"
1070 rv(i
, j
) = CLng(rng
.Cells(i
, j
).UseStandardWidth
)
1074 rv
= CLng(rng
.UseStandardWidth
)
1077 Case
"valign", "verticalalignment" /* from later 123 versions */
1078 /* Note: different return values than 123. 0 = Bottom-aligned */
1083 rng
.Cells(i
, j
).VerticalAlignment
- _
1088 rv
= rng
.VerticalAlignment
- xlVAlignBottom
1091 Case
"visible", "sheetvisible", "worksheetvisible"
1092 t
= CLng(ws
.Visible
) /* invariant */
1104 Case
"workbookfullname" /* same as FileName in later 123 versions */
1105 t
= wb
.FullName
/* invariant */
1118 t
= wb
.Name
/* invariant */
1131 t
= wb
.path
/* invariant */
1143 Case
"wrap", "wraptext" /* from later 123 versions */
1147 rv(i
, j
) = CLng(rng
.Cells(i
, j
).WrapText
)
1151 rv
= CLng(rng
.WrapText
)
1154 Case Else
/* invalid property/characteristic */
1155 t
= CVErr(xlErrValue
) /* invariant */
1173 /***************************************************************************/
1175 static GnmFuncHelp
const help_expression
[] = {
1176 { GNM_FUNC_HELP_NAME
, F_("EXPRESSION:expression in @{cell} as a string")},
1177 { GNM_FUNC_HELP_ARG
, F_("cell:a cell reference")},
1178 { GNM_FUNC_HELP_NOTE
, F_("If @{cell} contains no expression, EXPRESSION returns empty.")},
1179 { GNM_FUNC_HELP_SEEALSO
, "TEXT"},
1180 { GNM_FUNC_HELP_END
}
1184 gnumeric_expression (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1186 GnmValue
const * const v
= argv
[0];
1187 if (VALUE_IS_CELLRANGE (v
)) {
1189 GnmCellRef
const * a
= &v
->v_range
.cell
.a
;
1190 GnmCellRef
const * b
= &v
->v_range
.cell
.b
;
1192 if (a
->col
!= b
->col
|| a
->row
!= b
->row
|| a
->sheet
!=b
->sheet
)
1193 return value_new_error_REF (ei
->pos
);
1195 cell
= sheet_cell_get (eval_sheet (a
->sheet
, ei
->pos
->sheet
),
1198 if (cell
&& gnm_cell_has_expr (cell
)) {
1200 char *expr_string
= gnm_expr_top_as_string
1202 parse_pos_init_cell (&pos
, cell
),
1203 gnm_conventions_default
);
1204 return value_new_string_nocopy (expr_string
);
1208 return value_new_empty ();
1210 /***************************************************************************/
1212 static GnmFuncHelp
const help_get_formula
[] = {
1213 { GNM_FUNC_HELP_NAME
, F_("GET.FORMULA:the formula in @{cell} as a string")},
1214 { GNM_FUNC_HELP_ARG
, F_("cell:the referenced cell")},
1215 { GNM_FUNC_HELP_ODF
, F_("GET.FORMULA is the OpenFormula function FORMULA.") },
1216 { GNM_FUNC_HELP_EXAMPLES
, F_("If A1 is empty and A2 contains =B1+B2, then\n"
1217 "GET.FORMULA(A2) yields '=B1+B2' and\n"
1218 "GET.FORMULA(A1) yields ''.") },
1219 { GNM_FUNC_HELP_SEEALSO
, "EXPRESSION,ISFORMULA"},
1220 { GNM_FUNC_HELP_END
}
1224 gnumeric_get_formula (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1226 GnmValue
const * const v
= argv
[0];
1227 if (VALUE_IS_CELLRANGE (v
)) {
1229 GnmCellRef
const * a
= &v
->v_range
.cell
.a
;
1230 GnmCellRef
const * b
= &v
->v_range
.cell
.b
;
1232 if (a
->col
!= b
->col
|| a
->row
!= b
->row
|| a
->sheet
!=b
->sheet
)
1233 return value_new_error_REF (ei
->pos
);
1235 cell
= sheet_cell_get (eval_sheet (a
->sheet
, ei
->pos
->sheet
),
1238 if (cell
&& gnm_cell_has_expr (cell
)) {
1239 GnmConventionsOut out
;
1241 out
.accum
= g_string_new ("=");
1242 out
.pp
= parse_pos_init_cell (&pp
, cell
);
1243 out
.convs
= gnm_conventions_default
;
1244 gnm_expr_top_as_gstring (cell
->base
.texpr
, &out
);
1245 return value_new_string_nocopy (g_string_free (out
.accum
, FALSE
));
1249 return value_new_empty ();
1252 /***************************************************************************/
1254 static GnmFuncHelp
const help_isformula
[] = {
1255 { GNM_FUNC_HELP_NAME
, F_("ISFORMULA:TRUE if @{cell} contains a formula")},
1256 { GNM_FUNC_HELP_ARG
, F_("cell:the referenced cell")},
1257 { GNM_FUNC_HELP_ODF
, F_("ISFORMULA is OpenFormula compatible.") },
1258 { GNM_FUNC_HELP_SEEALSO
, "GET.FORMULA"},
1259 { GNM_FUNC_HELP_END
}
1263 gnumeric_isformula (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1265 GnmValue
const * const v
= argv
[0];
1266 if (VALUE_IS_CELLRANGE (v
)) {
1268 GnmCellRef
const * a
= &v
->v_range
.cell
.a
;
1269 GnmCellRef
const * b
= &v
->v_range
.cell
.b
;
1271 if (a
->col
!= b
->col
|| a
->row
!= b
->row
|| a
->sheet
!=b
->sheet
)
1272 return value_new_error_REF (ei
->pos
);
1274 cell
= sheet_cell_get (eval_sheet (a
->sheet
, ei
->pos
->sheet
),
1276 return value_new_bool (cell
&& gnm_cell_has_expr (cell
));
1279 return value_new_error_REF (ei
->pos
);
1283 /***************************************************************************/
1285 static GnmFuncHelp
const help_countblank
[] = {
1286 { GNM_FUNC_HELP_NAME
, F_("COUNTBLANK:the number of blank cells in @{range}")},
1287 { GNM_FUNC_HELP_ARG
, F_("range:a cell range")},
1288 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1289 { GNM_FUNC_HELP_EXAMPLES
, F_("COUNTBLANK(A1:A20) returns the number of blank cell in A1:A20.") },
1290 { GNM_FUNC_HELP_SEEALSO
, "COUNT"},
1291 { GNM_FUNC_HELP_END
}
1295 cb_countblank (GnmValueIter
const *iter
, gpointer user
)
1297 GnmValue
const *v
= iter
->v
;
1299 if (VALUE_IS_STRING (v
) && value_peek_string (v
)[0] == 0)
1300 ; /* Nothing -- the empty string is blank. */
1301 else if (VALUE_IS_EMPTY (v
))
1304 *((int *)user
) -= 1;
1310 gnumeric_countblank (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1312 GnmValue
const *v
= argv
[0];
1314 value_area_get_width (v
, ei
->pos
) *
1315 value_area_get_height (v
, ei
->pos
);
1318 if (VALUE_IS_CELLRANGE (v
)) {
1320 Sheet
*start_sheet
, *end_sheet
;
1322 gnm_rangeref_normalize (&v
->v_range
.cell
, ei
->pos
,
1323 &start_sheet
, &end_sheet
, &r
);
1325 if (start_sheet
!= end_sheet
&& end_sheet
!= NULL
)
1326 nsheets
= 1 + abs (end_sheet
->index_in_wb
-
1327 start_sheet
->index_in_wb
);
1332 value_area_foreach (v
, ei
->pos
, CELL_ITER_IGNORE_BLANK
,
1333 &cb_countblank
, &count
);
1335 return value_new_int (count
);
1338 /***************************************************************************/
1340 static GnmFuncHelp
const help_info
[] = {
1341 { GNM_FUNC_HELP_NAME
, F_("INFO:information about the current operating environment "
1342 "according to @{type}")},
1343 { GNM_FUNC_HELP_ARG
, F_("type:string giving the type of information requested")},
1344 { GNM_FUNC_HELP_DESCRIPTION
, F_("INFO returns information about the current operating "
1345 "environment according to @{type}:\n"
1346 " memavail \t\tReturns the amount of memory available, bytes.\n"
1347 " memused \tReturns the amount of memory used (bytes).\n"
1348 " numfile \t\tReturns the number of active worksheets.\n"
1349 " osversion \t\tReturns the operating system version.\n"
1350 " recalc \t\tReturns the recalculation mode (automatic).\n"
1351 " release \t\tReturns the version of Gnumeric as text.\n"
1352 " system \t\tReturns the name of the environment.\n"
1353 " totmem \t\tReturns the amount of total memory available.")},
1354 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1355 { GNM_FUNC_HELP_EXAMPLES
, "=INFO(\"system\")" },
1356 { GNM_FUNC_HELP_EXAMPLES
, "=INFO(\"release\")" },
1357 { GNM_FUNC_HELP_EXAMPLES
, "=INFO(\"numfile\")" },
1358 { GNM_FUNC_HELP_SEEALSO
, "CELL"},
1359 { GNM_FUNC_HELP_END
}
1363 gnumeric_info (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1365 char const * const info_type
= value_peek_string (argv
[0]);
1366 if (!g_ascii_strcasecmp (info_type
, "directory")) {
1367 /* Path of the current directory or folder. */
1368 return value_new_error (ei
->pos
, _("Unimplemented"));
1369 } else if (!g_ascii_strcasecmp (info_type
, "memavail")) {
1370 /* Amount of memory available, in bytes. */
1371 return value_new_int (15 << 20); /* Good enough... */
1372 } else if (!g_ascii_strcasecmp (info_type
, "memused")) {
1373 /* Amount of memory being used for data. */
1374 return value_new_int (1 << 20); /* Good enough... */
1375 } else if (!g_ascii_strcasecmp (info_type
, "numfile")) {
1376 /* Number of active worksheets. */
1377 return value_new_int (1); /* Good enough... */
1378 } else if (!g_ascii_strcasecmp (info_type
, "origin")) {
1379 /* Absolute A1-style reference, as text, prepended with "$A:"
1380 * for Lotus 1-2-3 release 3.x compatibility. Returns the cell
1381 * reference of the top and leftmost cell visible in the
1382 * window, based on the current scrolling position.
1384 return value_new_error (ei
->pos
, _("Unimplemented"));
1385 } else if (!g_ascii_strcasecmp (info_type
, "osversion")) {
1387 /* Current operating system version, as text. */
1388 struct utsname unamedata
;
1390 if (uname (&unamedata
) == -1)
1391 return value_new_error (ei
->pos
,
1392 _("Unknown version"));
1394 char *tmp
= g_strdup_printf (_("%s version %s"),
1397 return value_new_string_nocopy (tmp
);
1399 #elif defined(G_OS_WIN32)
1401 return value_new_string ("Windows (32-bit) NT 5.01");
1403 // Nothing -- go to catch-all
1405 } else if (!g_ascii_strcasecmp (info_type
, "recalc")) {
1406 /* Current recalculation mode; returns "Automatic" or "Manual". */
1407 Workbook
const *wb
= ei
->pos
->sheet
->workbook
;
1408 return value_new_string (
1409 workbook_get_recalcmode (wb
) ? _("Automatic") : _("Manual"));
1410 } else if (!g_ascii_strcasecmp (info_type
, "release")) {
1411 /* Version of Gnumeric (Well, Microsoft Excel), as text. */
1412 return value_new_string (GNM_VERSION_FULL
);
1413 } else if (!g_ascii_strcasecmp (info_type
, "system")) {
1415 /* Name of the operating environment. */
1416 struct utsname unamedata
;
1418 if (uname (&unamedata
) == -1)
1419 return value_new_error (ei
->pos
, _("Unknown system"));
1421 return value_new_string (unamedata
.sysname
);
1422 #elif defined(G_OS_WIN32)
1423 return value_new_string ("pcdos"); /* seems constant */
1425 // Nothing -- go to catch-all
1427 } else if (!g_ascii_strcasecmp (info_type
, "totmem")) {
1428 /* Total memory available, including memory already in use, in
1431 return value_new_int (16 << 20); /* Good enough... */
1434 return value_new_error (ei
->pos
, _("Unknown info_type"));
1437 /***************************************************************************/
1439 static GnmFuncHelp
const help_iserror
[] = {
1440 { GNM_FUNC_HELP_NAME
, F_("ISERROR:TRUE if @{value} is any error value")},
1441 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1442 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1443 { GNM_FUNC_HELP_EXAMPLES
, "=ISERROR(NA())" },
1444 { GNM_FUNC_HELP_EXAMPLES
, "=ISERROR(5/0)" },
1445 { GNM_FUNC_HELP_SEEALSO
, "ISERR,ISNA"},
1446 { GNM_FUNC_HELP_END
}
1450 gnumeric_iserror (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1452 return value_new_bool (VALUE_IS_ERROR (argv
[0]));
1455 /***************************************************************************/
1457 static GnmFuncHelp
const help_isna
[] = {
1458 { GNM_FUNC_HELP_NAME
, F_("ISNA:TRUE if @{value} is the #N/A error value")},
1459 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1460 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1461 { GNM_FUNC_HELP_EXAMPLES
, "=ISNA(NA())" },
1462 { GNM_FUNC_HELP_EXAMPLES
, "=ISNA(5/0)" },
1463 { GNM_FUNC_HELP_SEEALSO
, "NA"},
1464 { GNM_FUNC_HELP_END
}
1468 * We need to operator directly in the input expression in order to bypass
1469 * the error handling mechanism
1472 gnumeric_isna (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1474 return value_new_bool (value_error_classify (argv
[0]) == GNM_ERROR_NA
);
1477 /***************************************************************************/
1479 static GnmFuncHelp
const help_iserr
[] = {
1480 { GNM_FUNC_HELP_NAME
, F_("ISERR:TRUE if @{value} is any error value except #N/A")},
1481 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1482 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1483 { GNM_FUNC_HELP_EXAMPLES
, "=ISERR(NA())" },
1484 { GNM_FUNC_HELP_EXAMPLES
, "=ISERR(5/0)" },
1485 { GNM_FUNC_HELP_SEEALSO
, "ISERROR"},
1486 { GNM_FUNC_HELP_END
}
1490 gnumeric_iserr (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1492 return value_new_bool (VALUE_IS_ERROR (argv
[0]) &&
1493 value_error_classify (argv
[0]) != GNM_ERROR_NA
);
1496 /***************************************************************************/
1498 static GnmFuncHelp
const help_error_type
[] = {
1499 { GNM_FUNC_HELP_NAME
, F_("ERROR.TYPE:the type of @{error}")},
1500 { GNM_FUNC_HELP_ARG
, F_("error:an error")},
1501 { GNM_FUNC_HELP_DESCRIPTION
, F_("ERROR.TYPE returns an error number corresponding to the given "
1502 "error value. The error numbers for error values are:\n\n"
1509 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1510 { GNM_FUNC_HELP_EXAMPLES
, "=ERROR.TYPE(NA())" },
1511 { GNM_FUNC_HELP_EXAMPLES
, "=ERROR.TYPE(ERROR(\"#X\"))" },
1512 { GNM_FUNC_HELP_SEEALSO
, "ISERROR"},
1513 { GNM_FUNC_HELP_END
}
1517 gnumeric_error_type (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1519 switch (value_error_classify (argv
[0])) {
1520 case GNM_ERROR_NULL
: return value_new_int (1);
1521 case GNM_ERROR_DIV0
: return value_new_int (2);
1522 case GNM_ERROR_VALUE
: return value_new_int (3);
1523 case GNM_ERROR_REF
: return value_new_int (4);
1524 case GNM_ERROR_NAME
: return value_new_int (5);
1525 case GNM_ERROR_NUM
: return value_new_int (6);
1526 case GNM_ERROR_NA
: return value_new_int (7);
1528 return value_new_error_NA (ei
->pos
);
1532 /***************************************************************************/
1534 static GnmFuncHelp
const help_na
[] = {
1535 { GNM_FUNC_HELP_NAME
, F_("NA:the error value #N/A")},
1536 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1537 { GNM_FUNC_HELP_EXAMPLES
, "=NA()" },
1538 { GNM_FUNC_HELP_EXAMPLES
, "=ISNA(NA())" },
1539 { GNM_FUNC_HELP_SEEALSO
, "ISNA"},
1540 { GNM_FUNC_HELP_END
}
1545 gnumeric_na (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1547 return value_new_error_NA (ei
->pos
);
1550 /***************************************************************************/
1552 static GnmFuncHelp
const help_error
[] = {
1553 { GNM_FUNC_HELP_NAME
, F_("ERROR:the error with the given @{name}")},
1554 { GNM_FUNC_HELP_ARG
, F_("name:string")},
1555 { GNM_FUNC_HELP_EXAMPLES
, "=ERROR(\"#N/A\")" },
1556 { GNM_FUNC_HELP_EXAMPLES
, "=ISNA(ERROR(\"#N/A\"))" },
1557 { GNM_FUNC_HELP_SEEALSO
, "ISERROR"},
1558 { GNM_FUNC_HELP_END
}
1562 gnumeric_error (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1564 return value_new_error (ei
->pos
, value_peek_string (argv
[0]));
1567 /***************************************************************************/
1569 static GnmFuncHelp
const help_isblank
[] = {
1570 { GNM_FUNC_HELP_NAME
, F_("ISBLANK:TRUE if @{value} is blank")},
1571 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1572 { GNM_FUNC_HELP_DESCRIPTION
, F_("This function checks if a value is blank. Empty cells are blank, but empty strings are not.")},
1573 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1574 { GNM_FUNC_HELP_EXAMPLES
, "=ISBLANK(\"\")" },
1575 { GNM_FUNC_HELP_END
}
1579 gnumeric_isblank (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1581 return value_new_bool (VALUE_IS_EMPTY (argv
[0]));
1584 /***************************************************************************/
1586 static GnmFuncHelp
const help_iseven
[] = {
1587 { GNM_FUNC_HELP_NAME
, F_("ISEVEN:TRUE if @{n} is even")},
1588 { GNM_FUNC_HELP_ARG
, F_("n:number")},
1589 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1590 { GNM_FUNC_HELP_EXAMPLES
, "=ISEVEN(4)" },
1591 { GNM_FUNC_HELP_SEEALSO
, "ISODD"},
1592 { GNM_FUNC_HELP_END
}
1596 gnumeric_iseven (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1598 gnm_float x
= value_get_as_float (argv
[0]);
1599 gnm_float r
= gnm_fmod (gnm_abs (x
), 2);
1601 /* If x is too big, this will always be true. */
1602 return value_new_bool (r
< 1);
1605 /***************************************************************************/
1607 static GnmFuncHelp
const help_islogical
[] = {
1608 { GNM_FUNC_HELP_NAME
, F_("ISLOGICAL:TRUE if @{value} is a logical value")},
1609 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1610 { GNM_FUNC_HELP_DESCRIPTION
, F_("This function checks if a value is either TRUE or FALSE.") },
1611 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1612 { GNM_FUNC_HELP_EXAMPLES
, "=ISLOGICAL(1)" },
1613 { GNM_FUNC_HELP_EXAMPLES
, "=ISLOGICAL(\"Gnumeric\")" },
1614 { GNM_FUNC_HELP_END
}
1618 gnumeric_islogical (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1620 return value_new_bool (VALUE_IS_BOOLEAN (argv
[0]));
1623 /***************************************************************************/
1625 static GnmFuncHelp
const help_isnontext
[] = {
1626 { GNM_FUNC_HELP_NAME
, F_("ISNONTEXT:TRUE if @{value} is not text")},
1627 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1628 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1629 { GNM_FUNC_HELP_EXAMPLES
, "=ISNONTEXT(\"Gnumeric\")" },
1630 { GNM_FUNC_HELP_SEEALSO
, "ISTEXT"},
1631 { GNM_FUNC_HELP_END
}
1635 gnumeric_isnontext (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1637 return value_new_bool (!VALUE_IS_STRING (argv
[0]));
1640 /***************************************************************************/
1642 static GnmFuncHelp
const help_isnumber
[] = {
1643 { GNM_FUNC_HELP_NAME
, F_("ISNUMBER:TRUE if @{value} is a number")},
1644 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1645 { GNM_FUNC_HELP_DESCRIPTION
, F_("This function checks if a value is a number. Neither TRUE nor FALSE are numbers for this purpose.") },
1646 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1647 { GNM_FUNC_HELP_EXAMPLES
, "=ISNUMBER(\"Gnumeric\")" },
1648 { GNM_FUNC_HELP_EXAMPLES
, "=ISNUMBER(PI())" },
1649 { GNM_FUNC_HELP_END
}
1653 gnumeric_isnumber (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1655 return value_new_bool (argv
[0] && VALUE_IS_FLOAT (argv
[0]));
1658 /***************************************************************************/
1660 static GnmFuncHelp
const help_isodd
[] = {
1661 { GNM_FUNC_HELP_NAME
, F_("ISODD:TRUE if @{n} is odd")},
1662 { GNM_FUNC_HELP_ARG
, F_("n:number")},
1663 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1664 { GNM_FUNC_HELP_EXAMPLES
, "=ISODD(3)" },
1665 { GNM_FUNC_HELP_SEEALSO
, "ISEVEN"},
1666 { GNM_FUNC_HELP_END
}
1670 gnumeric_isodd (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1672 gnm_float x
= value_get_as_float (argv
[0]);
1673 gnm_float r
= gnm_fmod (gnm_abs (x
), 2);
1675 /* If x is too big, this will always be false. */
1676 return value_new_bool (r
>= 1);
1679 /***************************************************************************/
1681 static GnmFuncHelp
const help_isref
[] = {
1682 { GNM_FUNC_HELP_NAME
, F_("ISREF:TRUE if @{value} is a reference")},
1683 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1684 { GNM_FUNC_HELP_DESCRIPTION
, F_("This function checks if a value is a cell reference.") },
1685 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1686 { GNM_FUNC_HELP_EXAMPLES
, "=ISREF(A1)" },
1687 { GNM_FUNC_HELP_END
}
1691 gnumeric_isref (GnmFuncEvalInfo
*ei
, int argc
, GnmExprConstPtr
const *argv
)
1697 return value_new_error (ei
->pos
,
1698 _("Invalid number of arguments"));
1700 v
= gnm_expr_eval (argv
[0], ei
->pos
,
1701 GNM_EXPR_EVAL_PERMIT_NON_SCALAR
|
1702 GNM_EXPR_EVAL_WANT_REF
);
1703 res
= VALUE_IS_CELLRANGE (v
);
1706 return value_new_bool (res
);
1709 /***************************************************************************/
1711 static GnmFuncHelp
const help_istext
[] = {
1712 { GNM_FUNC_HELP_NAME
, F_("ISTEXT:TRUE if @{value} is text")},
1713 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1714 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1715 { GNM_FUNC_HELP_EXAMPLES
, "=ISTEXT(\"Gnumeric\")" },
1716 { GNM_FUNC_HELP_EXAMPLES
, "=ISTEXT(34)" },
1717 { GNM_FUNC_HELP_SEEALSO
, "ISNONTEXT"},
1718 { GNM_FUNC_HELP_END
}
1722 gnumeric_istext (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1724 return value_new_bool (VALUE_IS_STRING (argv
[0]));
1727 /***************************************************************************/
1729 static GnmFuncHelp
const help_n
[] = {
1730 { GNM_FUNC_HELP_NAME
, F_("N:@{text} converted to a number")},
1731 { GNM_FUNC_HELP_ARG
, F_("text:string")},
1732 { GNM_FUNC_HELP_NOTE
, F_("If @{text} contains non-numerical text, 0 is returned.") },
1733 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1734 { GNM_FUNC_HELP_EXAMPLES
, "=N(\"42\")" },
1735 { GNM_FUNC_HELP_EXAMPLES
, F_("=N(\"eleven\")") },
1736 { GNM_FUNC_HELP_END
}
1740 gnumeric_n (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1744 if (VALUE_IS_NUMBER (argv
[0]))
1745 return value_new_float (value_get_as_float (argv
[0]));
1747 if (!VALUE_IS_STRING (argv
[0]))
1748 return value_new_error_NUM (ei
->pos
);
1750 v
= format_match_number (value_peek_string (argv
[0]),
1752 sheet_date_conv (ei
->pos
->sheet
));
1756 return value_new_float (0);
1759 /***************************************************************************/
1761 static GnmFuncHelp
const help_type
[] = {
1762 { GNM_FUNC_HELP_NAME
, F_("TYPE:a number indicating the data type of @{value}")},
1763 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1764 { GNM_FUNC_HELP_DESCRIPTION
, F_("TYPE returns a number indicating the data type of @{value}:\n"
1770 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1771 { GNM_FUNC_HELP_EXAMPLES
, "=TYPE(3)" },
1772 { GNM_FUNC_HELP_EXAMPLES
, "=TYPE(\"Gnumeric\")" },
1773 { GNM_FUNC_HELP_END
}
1777 gnumeric_type (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1779 GnmValue
const *v
= argv
[0];
1780 switch (v
? v
->v_any
.type
: VALUE_EMPTY
) {
1782 return value_new_int (4);
1785 return value_new_int (1);
1786 case VALUE_CELLRANGE
:
1788 return value_new_int (16);
1790 return value_new_int (2);
1792 return value_new_int (64);
1797 return value_new_error_VALUE (ei
->pos
);
1800 /***************************************************************************/
1802 static GnmFuncHelp
const help_getenv
[] = {
1803 { GNM_FUNC_HELP_NAME
, F_("GETENV:the value of execution environment variable @{name}")},
1804 { GNM_FUNC_HELP_ARG
, F_("name:the name of the environment variable")},
1805 { GNM_FUNC_HELP_NOTE
, F_("If a variable called @{name} does not exist, #N/A will be returned.") },
1806 { GNM_FUNC_HELP_NOTE
, F_("Variable names are case sensitive.") },
1807 { GNM_FUNC_HELP_EXAMPLES
, "=GETENV(\"HOME\")" },
1808 { GNM_FUNC_HELP_END
}
1812 gnumeric_getenv (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1814 char const *var
= value_peek_string (argv
[0]);
1815 char const *val
= g_getenv (var
);
1817 if (val
&& g_utf8_validate (val
, -1, NULL
))
1818 return value_new_string (val
);
1820 return value_new_error_NA (ei
->pos
);
1823 /***************************************************************************/
1825 static GnmFuncHelp
const help_get_link
[] = {
1826 { GNM_FUNC_HELP_NAME
, F_("GET.LINK:the target of the hyperlink attached to @{cell} as a string")},
1827 { GNM_FUNC_HELP_ARG
, F_("cell:the referenced cell")},
1828 { GNM_FUNC_HELP_NOTE
, F_("The value return is not updated automatically when "
1829 "the link attached to @{cell} changes but requires a"
1830 " recalculation.")},
1831 { GNM_FUNC_HELP_SEEALSO
, "HYPERLINK"},
1832 { GNM_FUNC_HELP_END
}
1836 gnumeric_get_link (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1838 GnmValue
const * const v
= argv
[0];
1840 if (VALUE_IS_CELLRANGE (v
)) {
1841 GnmCellRef
const * a
= &v
->v_range
.cell
.a
;
1842 GnmCellRef
const * b
= &v
->v_range
.cell
.b
;
1847 if (a
->col
!= b
->col
|| a
->row
!= b
->row
|| a
->sheet
!=b
->sheet
)
1848 return value_new_error_REF (ei
->pos
);
1850 sheet
= (a
->sheet
== NULL
) ? ei
->pos
->sheet
: a
->sheet
;
1851 gnm_cellpos_init_cellref (&pos
, a
, &(ei
->pos
->eval
), sheet
);
1852 lnk
= gnm_sheet_hlink_find (sheet
, &pos
);
1855 return value_new_string (gnm_hlink_get_target (lnk
));
1858 return value_new_empty ();
1861 /***************************************************************************/
1863 GnmFuncDescriptor
const info_functions
[] = {
1864 { "cell", "sr", help_cell
,
1865 gnumeric_cell
, NULL
,
1866 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_SUBSET_WITH_EXTENSIONS
, GNM_FUNC_TEST_STATUS_BASIC
},
1867 { "error.type", "E", help_error_type
,
1868 gnumeric_error_type
, NULL
,
1869 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1870 { "info", "s", help_info
,
1871 gnumeric_info
, NULL
,
1872 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1873 { "isblank", "E", help_isblank
,
1874 gnumeric_isblank
, NULL
,
1875 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1876 { "iserr", "E", help_iserr
,
1877 gnumeric_iserr
, NULL
,
1878 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1879 { "iserror", "E", help_iserror
,
1880 gnumeric_iserror
, NULL
,
1881 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1882 { "iseven", "f", help_iseven
,
1883 gnumeric_iseven
, NULL
,
1884 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1885 { "islogical", "E", help_islogical
,
1886 gnumeric_islogical
, NULL
,
1887 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1888 { "isna", "E", help_isna
,
1889 gnumeric_isna
, NULL
,
1890 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1891 { "isnontext", "E", help_isnontext
,
1892 gnumeric_isnontext
, NULL
,
1893 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1894 { "isnumber", "E", help_isnumber
,
1895 gnumeric_isnumber
, NULL
,
1896 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1897 { "isodd", "S", help_isodd
,
1898 gnumeric_isodd
, NULL
,
1899 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1900 { "isref", NULL
, help_isref
,
1901 NULL
, gnumeric_isref
,
1902 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1903 { "istext", "E", help_istext
,
1904 gnumeric_istext
, NULL
,
1905 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1908 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1909 { "na", "", help_na
,
1911 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1912 { "type", "?", help_type
,
1913 gnumeric_type
, NULL
,
1914 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1916 /* XL stores this in statistical ? */
1917 { "countblank", "r", help_countblank
,
1918 gnumeric_countblank
, NULL
,
1919 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1921 { "error", "s", help_error
,
1922 gnumeric_error
, NULL
,
1923 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},
1925 { "expression", "r", help_expression
,
1926 gnumeric_expression
, NULL
,
1927 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},
1928 /* XLM : looks common in charts */
1929 { "get.formula", "r", help_get_formula
,
1930 gnumeric_get_formula
, NULL
,
1931 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},
1932 { "get.link", "r", help_get_link
,
1933 gnumeric_get_link
, NULL
,
1934 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},
1935 { "isformula", "r", help_isformula
,
1936 gnumeric_isformula
, NULL
,
1937 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},
1938 { "getenv", "s", help_getenv
,
1939 gnumeric_getenv
, NULL
,
1940 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},