1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * fn-information.c: Information built-in functions
6 * Jukka-Pekka Iivonen (iivonen@iki.fi)
7 * Jody Goldberg (jody@gnome.org)
8 * Morten Welinder (terra@gnome.org)
9 * Almer S. Tigelaar (almer@gnome.org)
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses/>.
25 * Many thanks to Harlan Grove for his excellent characterization and writeup
26 * of the multitude of different potential arguments across the various
27 * different spreadsheets. Although neither the code is not his, the set of
28 * attributes, and the comments on their behviour are. Hence he holds partial
29 * copyright on the CELL implementation.
32 #include <gnumeric-config.h>
35 #include <parse-util.h>
40 #include <gnm-format.h>
42 #include <style-font.h>
46 #include <sheet-style.h>
47 #include <number-match.h>
51 #include <goffice/goffice.h>
52 #include <gnm-plugin.h>
55 #include <sys/utsname.h>
61 GNM_PLUGIN_MODULE_HEADER
;
63 /***************************************************************************/
65 static GnmFuncHelp
const help_cell
[] = {
66 { GNM_FUNC_HELP_NAME
, F_("CELL:information of @{type} about @{cell}")},
67 { GNM_FUNC_HELP_ARG
, F_("type:string specifying the type of information requested")},
68 { GNM_FUNC_HELP_ARG
, F_("cell:cell reference")},
69 { GNM_FUNC_HELP_DESCRIPTION
, F_("@{type} specifies the type of information you want to obtain:\n"
70 " address \t\tReturns the given cell reference as text.\n"
71 " col \t\tReturns the number of the column in @{cell}.\n"
72 " color \t\tReturns 0.\n"
73 " contents \t\tReturns the contents of the cell in @{cell}.\n"
74 " column \t\tReturns the number of the column in @{cell}.\n"
75 " columnwidth \tReturns the column width.\n"
76 " coord \t\tReturns the absolute address of @{cell}.\n"
77 " datatype \tsame as type\n"
78 " filename \t\tReturns the name of the file of @{cell}.\n"
79 " format \t\tReturns the code of the format of the cell.\n"
80 " formulatype \tsame as type\n"
81 " locked \t\tReturns 1 if @{cell} is locked.\n"
82 " parentheses \tReturns 1 if @{cell} contains a negative value\n"
83 " \t\tand its format displays it with parentheses.\n"
84 " prefix \t\tReturns a character indicating the horizontal\n"
85 " \t\talignment of @{cell}.\n"
86 " prefixcharacter \tsame as prefix\n"
87 " protect \t\tReturns 1 if @{cell} is locked.\n"
88 " row \t\tReturns the number of the row in @{cell}.\n"
89 " sheetname \tReturns the name of the sheet of @{cell}.\n"
90 " type \t\tReturns \"l\" if @{cell} contains a string, \n"
91 " \t\t\"v\" if it contains some other value, and \n"
92 " \t\t\"b\" if @{cell} is blank.\n"
93 " value \t\tReturns the contents of the cell in @{cell}.\n"
94 " width \t\tReturns the column width.")},
95 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
96 { GNM_FUNC_HELP_EXAMPLES
, "=CELL(\"col\",A1)" },
97 { GNM_FUNC_HELP_EXAMPLES
, "=CELL(\"width\",A1)" },
98 { GNM_FUNC_HELP_SEEALSO
, "INDIRECT"},
106 static const translate_t translate_table
[] = {
111 { "#,##0.00", ",2" },
112 { "\"$\"#,##0_);\\(\"$\"#,##0\\)", "C0" },
113 { "\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)", "C0-" },
114 { "\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)", "C2" },
115 { "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)", "C2-" },
118 { "0.00e+00", "S2" },
120 { "# ?" "?/?" "?", "G" }, /* Don't accidentally use trigraphs here. */
122 { "m/d/yy h:mm", "D4" },
123 { "mm/dd/yy", "D4" },
124 { "d-mmm-yy", "D1" },
125 { "dd-mmm-yy", "D1" },
130 { "h:mm am/pm", "D7" },
131 { "h:mm:ss am/pm", "D6" },
137 translate_cell_format (GOFormat
const *format
)
141 const int translate_table_count
= G_N_ELEMENTS (translate_table
);
144 return value_new_string ("G");
146 fmt
= go_format_as_XL (format
);
149 * TODO : What does this do in different locales ??
151 for (i
= 0; i
< translate_table_count
; i
++) {
152 const translate_t
*t
= &translate_table
[i
];
154 if (!g_ascii_strcasecmp (fmt
, t
->format
)) {
155 return value_new_string (t
->output
);
159 #warning "FIXME: CELL('format',...) isn't right"
161 * 1. The above lookup should be done with respect to just the
162 * first of format alternatives.
163 * 2. I don't think colour should count.
164 * 3. We should add a dash if there are more alternatives.
167 return value_new_string ("G");
170 /* TODO : turn this into a range based routine */
172 gnumeric_cell (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
174 char const *info_type
= value_peek_string (argv
[0]);
175 GnmCellRef
const *ref
= &argv
[1]->v_range
.cell
.a
;
176 const Sheet
*sheet
= eval_sheet (ref
->sheet
, ei
->pos
->sheet
);
179 * CELL translates its keywords (ick)
187 nomfichier - filename
188 parentheses - parentheses
194 /* from CELL - limited usefulness! */
195 if (!g_ascii_strcasecmp(info_type
, "address")) {
197 GnmConventionsOut out
;
198 out
.accum
= g_string_new (NULL
);
199 out
.pp
= parse_pos_init_evalpos (&pp
, ei
->pos
);
200 out
.convs
= gnm_conventions_default
;
201 cellref_as_string (&out
, ref
, TRUE
);
202 return value_new_string_nocopy (g_string_free (out
.accum
, FALSE
));
204 } else if (!g_ascii_strcasecmp(info_type
, "sheetname")) {
205 return value_new_string (sheet
->name_unquoted
);
207 /* from later 123 versions - USEFUL! */
208 } else if (!g_ascii_strcasecmp(info_type
, "coord")) {
210 GnmConventionsOut out
;
211 out
.accum
= g_string_new (NULL
);
212 out
.pp
= parse_pos_init_evalpos (&pp
, ei
->pos
);
213 out
.convs
= gnm_conventions_default
;
214 cellref_as_string (&out
, ref
, TRUE
);
215 return value_new_string_nocopy (g_string_free (out
.accum
, FALSE
));
217 /* from CELL - pointless - use COLUMN instead! */
218 } else if (!g_ascii_strcasecmp (info_type
, "col") ||
219 !g_ascii_strcasecmp (info_type
, "column")) {
220 return value_new_int (ref
->col
+ 1);
222 /* from CELL - pointless - use ROW instead! */
223 } else if (!g_ascii_strcasecmp (info_type
, "row")) {
224 return value_new_int (ref
->row
+ 1);
226 /* from CELL - limited usefulness
227 * NOTE: differences between Excel & 123 - Excel's returns 1 whenever
228 * there's a color specified for EITHER positive OR negative values
229 * in the number format, e.g., 1 for format "[Black]0;-0;0" but not
230 * for format "0;-0;[Green]0"
231 * Another place where Excel doesn't conform to its documentation!
233 } else if (!g_ascii_strcasecmp (info_type
, "color")) {
234 /* See 1.7.6 for old version. */
235 return value_new_int (0);
237 /* absolutely pointless - compatibility only */
238 } else if (!g_ascii_strcasecmp (info_type
, "contents") ||
239 !g_ascii_strcasecmp (info_type
, "value")) {
240 GnmCell
const *cell
=
241 sheet_cell_get (sheet
, ref
->col
, ref
->row
);
242 if (cell
&& cell
->value
)
243 return value_dup (cell
->value
);
244 return value_new_empty ();
246 /* from CELL - limited usefulness!
247 * A testament to Microsoft's hypocracy! They could include this from
248 * 123R2.2 (it wasn't in 123R2.0x), modify it in Excel 4.0 to include
249 * the worksheet name, but they can't make any other changes to CELL?!
251 } else if (!g_ascii_strcasecmp (info_type
, "filename")) {
252 char const *name
= go_doc_get_uri (GO_DOC (sheet
->workbook
));
255 return value_new_string ("");
257 return value_new_string (name
);
260 /* Backwards compatibility w/123 - unnecessary */
261 } else if (!g_ascii_strcasecmp (info_type
, "format")) {
262 GnmStyle
const *mstyle
=
263 sheet_style_get (sheet
, ref
->col
, ref
->row
);
265 return translate_cell_format (gnm_style_get_format (mstyle
));
268 /* Backwards compatibility w/123 - unnecessary */
269 } else if (!g_ascii_strcasecmp (info_type
, "parentheses")) {
270 /* See 1.7.6 for old version. */
271 return value_new_int (0);
274 /* Backwards compatibility w/123 - unnecessary */
275 } else if (!g_ascii_strcasecmp (info_type
, "prefix") ||
276 !g_ascii_strcasecmp (info_type
, "prefixcharacter")) {
277 GnmStyle
const *mstyle
=
278 sheet_style_get (sheet
, ref
->col
, ref
->row
);
279 GnmCell
const *cell
=
280 sheet_cell_get (sheet
, ref
->col
, ref
->row
);
282 if (cell
&& cell
->value
&& VALUE_IS_STRING (cell
->value
)) {
283 switch (gnm_style_get_align_h (mstyle
)) {
284 case GNM_HALIGN_GENERAL
:
285 case GNM_HALIGN_LEFT
:
286 case GNM_HALIGN_JUSTIFY
:
287 case GNM_HALIGN_DISTRIBUTED
:
288 return value_new_string ("'");
289 case GNM_HALIGN_RIGHT
: return value_new_string ("\"");
290 case GNM_HALIGN_CENTER_ACROSS_SELECTION
:
291 case GNM_HALIGN_CENTER
: return value_new_string ("^");
292 case GNM_HALIGN_FILL
: return value_new_string ("\\");
293 default : return value_new_string ("");
296 return value_new_string ("");
299 } else if (!g_ascii_strcasecmp (info_type
, "locked") ||
300 !g_ascii_strcasecmp (info_type
, "protect")) {
301 GnmStyle
const *mstyle
=
302 sheet_style_get (sheet
, ref
->col
, ref
->row
);
303 return value_new_int (gnm_style_get_contents_locked (mstyle
) ? 1 : 0);
305 /* different characteristics grouped for efficiency
306 * TYPE needed for backward compatibility w/123 but otherwise useless
307 * DATATYPE and FORMULATYPE are options in later 123 versions' @CELL
308 * no need for them but included to make 123 conversion easier
309 Case "datatype", "formulatype", "type"
312 rv = IIf( t = "f" And rng.HasFormula, "f", "" )
314 If rng.formula = "" Then
316 ElseIf IsNumeric("0" & CStr(rng.Value)) _
317 Or (t = "t" And IsError(rng.Value)) Then
319 ElseIf rng.Value = CVErr(xlErrNA) Then
321 ElseIf IsError(rng.Value) Then
329 } else if (!g_ascii_strcasecmp (info_type
, "type") ||
330 !g_ascii_strcasecmp (info_type
, "datatype") ||
331 !g_ascii_strcasecmp (info_type
, "formulatype")) {
332 GnmCell
const *cell
=
333 sheet_cell_get (sheet
, ref
->col
, ref
->row
);
334 if (cell
&& cell
->value
) {
335 if (VALUE_IS_STRING (cell
->value
))
336 return value_new_string ("l");
338 return value_new_string ("v");
340 return value_new_string ("b");
343 } else if (!g_ascii_strcasecmp (info_type
, "width") ||
344 !g_ascii_strcasecmp (info_type
, "columnwidth")) {
345 ColRowInfo
const *info
=
346 sheet_col_get_info (sheet
, ref
->col
);
350 charwidth
= gnm_font_default_width
;
351 cellwidth
= info
->size_pts
;
353 return value_new_int (rint (cellwidth
/ charwidth
));
356 return value_new_error_VALUE (ei
->pos
);
361 *extension to CELL providing 123 @CELL/@CELLPOINTER functionality as
362 *well as access to most Range properties
363 *1st arg determines the property of characteristic being sought
364 *2nd arg [OPTIONAL] specifies cell reference - AcitveCell if missing
365 *3rd arg [OPTIONAL] specifies whether to return an array or not
366 * True = return array result for .Areas(1)
367 * False/missing = return scalar result for .Areas(1).Cells(1, 1)
371 Optional rng As Variant
, _
372 Optional rar As Boolean
= False _
374 Dim ws As Worksheet
, wb As Workbook
, rv As Variant
375 Dim i As Long
, j As Long
, m As Long
, n As Long
, t As String
377 Application
.Volatile True
379 If TypeOf rng Is Range Then
381 Set rng
= rng
.Areas(1)
383 Set rng
= rng
.Areas(1).Cells(1, 1)
385 ElseIf
IsMissing(rng
) Then
388 ExtCell
= CVErr(xlErrRef
)
395 n
= rng
.Columns
.Count
398 Set ws
= rng
.Worksheet
403 Case
"across" /* from later 123 versions - limited usefulness! */
408 rng
.Cells(i
, j
).HorizontalAlignment
= _
409 xlHAlignCenterAcrossSelection _
415 rng
.HorizontalAlignment
= _
416 xlHAlignCenterAcrossSelection _
420 Case
"backgroundcolor" /* from later 123 versions - USEFUL! */
424 rv(i
, j
) = rng
.Cells(i
, j
).Interior
.ColorIndex
428 rv
= rng
.Interior
.ColorIndex
431 Case
"bold" /* from later 123 versions - USEFUL! */
435 rv(i
, j
) = CLng(rng
.Cells(i
, j
).Font
.Bold
)
439 rv
= CLng(rng
.Font
.Bold
)
443 Case
"bottomborder" /* from later 123 versions - USEFUL! */
444 /* Note: many possible return values! wrap inside SIGN to test T/F */
449 rng
.Cells(i
, j
).Borders(xlEdgeBottom
).LineStyle
- _
454 rv
= rng
.Borders(xlEdgeBottom
).LineStyle
- xlLineStyleNone
457 Case
"bottombordercolor" /* from later 123 versions - USEFUL! */
462 rng
.Cells(i
, j
).Borders(xlEdgeBottom
).ColorIndex
466 rv
= rng
.Borders(xlEdgeBottom
).ColorIndex
473 rv(i
, j
) = rng
.Cells(i
, j
).EntireColumn
.Hidden
477 rv
= rng
.EntireColumn
.Hidden
484 If Not rng
.Cells(i
, j
).Comment Is Nothing Then
485 rv(i
, j
) = rng
.Cells(i
, j
).Comment
.text
492 If Not rng
.Comment Is Nothing Then
493 rv
= rng
.Comment
.text
499 Case
"currentarray" /* NOTE: returns Range addresses! */
503 rv(i
, j
) = rng
.Cells(i
, j
).CurrentArray
.Address
507 rv
= rng
.CurrentArray
.Address
510 Case
"currentregion" /* NOTE: returns Range addresses! */
514 rv(i
, j
) = rng
.Cells(i
, j
).CurrentRegion
.Address
518 rv
= rng
.CurrentRegion
.Address
521 Case
"filedate" /* from later 123 versions - limited usefulness! */
522 t
= wb
.BuiltinDocumentProperties("Last Save Time") /* invariant! */
534 Case
"fontface", "fontname", "typeface" /* from later 123 versions */
538 rv(i
, j
) = rng
.Cells(i
, j
).Font
.Name
545 Case
"fontsize", "pitch", "typesize" /* from later 123 versions */
549 rv(i
, j
) = rng
.Cells(i
, j
).Font
.Size
560 rv(i
, j
) = rng
.Cells(i
, j
).formula
567 Case
"formulaarray" /* questionable usefulness */
571 rv(i
, j
) = rng
.Cells(i
, j
).FormulaArray
575 rv
= rng
.FormulaArray
582 rv(i
, j
) = CLng(rng
.Cells(i
, j
).FormulaHidden
)
586 rv
= CLng(rng
.FormulaHidden
)
593 rv(i
, j
) = rng
.Cells(i
, j
).FormulaLocal
597 rv
= rng
.FormulaLocal
604 rv(i
, j
) = rng
.Cells(i
, j
).FormulaR1C1
611 Case
"formular1c1local"
615 rv(i
, j
) = rng
.Cells(i
, j
).FormulaR1C1Local
619 rv
= rng
.FormulaR1C1Local
622 Case
"halign", "horizontalalignment" /* from later 123 versions */
623 /* Note: different return values than 123. 0 = general alignment */
628 rng
.Cells(i
, j
).HorizontalAlignment
- _
633 rv
= rng
.HorizontalAlignment
- xlHAlignGeneral
640 rv(i
, j
) = CLng(rng
.Cells(i
, j
).HasArray
)
644 rv
= CLng(rng
.HasArray
)
651 rv(i
, j
) = CLng(rng
.Cells(i
, j
).HasFormula
)
655 rv
= CLng(rng
.HasFormula
)
658 Case
"hashyperlink", "hashyperlinks"
662 rv(i
, j
) = CLng(rng
.Cells(i
, j
).Hyperlinks
.Count
> 0)
666 rv
= CLng(rng
.Hyperlinks
.Count
> 0)
669 Case
"height", "rowheight" /* from later 123 versions - USEFUL! */
673 rv(i
, j
) = rng
.Cells(i
, j
).Height
680 Case
"hidden" /* see ColumnHidden and RowHidden - this is less useful */
684 rv(i
, j
) = CLng(rng
.Cells(i
, j
).Hidden
)
688 rv
= CLng(rng
.Hidden
)
691 Case
"hyperlinkaddress"
695 rv(i
, j
) = rng
.Cells(i
, j
).Hyperlinks(1).Address
699 rv
= rng
.Hyperlinks(1).Address
706 rv(i
, j
) = rng
.Cells(i
, j
).rng
.IndentLevel
710 rv
= rng
.rng
.IndentLevel
713 Case
"italic" /* from later 123 versions - USEFUL! */
717 rv(i
, j
) = CLng(rng
.Cells(i
, j
).Font
.Italic
)
721 rv
= CLng(rng
.Font
.Italic
)
728 rv(i
, j
) = rng
.Cells(i
, j
).Left
735 Case
"leftborder" /* from later 123 versions */
736 /* Note: many possible return values! wrap inside SIGN to test T/F */
741 rng
.Cells(i
, j
).Borders(xlEdgeLeft
).LineStyle
- _
746 rv
= rng
.Borders(xlEdgeLeft
).LineStyle
- xlLineStyleNone
749 Case
"leftbordercolor" /* from later 123 versions */
754 rng
.Cells(i
, j
).Borders(xlEdgeLeft
).ColorIndex
758 rv
= rng
.Borders(xlEdgeLeft
).ColorIndex
761 Case
"mergearea" /* NOTE: returns Range addresses! */
765 rv(i
, j
) = rng
.Cells(i
, j
).MergeArea
.Address
769 rv
= rng
.MergeArea
.Address
776 rv(i
, j
) = CLng(rng
.Cells(i
, j
).MergeCells
)
780 rv
= CLng(rng
.MergeCells
)
787 rv(i
, j
) = rng
.Cells(i
, j
).Name
798 rv(i
, j
) = rng
.Cells(i
, j
).NumberFormat
802 rv
= rng
.NumberFormat
805 Case
"numberformatlocal"
809 rv(i
, j
) = rng
.Cells(i
, j
).NumberFormatLocal
813 rv
= rng
.NumberFormatLocal
816 Case
"orientation", "rotation" /* from later 123 versions */
820 rv(i
, j
) = rng
.Cells(i
, j
).Orientation
827 Case
"pattern" /* from later 123 versions */
832 rng
.Cells(i
, j
).Interior
.Pattern
- _
837 rv
= rng
.Interior
.Pattern
- xlPatternNone
840 Case
"patterncolor" /* from later 123 versions */
845 rng
.Cells(i
, j
).Interior
.PatternColorIndex
849 rv
= rng
.Interior
.PatternColorIndex
852 Case
"rightborder" /* from later 123 versions */
853 /* Note: many possible return values! wrap inside SIGN to test T/F */
858 rng
.Cells(i
, j
).Borders(xlEdgeRight
).LineStyle
- _
863 rv
= rng
.Borders(xlEdgeRight
).LineStyle
- xlLineStyleNone
866 Case
"rightbordercolor" /* from later 123 versions */
871 rng
.Cells(i
, j
).Borders(xlEdgeRight
).ColorIndex
875 rv
= rng
.Borders(xlEdgeRight
).ColorIndex
882 rv(i
, j
) = CLng(rng
.Cells(i
, j
).EntireRow
.Hidden
)
886 rv
= CLng(rng
.EntireRow
.Hidden
)
890 /* Who needs consistency?! Why doesn't this return a Range object? */
891 t
= ws
.ScrollArea
/* invariant! */
903 Case
"sheet", "worksheet" /* from later 123 versions - USEFUL! */
904 t
= ws
.Index
/* invariant! */
916 Case
"sheetname", "worksheetname" /* from later 123 versions - USEFUL! */
917 t
= ws
.Name
/* invariant */
929 Case
"sheetcount", "sheetscount", "worksheetcount", "worksheetscount"
930 t
= wb
.Worksheets
.Count
/* invariant */
946 rv(i
, j
) = CLng(rng
.Cells(i
, j
).ShrinkToFit
)
950 rv
= CLng(rng
.ShrinkToFit
)
957 rv(i
, j
) = rng
.Cells(i
, j
).Style
.Name
964 Case
"text" /* USEFUL! */
968 rv(i
, j
) = rng
.Cells(i
, j
).text
975 Case
"textcolor" /* from later 123 versions - USEFUL! */
979 rv(i
, j
) = rng
.Cells(i
, j
).Font
.ColorIndex
983 rv
= rng
.Font
.ColorIndex
990 rv(i
, j
) = rng
.Cells(i
, j
).Top
997 Case
"topborder" /* from later 123 versions */
998 /* Note: many possible return values! wrap inside SIGN to test T/F */
1003 rng
.Cells(i
, j
).Borders(xlEdgeTop
).LineStyle
- _
1008 rv
= rng
.Borders(xlEdgeTop
).LineStyle
- xlLineStyleNone
1011 Case
"topbordercolor" /* from later 123 versions */
1016 rng
.Cells(i
, j
).Borders(xlEdgeTop
).ColorIndex
1020 rv
= rng
.Borders(xlEdgeTop
).ColorIndex
1023 Case
"underline" /* from later 123 versions - USEFUL! */
1024 /* Note: many possible return values! wrap inside SIGN to test T/F */
1029 rng
.Cells(i
, j
).Font
.Underline
- _
1030 xlUnderlineStyleNone
1034 rv
= rng
.Font
.Underline
- xlUnderlineStyleNone
1037 Case
"usedrange" /* NOTE: returns Range addresses! */
1038 t
= ws
.UsedRange
.Address
/* invariant */
1050 Case
"usestandardheight"
1054 rv(i
, j
) = CLng(rng
.Cells(i
, j
).UseStandardHeight
)
1058 rv
= CLng(rng
.UseStandardHeight
)
1061 Case
"usestandardwidth"
1065 rv(i
, j
) = CLng(rng
.Cells(i
, j
).UseStandardWidth
)
1069 rv
= CLng(rng
.UseStandardWidth
)
1072 Case
"valign", "verticalalignment" /* from later 123 versions */
1073 /* Note: different return values than 123. 0 = Bottom-aligned */
1078 rng
.Cells(i
, j
).VerticalAlignment
- _
1083 rv
= rng
.VerticalAlignment
- xlVAlignBottom
1086 Case
"visible", "sheetvisible", "worksheetvisible"
1087 t
= CLng(ws
.Visible
) /* invariant */
1099 Case
"workbookfullname" /* same as FileName in later 123 versions */
1100 t
= wb
.FullName
/* invariant */
1113 t
= wb
.Name
/* invariant */
1126 t
= wb
.path
/* invariant */
1138 Case
"wrap", "wraptext" /* from later 123 versions */
1142 rv(i
, j
) = CLng(rng
.Cells(i
, j
).WrapText
)
1146 rv
= CLng(rng
.WrapText
)
1149 Case Else
/* invalid property/characteristic */
1150 t
= CVErr(xlErrValue
) /* invariant */
1168 /***************************************************************************/
1170 static GnmFuncHelp
const help_expression
[] = {
1171 { GNM_FUNC_HELP_NAME
, F_("EXPRESSION:expression in @{cell} as a string")},
1172 { GNM_FUNC_HELP_ARG
, F_("cell:a cell reference")},
1173 { GNM_FUNC_HELP_NOTE
, F_("If @{cell} contains no expression, EXPRESSION returns empty.")},
1174 { GNM_FUNC_HELP_SEEALSO
, "TEXT"},
1175 { GNM_FUNC_HELP_END
}
1179 gnumeric_expression (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1181 GnmValue
const * const v
= argv
[0];
1182 if (VALUE_IS_CELLRANGE (v
)) {
1184 GnmCellRef
const * a
= &v
->v_range
.cell
.a
;
1185 GnmCellRef
const * b
= &v
->v_range
.cell
.b
;
1187 if (a
->col
!= b
->col
|| a
->row
!= b
->row
|| a
->sheet
!=b
->sheet
)
1188 return value_new_error_REF (ei
->pos
);
1190 cell
= sheet_cell_get (eval_sheet (a
->sheet
, ei
->pos
->sheet
),
1193 if (cell
&& gnm_cell_has_expr (cell
)) {
1195 char *expr_string
= gnm_expr_top_as_string
1197 parse_pos_init_cell (&pos
, cell
),
1198 gnm_conventions_default
);
1199 return value_new_string_nocopy (expr_string
);
1203 return value_new_empty ();
1205 /***************************************************************************/
1207 static GnmFuncHelp
const help_get_formula
[] = {
1208 { GNM_FUNC_HELP_NAME
, F_("GET.FORMULA:the formula in @{cell} as a string")},
1209 { GNM_FUNC_HELP_ARG
, F_("cell:the referenced cell")},
1210 { GNM_FUNC_HELP_ODF
, F_("GET.FORMULA is the OpenFormula function FORMULA.") },
1211 { GNM_FUNC_HELP_EXAMPLES
, F_("If A1 is empty and A2 contains =B1+B2, then\n"
1212 "GET.FORMULA(A2) yields '=B1+B2' and\n"
1213 "GET.FORMULA(A1) yields ''.") },
1214 { GNM_FUNC_HELP_SEEALSO
, "EXPRESSION,ISFORMULA"},
1215 { GNM_FUNC_HELP_END
}
1219 gnumeric_get_formula (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1221 GnmValue
const * const v
= argv
[0];
1222 if (VALUE_IS_CELLRANGE (v
)) {
1224 GnmCellRef
const * a
= &v
->v_range
.cell
.a
;
1225 GnmCellRef
const * b
= &v
->v_range
.cell
.b
;
1227 if (a
->col
!= b
->col
|| a
->row
!= b
->row
|| a
->sheet
!=b
->sheet
)
1228 return value_new_error_REF (ei
->pos
);
1230 cell
= sheet_cell_get (eval_sheet (a
->sheet
, ei
->pos
->sheet
),
1233 if (cell
&& gnm_cell_has_expr (cell
)) {
1234 GnmConventionsOut out
;
1236 out
.accum
= g_string_new ("=");
1237 out
.pp
= parse_pos_init_cell (&pp
, cell
);
1238 out
.convs
= gnm_conventions_default
;
1239 gnm_expr_top_as_gstring (cell
->base
.texpr
, &out
);
1240 return value_new_string_nocopy (g_string_free (out
.accum
, FALSE
));
1244 return value_new_empty ();
1247 /***************************************************************************/
1249 static GnmFuncHelp
const help_isformula
[] = {
1250 { GNM_FUNC_HELP_NAME
, F_("ISFORMULA:TRUE if @{cell} contains a formula")},
1251 { GNM_FUNC_HELP_ARG
, F_("cell:the referenced cell")},
1252 { GNM_FUNC_HELP_ODF
, F_("ISFORMULA is OpenFormula compatible.") },
1253 { GNM_FUNC_HELP_SEEALSO
, "GET.FORMULA"},
1254 { GNM_FUNC_HELP_END
}
1258 gnumeric_isformula (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1260 GnmValue
const * const v
= argv
[0];
1261 if (VALUE_IS_CELLRANGE (v
)) {
1263 GnmCellRef
const * a
= &v
->v_range
.cell
.a
;
1264 GnmCellRef
const * b
= &v
->v_range
.cell
.b
;
1266 if (a
->col
!= b
->col
|| a
->row
!= b
->row
|| a
->sheet
!=b
->sheet
)
1267 return value_new_error_REF (ei
->pos
);
1269 cell
= sheet_cell_get (eval_sheet (a
->sheet
, ei
->pos
->sheet
),
1271 return value_new_bool (cell
&& gnm_cell_has_expr (cell
));
1274 return value_new_error_REF (ei
->pos
);
1278 /***************************************************************************/
1280 static GnmFuncHelp
const help_countblank
[] = {
1281 { GNM_FUNC_HELP_NAME
, F_("COUNTBLANK:the number of blank cells in @{range}")},
1282 { GNM_FUNC_HELP_ARG
, F_("range:a cell range")},
1283 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1284 { GNM_FUNC_HELP_EXAMPLES
, F_("COUNTBLANK(A1:A20) returns the number of blank cell in A1:A20.") },
1285 { GNM_FUNC_HELP_SEEALSO
, "COUNT"},
1286 { GNM_FUNC_HELP_END
}
1290 cb_countblank (GnmValueIter
const *iter
, gpointer user
)
1292 GnmValue
const *v
= iter
->v
;
1294 if (VALUE_IS_STRING (v
) && value_peek_string (v
)[0] == 0)
1295 ; /* Nothing -- the empty string is blank. */
1296 else if (VALUE_IS_EMPTY (v
))
1299 *((int *)user
) -= 1;
1305 gnumeric_countblank (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1307 GnmValue
const *v
= argv
[0];
1309 value_area_get_width (v
, ei
->pos
) *
1310 value_area_get_height (v
, ei
->pos
);
1313 if (VALUE_IS_CELLRANGE (v
)) {
1315 Sheet
*start_sheet
, *end_sheet
;
1317 gnm_rangeref_normalize (&v
->v_range
.cell
, ei
->pos
,
1318 &start_sheet
, &end_sheet
, &r
);
1320 if (start_sheet
!= end_sheet
&& end_sheet
!= NULL
)
1321 nsheets
= 1 + abs (end_sheet
->index_in_wb
-
1322 start_sheet
->index_in_wb
);
1327 value_area_foreach (v
, ei
->pos
, CELL_ITER_IGNORE_BLANK
,
1328 &cb_countblank
, &count
);
1330 return value_new_int (count
);
1333 /***************************************************************************/
1335 static GnmFuncHelp
const help_info
[] = {
1336 { GNM_FUNC_HELP_NAME
, F_("INFO:information about the current operating environment "
1337 "according to @{type}")},
1338 { GNM_FUNC_HELP_ARG
, F_("type:string giving the type of information requested")},
1339 { GNM_FUNC_HELP_DESCRIPTION
, F_("INFO returns information about the current operating "
1340 "environment according to @{type}:\n"
1341 " memavail \t\tReturns the amount of memory available, bytes.\n"
1342 " memused \tReturns the amount of memory used (bytes).\n"
1343 " numfile \t\tReturns the number of active worksheets.\n"
1344 " osversion \t\tReturns the operating system version.\n"
1345 " recalc \t\tReturns the recalculation mode (automatic).\n"
1346 " release \t\tReturns the version of Gnumeric as text.\n"
1347 " system \t\tReturns the name of the environment.\n"
1348 " totmem \t\tReturns the amount of total memory available.")},
1349 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1350 { GNM_FUNC_HELP_EXAMPLES
, "=INFO(\"system\")" },
1351 { GNM_FUNC_HELP_EXAMPLES
, "=INFO(\"release\")" },
1352 { GNM_FUNC_HELP_EXAMPLES
, "=INFO(\"numfile\")" },
1353 { GNM_FUNC_HELP_SEEALSO
, "CELL"},
1354 { GNM_FUNC_HELP_END
}
1358 gnumeric_info (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1360 char const * const info_type
= value_peek_string (argv
[0]);
1361 if (!g_ascii_strcasecmp (info_type
, "directory")) {
1362 /* Path of the current directory or folder. */
1363 return value_new_error (ei
->pos
, _("Unimplemented"));
1364 } else if (!g_ascii_strcasecmp (info_type
, "memavail")) {
1365 /* Amount of memory available, in bytes. */
1366 return value_new_int (15 << 20); /* Good enough... */
1367 } else if (!g_ascii_strcasecmp (info_type
, "memused")) {
1368 /* Amount of memory being used for data. */
1369 return value_new_int (1 << 20); /* Good enough... */
1370 } else if (!g_ascii_strcasecmp (info_type
, "numfile")) {
1371 /* Number of active worksheets. */
1372 return value_new_int (1); /* Good enough... */
1373 } else if (!g_ascii_strcasecmp (info_type
, "origin")) {
1374 /* Absolute A1-style reference, as text, prepended with "$A:"
1375 * for Lotus 1-2-3 release 3.x compatibility. Returns the cell
1376 * reference of the top and leftmost cell visible in the
1377 * window, based on the current scrolling position.
1379 return value_new_error (ei
->pos
, _("Unimplemented"));
1380 } else if (!g_ascii_strcasecmp (info_type
, "osversion")) {
1382 /* Current operating system version, as text. */
1383 struct utsname unamedata
;
1385 if (uname (&unamedata
) == -1)
1386 return value_new_error (ei
->pos
,
1387 _("Unknown version"));
1389 char *tmp
= g_strdup_printf (_("%s version %s"),
1392 return value_new_string_nocopy (tmp
);
1394 #elif defined(G_OS_WIN32)
1396 return value_new_string ("Windows (32-bit) NT 5.01");
1398 // Nothing -- go to catch-all
1400 } else if (!g_ascii_strcasecmp (info_type
, "recalc")) {
1401 /* Current recalculation mode; returns "Automatic" or "Manual". */
1402 Workbook
const *wb
= ei
->pos
->sheet
->workbook
;
1403 return value_new_string (
1404 workbook_get_recalcmode (wb
) ? _("Automatic") : _("Manual"));
1405 } else if (!g_ascii_strcasecmp (info_type
, "release")) {
1406 /* Version of Gnumeric (Well, Microsoft Excel), as text. */
1407 return value_new_string (GNM_VERSION_FULL
);
1408 } else if (!g_ascii_strcasecmp (info_type
, "system")) {
1410 /* Name of the operating environment. */
1411 struct utsname unamedata
;
1413 if (uname (&unamedata
) == -1)
1414 return value_new_error (ei
->pos
, _("Unknown system"));
1416 return value_new_string (unamedata
.sysname
);
1417 #elif defined(G_OS_WIN32)
1418 return value_new_string ("pcdos"); /* seems constant */
1420 // Nothing -- go to catch-all
1422 } else if (!g_ascii_strcasecmp (info_type
, "totmem")) {
1423 /* Total memory available, including memory already in use, in
1426 return value_new_int (16 << 20); /* Good enough... */
1429 return value_new_error (ei
->pos
, _("Unknown info_type"));
1432 /***************************************************************************/
1434 static GnmFuncHelp
const help_iserror
[] = {
1435 { GNM_FUNC_HELP_NAME
, F_("ISERROR:TRUE if @{value} is any error value")},
1436 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1437 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1438 { GNM_FUNC_HELP_EXAMPLES
, "=ISERROR(NA())" },
1439 { GNM_FUNC_HELP_EXAMPLES
, "=ISERROR(5/0)" },
1440 { GNM_FUNC_HELP_SEEALSO
, "ISERR,ISNA"},
1441 { GNM_FUNC_HELP_END
}
1445 gnumeric_iserror (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1447 return value_new_bool (VALUE_IS_ERROR (argv
[0]));
1450 /***************************************************************************/
1452 static GnmFuncHelp
const help_isna
[] = {
1453 { GNM_FUNC_HELP_NAME
, F_("ISNA:TRUE if @{value} is the #N/A error value")},
1454 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1455 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1456 { GNM_FUNC_HELP_EXAMPLES
, "=ISNA(NA())" },
1457 { GNM_FUNC_HELP_EXAMPLES
, "=ISNA(5/0)" },
1458 { GNM_FUNC_HELP_SEEALSO
, "NA"},
1459 { GNM_FUNC_HELP_END
}
1463 * We need to operator directly in the input expression in order to bypass
1464 * the error handling mechanism
1467 gnumeric_isna (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1469 return value_new_bool (value_error_classify (argv
[0]) == GNM_ERROR_NA
);
1472 /***************************************************************************/
1474 static GnmFuncHelp
const help_iserr
[] = {
1475 { GNM_FUNC_HELP_NAME
, F_("ISERR:TRUE if @{value} is any error value except #N/A")},
1476 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1477 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1478 { GNM_FUNC_HELP_EXAMPLES
, "=ISERR(NA())" },
1479 { GNM_FUNC_HELP_EXAMPLES
, "=ISERR(5/0)" },
1480 { GNM_FUNC_HELP_SEEALSO
, "ISERROR"},
1481 { GNM_FUNC_HELP_END
}
1485 gnumeric_iserr (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1487 return value_new_bool (VALUE_IS_ERROR (argv
[0]) &&
1488 value_error_classify (argv
[0]) != GNM_ERROR_NA
);
1491 /***************************************************************************/
1493 static GnmFuncHelp
const help_error_type
[] = {
1494 { GNM_FUNC_HELP_NAME
, F_("ERROR.TYPE:the type of @{error}")},
1495 { GNM_FUNC_HELP_ARG
, F_("error:an error")},
1496 { GNM_FUNC_HELP_DESCRIPTION
, F_("ERROR.TYPE returns an error number corresponding to the given "
1497 "error value. The error numbers for error values are:\n\n"
1504 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1505 { GNM_FUNC_HELP_EXAMPLES
, "=ERROR.TYPE(NA())" },
1506 { GNM_FUNC_HELP_EXAMPLES
, "=ERROR.TYPE(ERROR(\"#X\"))" },
1507 { GNM_FUNC_HELP_SEEALSO
, "ISERROR"},
1508 { GNM_FUNC_HELP_END
}
1512 gnumeric_error_type (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1514 switch (value_error_classify (argv
[0])) {
1515 case GNM_ERROR_NULL
: return value_new_int (1);
1516 case GNM_ERROR_DIV0
: return value_new_int (2);
1517 case GNM_ERROR_VALUE
: return value_new_int (3);
1518 case GNM_ERROR_REF
: return value_new_int (4);
1519 case GNM_ERROR_NAME
: return value_new_int (5);
1520 case GNM_ERROR_NUM
: return value_new_int (6);
1521 case GNM_ERROR_NA
: return value_new_int (7);
1523 return value_new_error_NA (ei
->pos
);
1527 /***************************************************************************/
1529 static GnmFuncHelp
const help_na
[] = {
1530 { GNM_FUNC_HELP_NAME
, F_("NA:the error value #N/A")},
1531 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1532 { GNM_FUNC_HELP_EXAMPLES
, "=NA()" },
1533 { GNM_FUNC_HELP_EXAMPLES
, "=ISNA(NA())" },
1534 { GNM_FUNC_HELP_SEEALSO
, "ISNA"},
1535 { GNM_FUNC_HELP_END
}
1540 gnumeric_na (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1542 return value_new_error_NA (ei
->pos
);
1545 /***************************************************************************/
1547 static GnmFuncHelp
const help_error
[] = {
1548 { GNM_FUNC_HELP_NAME
, F_("ERROR:the error with the given @{name}")},
1549 { GNM_FUNC_HELP_ARG
, F_("name:string")},
1550 { GNM_FUNC_HELP_EXAMPLES
, "=ERROR(\"#N/A\")" },
1551 { GNM_FUNC_HELP_EXAMPLES
, "=ISNA(ERROR(\"#N/A\"))" },
1552 { GNM_FUNC_HELP_SEEALSO
, "ISERROR"},
1553 { GNM_FUNC_HELP_END
}
1557 gnumeric_error (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1559 return value_new_error (ei
->pos
, value_peek_string (argv
[0]));
1562 /***************************************************************************/
1564 static GnmFuncHelp
const help_isblank
[] = {
1565 { GNM_FUNC_HELP_NAME
, F_("ISBLANK:TRUE if @{value} is blank")},
1566 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1567 { GNM_FUNC_HELP_DESCRIPTION
, F_("This function checks if a value is blank. Empty cells are blank, but empty strings are not.")},
1568 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1569 { GNM_FUNC_HELP_EXAMPLES
, "=ISBLANK(\"\")" },
1570 { GNM_FUNC_HELP_END
}
1574 gnumeric_isblank (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1576 return value_new_bool (VALUE_IS_EMPTY (argv
[0]));
1579 /***************************************************************************/
1581 static GnmFuncHelp
const help_iseven
[] = {
1582 { GNM_FUNC_HELP_NAME
, F_("ISEVEN:TRUE if @{n} is even")},
1583 { GNM_FUNC_HELP_ARG
, F_("n:number")},
1584 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1585 { GNM_FUNC_HELP_EXAMPLES
, "=ISEVEN(4)" },
1586 { GNM_FUNC_HELP_SEEALSO
, "ISODD"},
1587 { GNM_FUNC_HELP_END
}
1591 gnumeric_iseven (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1593 gnm_float x
= value_get_as_float (argv
[0]);
1594 gnm_float r
= gnm_fmod (gnm_abs (x
), 2);
1596 /* If x is too big, this will always be true. */
1597 return value_new_bool (r
< 1);
1600 /***************************************************************************/
1602 static GnmFuncHelp
const help_islogical
[] = {
1603 { GNM_FUNC_HELP_NAME
, F_("ISLOGICAL:TRUE if @{value} is a logical value")},
1604 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1605 { GNM_FUNC_HELP_DESCRIPTION
, F_("This function checks if a value is either TRUE or FALSE.") },
1606 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1607 { GNM_FUNC_HELP_EXAMPLES
, "=ISLOGICAL(1)" },
1608 { GNM_FUNC_HELP_EXAMPLES
, "=ISLOGICAL(\"Gnumeric\")" },
1609 { GNM_FUNC_HELP_END
}
1613 gnumeric_islogical (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1615 return value_new_bool (VALUE_IS_BOOLEAN (argv
[0]));
1618 /***************************************************************************/
1620 static GnmFuncHelp
const help_isnontext
[] = {
1621 { GNM_FUNC_HELP_NAME
, F_("ISNONTEXT:TRUE if @{value} is not text")},
1622 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1623 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1624 { GNM_FUNC_HELP_EXAMPLES
, "=ISNONTEXT(\"Gnumeric\")" },
1625 { GNM_FUNC_HELP_SEEALSO
, "ISTEXT"},
1626 { GNM_FUNC_HELP_END
}
1630 gnumeric_isnontext (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1632 return value_new_bool (!VALUE_IS_STRING (argv
[0]));
1635 /***************************************************************************/
1637 static GnmFuncHelp
const help_isnumber
[] = {
1638 { GNM_FUNC_HELP_NAME
, F_("ISNUMBER:TRUE if @{value} is a number")},
1639 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1640 { GNM_FUNC_HELP_DESCRIPTION
, F_("This function checks if a value is a number. Neither TRUE nor FALSE are numbers for this purpose.") },
1641 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1642 { GNM_FUNC_HELP_EXAMPLES
, "=ISNUMBER(\"Gnumeric\")" },
1643 { GNM_FUNC_HELP_EXAMPLES
, "=ISNUMBER(PI())" },
1644 { GNM_FUNC_HELP_END
}
1648 gnumeric_isnumber (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1650 return value_new_bool (argv
[0] && VALUE_IS_FLOAT (argv
[0]));
1653 /***************************************************************************/
1655 static GnmFuncHelp
const help_isodd
[] = {
1656 { GNM_FUNC_HELP_NAME
, F_("ISODD:TRUE if @{n} is odd")},
1657 { GNM_FUNC_HELP_ARG
, F_("n:number")},
1658 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1659 { GNM_FUNC_HELP_EXAMPLES
, "=ISODD(3)" },
1660 { GNM_FUNC_HELP_SEEALSO
, "ISEVEN"},
1661 { GNM_FUNC_HELP_END
}
1665 gnumeric_isodd (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1667 gnm_float x
= value_get_as_float (argv
[0]);
1668 gnm_float r
= gnm_fmod (gnm_abs (x
), 2);
1670 /* If x is too big, this will always be false. */
1671 return value_new_bool (r
>= 1);
1674 /***************************************************************************/
1676 static GnmFuncHelp
const help_isref
[] = {
1677 { GNM_FUNC_HELP_NAME
, F_("ISREF:TRUE if @{value} is a reference")},
1678 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1679 { GNM_FUNC_HELP_DESCRIPTION
, F_("This function checks if a value is a cell reference.") },
1680 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1681 { GNM_FUNC_HELP_EXAMPLES
, "=ISREF(A1)" },
1682 { GNM_FUNC_HELP_END
}
1686 gnumeric_isref (GnmFuncEvalInfo
*ei
, int argc
, GnmExprConstPtr
const *argv
)
1692 return value_new_error (ei
->pos
,
1693 _("Invalid number of arguments"));
1695 v
= gnm_expr_eval (argv
[0], ei
->pos
,
1696 GNM_EXPR_EVAL_PERMIT_NON_SCALAR
|
1697 GNM_EXPR_EVAL_WANT_REF
);
1698 res
= VALUE_IS_CELLRANGE (v
);
1701 return value_new_bool (res
);
1704 /***************************************************************************/
1706 static GnmFuncHelp
const help_istext
[] = {
1707 { GNM_FUNC_HELP_NAME
, F_("ISTEXT:TRUE if @{value} is text")},
1708 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1709 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1710 { GNM_FUNC_HELP_EXAMPLES
, "=ISTEXT(\"Gnumeric\")" },
1711 { GNM_FUNC_HELP_EXAMPLES
, "=ISTEXT(34)" },
1712 { GNM_FUNC_HELP_SEEALSO
, "ISNONTEXT"},
1713 { GNM_FUNC_HELP_END
}
1717 gnumeric_istext (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1719 return value_new_bool (VALUE_IS_STRING (argv
[0]));
1722 /***************************************************************************/
1724 static GnmFuncHelp
const help_n
[] = {
1725 { GNM_FUNC_HELP_NAME
, F_("N:@{text} converted to a number")},
1726 { GNM_FUNC_HELP_ARG
, F_("text:string")},
1727 { GNM_FUNC_HELP_NOTE
, F_("If @{text} contains non-numerical text, 0 is returned.") },
1728 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1729 { GNM_FUNC_HELP_EXAMPLES
, "=N(\"42\")" },
1730 { GNM_FUNC_HELP_EXAMPLES
, F_("=N(\"eleven\")") },
1731 { GNM_FUNC_HELP_END
}
1735 gnumeric_n (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1739 if (VALUE_IS_NUMBER (argv
[0]))
1740 return value_new_float (value_get_as_float (argv
[0]));
1742 if (!VALUE_IS_STRING (argv
[0]))
1743 return value_new_error_NUM (ei
->pos
);
1745 v
= format_match_number (value_peek_string (argv
[0]),
1747 workbook_date_conv (ei
->pos
->sheet
->workbook
));
1751 return value_new_float (0);
1754 /***************************************************************************/
1756 static GnmFuncHelp
const help_type
[] = {
1757 { GNM_FUNC_HELP_NAME
, F_("TYPE:a number indicating the data type of @{value}")},
1758 { GNM_FUNC_HELP_ARG
, F_("value:a value")},
1759 { GNM_FUNC_HELP_DESCRIPTION
, F_("TYPE returns a number indicating the data type of @{value}:\n"
1765 { GNM_FUNC_HELP_EXCEL
, F_("This function is Excel compatible.") },
1766 { GNM_FUNC_HELP_EXAMPLES
, "=TYPE(3)" },
1767 { GNM_FUNC_HELP_EXAMPLES
, "=TYPE(\"Gnumeric\")" },
1768 { GNM_FUNC_HELP_END
}
1772 gnumeric_type (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1774 GnmValue
const *v
= argv
[0];
1775 switch (v
? v
->v_any
.type
: VALUE_EMPTY
) {
1777 return value_new_int (4);
1780 return value_new_int (1);
1781 case VALUE_CELLRANGE
:
1783 return value_new_int (16);
1785 return value_new_int (2);
1787 return value_new_int (64);
1792 return value_new_error_VALUE (ei
->pos
);
1795 /***************************************************************************/
1797 static GnmFuncHelp
const help_getenv
[] = {
1798 { GNM_FUNC_HELP_NAME
, F_("GETENV:the value of execution environment variable @{name}")},
1799 { GNM_FUNC_HELP_ARG
, F_("name:the name of the environment variable")},
1800 { GNM_FUNC_HELP_NOTE
, F_("If a variable called @{name} does not exist, #N/A will be returned.") },
1801 { GNM_FUNC_HELP_NOTE
, F_("Variable names are case sensitive.") },
1802 { GNM_FUNC_HELP_EXAMPLES
, "=GETENV(\"HOME\")" },
1803 { GNM_FUNC_HELP_END
}
1807 gnumeric_getenv (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1809 char const *var
= value_peek_string (argv
[0]);
1810 char const *val
= g_getenv (var
);
1812 if (val
&& g_utf8_validate (val
, -1, NULL
))
1813 return value_new_string (val
);
1815 return value_new_error_NA (ei
->pos
);
1818 /***************************************************************************/
1820 static GnmFuncHelp
const help_get_link
[] = {
1821 { GNM_FUNC_HELP_NAME
, F_("GET.LINK:the target of the hyperlink attached to @{cell} as a string")},
1822 { GNM_FUNC_HELP_ARG
, F_("cell:the referenced cell")},
1823 { GNM_FUNC_HELP_NOTE
, F_("The value return is not updated automatically when "
1824 "the link attached to @{cell} changes but requires a"
1825 " recalculation.")},
1826 { GNM_FUNC_HELP_SEEALSO
, "HYPERLINK"},
1827 { GNM_FUNC_HELP_END
}
1831 gnumeric_get_link (GnmFuncEvalInfo
*ei
, GnmValue
const * const *argv
)
1833 GnmValue
const * const v
= argv
[0];
1835 if (VALUE_IS_CELLRANGE (v
)) {
1836 GnmCellRef
const * a
= &v
->v_range
.cell
.a
;
1837 GnmCellRef
const * b
= &v
->v_range
.cell
.b
;
1842 if (a
->col
!= b
->col
|| a
->row
!= b
->row
|| a
->sheet
!=b
->sheet
)
1843 return value_new_error_REF (ei
->pos
);
1845 sheet
= (a
->sheet
== NULL
) ? ei
->pos
->sheet
: a
->sheet
;
1846 gnm_cellpos_init_cellref (&pos
, a
, &(ei
->pos
->eval
), sheet
);
1847 lnk
= gnm_sheet_hlink_find (sheet
, &pos
);
1850 return value_new_string (gnm_hlink_get_target (lnk
));
1853 return value_new_empty ();
1856 /***************************************************************************/
1858 GnmFuncDescriptor
const info_functions
[] = {
1859 { "cell", "sr", help_cell
,
1860 gnumeric_cell
, NULL
, NULL
, NULL
,
1861 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_SUBSET_WITH_EXTENSIONS
, GNM_FUNC_TEST_STATUS_BASIC
},
1862 { "error.type", "E", help_error_type
,
1863 gnumeric_error_type
, NULL
, NULL
, NULL
,
1864 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1865 { "info", "s", help_info
,
1866 gnumeric_info
, NULL
, NULL
, NULL
,
1867 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1868 { "isblank", "E", help_isblank
,
1869 gnumeric_isblank
, NULL
, NULL
, NULL
,
1870 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1871 { "iserr", "E", help_iserr
,
1872 gnumeric_iserr
, NULL
, NULL
, NULL
,
1873 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1874 { "iserror", "E", help_iserror
,
1875 gnumeric_iserror
, NULL
, NULL
, NULL
,
1876 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1877 { "iseven", "f", help_iseven
,
1878 gnumeric_iseven
, NULL
, NULL
, NULL
,
1879 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1880 { "islogical", "E", help_islogical
,
1881 gnumeric_islogical
, NULL
, NULL
, NULL
,
1882 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1883 { "isna", "E", help_isna
,
1884 gnumeric_isna
, NULL
, NULL
, NULL
,
1885 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1886 { "isnontext", "E", help_isnontext
,
1887 gnumeric_isnontext
, NULL
, NULL
, NULL
,
1888 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1889 { "isnumber", "E", help_isnumber
,
1890 gnumeric_isnumber
, NULL
, NULL
, NULL
,
1891 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1892 { "isodd", "S", help_isodd
,
1893 gnumeric_isodd
, NULL
, NULL
, NULL
,
1894 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1895 { "isref", NULL
, help_isref
,
1896 NULL
, gnumeric_isref
, NULL
, NULL
,
1897 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1898 { "istext", "E", help_istext
,
1899 gnumeric_istext
, NULL
, NULL
, NULL
,
1900 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1902 gnumeric_n
, NULL
, NULL
, NULL
,
1903 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1904 { "na", "", help_na
,
1905 gnumeric_na
, NULL
, NULL
, NULL
,
1906 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1907 { "type", "?", help_type
,
1908 gnumeric_type
, NULL
, NULL
, NULL
,
1909 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1911 /* XL stores this in statistical ? */
1912 { "countblank", "r", help_countblank
,
1913 gnumeric_countblank
, NULL
, NULL
, NULL
,
1914 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_BASIC
},
1916 { "error", "s", help_error
,
1917 gnumeric_error
, NULL
, NULL
, NULL
,
1918 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},
1920 { "expression", "r", help_expression
,
1921 gnumeric_expression
, NULL
, NULL
, NULL
,
1922 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},
1923 /* XLM : looks common in charts */
1924 { "get.formula", "r", help_get_formula
,
1925 gnumeric_get_formula
, NULL
, NULL
, NULL
,
1926 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_COMPLETE
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},
1927 { "get.link", "r", help_get_link
,
1928 gnumeric_get_link
, NULL
, NULL
, NULL
,
1929 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},
1930 { "isformula", "r", help_isformula
,
1931 gnumeric_isformula
, NULL
, NULL
, NULL
,
1932 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},
1933 { "getenv", "s", help_getenv
,
1934 gnumeric_getenv
, NULL
, NULL
, NULL
,
1935 GNM_FUNC_SIMPLE
, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC
, GNM_FUNC_TEST_STATUS_NO_TESTSUITE
},