[gnumeric] fn-hebrew-date: new plugin.



commit 6a914c11579a9567767889a958690a5202dc19f2
Author: Morten Welinder <terra gnome org>
Date:   Tue Oct 20 19:42:12 2009 -0400

    fn-hebrew-date: new plugin.

 NEWS                                   |    3 +
 configure.in                           |    1 +
 plugins/Makefile.am                    |    4 +-
 plugins/fn-hebrew-date/.gitignore      |    9 +
 plugins/fn-hebrew-date/ChangeLog       |    8 +
 plugins/fn-hebrew-date/Makefile.am     |   18 ++
 plugins/fn-hebrew-date/functions.c     |  259 +++++++++++++++++++++++++++++
 plugins/fn-hebrew-date/hdate.h         |  142 ++++++++++++++++
 plugins/fn-hebrew-date/hdate_hdate.c   |  278 ++++++++++++++++++++++++++++++++
 plugins/fn-hebrew-date/hdate_strings.c |  134 +++++++++++++++
 plugins/fn-hebrew-date/plugin.xml.in   |   23 +++
 11 files changed, 877 insertions(+), 2 deletions(-)
---
diff --git a/NEWS b/NEWS
index 6999c3a..cbc18b8 100644
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,9 @@ Morten:
 	* Fix Excel-to-Gnumeric paste problem.  [#381732, #388531].
 	* Fix Alt-Enter problems.  [#597295]
 
+Yaacov Zamir:
+       * Hebrew Calendar functions.  [#153738]
+
 --------------------------------------------------------------------------
 Gnumeric 1.9.14
 
diff --git a/configure.in b/configure.in
index a543ef3..35b703e 100644
--- a/configure.in
+++ b/configure.in
@@ -1047,6 +1047,7 @@ plugins/fn-derivatives/Makefile
 plugins/fn-eng/Makefile
 plugins/fn-erlang/Makefile
 plugins/fn-financial/Makefile
+plugins/fn-hebrew-date/Makefile
 plugins/fn-info/Makefile
 plugins/fn-logical/Makefile
 plugins/fn-lookup/Makefile
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 14b4fab..8ae35e9 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -12,8 +12,8 @@ if WITH_PARADOX
 endif
 
 SUBDIRS_FUNCTIONS = fn-numtheory fn-database fn-date fn-eng fn-erlang \
-	fn-financial fn-info fn-logical fn-complex fn-lookup fn-math \
-	fn-r fn-stat fn-string fn-random fn-tsa fn-derivatives
+	fn-financial fn-hebrew-date fn-info fn-logical fn-complex fn-lookup \
+	fn-math fn-r fn-stat fn-string fn-random fn-tsa fn-derivatives
 
 if WITH_GDA
   SUBDIRS_FUNCTIONS += gda
diff --git a/plugins/fn-hebrew-date/.gitignore b/plugins/fn-hebrew-date/.gitignore
new file mode 100644
index 0000000..e64b392
--- /dev/null
+++ b/plugins/fn-hebrew-date/.gitignore
@@ -0,0 +1,9 @@
+Makefile.in
+Makefile
+.deps
+.libs
+*.lo
+*.la
+plugin.xml
+*.loT
+*.sw*
diff --git a/plugins/fn-hebrew-date/ChangeLog b/plugins/fn-hebrew-date/ChangeLog
new file mode 100644
index 0000000..3ca77c6
--- /dev/null
+++ b/plugins/fn-hebrew-date/ChangeLog
@@ -0,0 +1,8 @@
+2009-10-20  Morten Welinder  <terra gnome org>
+
+	* *.[ch]: Remove unused code; bring the rest up to current API.
+	Avoid fixed-length buffers.
+
+2005-01-14  Yaacov Zamir <kzamir walla co il>
+
+	* Release 0.0.1
diff --git a/plugins/fn-hebrew-date/Makefile.am b/plugins/fn-hebrew-date/Makefile.am
new file mode 100644
index 0000000..b495dd5
--- /dev/null
+++ b/plugins/fn-hebrew-date/Makefile.am
@@ -0,0 +1,18 @@
+AM_CPPFLAGS = \
+    -DGNOMELOCALEDIR=\""$(datadir)/locale"\" 	\
+    -I$(top_srcdir)/src	-I$(top_builddir)/src	\
+    $(GNUMERIC_CFLAGS)
+
+gnumeric_plugin_fndatedir = $(gnumeric_plugindir)/fn-hebrew-date
+xmldir = $(gnumeric_plugin_fndatedir)
+gnumeric_plugin_fndate_LTLIBRARIES = plugin.la
+plugin_la_LDFLAGS = -module $(GNUMERIC_PLUGIN_LDFLAGS)
+plugin_la_SOURCES = functions.c hdate_hdate.c hdate_strings.c hdate.h
+
+xml_in_files = plugin.xml.in
+xml_DATA = $(xml_in_files:.xml.in=.xml)
+
+ INTLTOOL_XML_RULE@
+
+EXTRA_DIST = $(xml_in_files)
+DISTCLEANFILES = $(xml_DATA)
diff --git a/plugins/fn-hebrew-date/functions.c b/plugins/fn-hebrew-date/functions.c
new file mode 100644
index 0000000..9683139
--- /dev/null
+++ b/plugins/fn-hebrew-date/functions.c
@@ -0,0 +1,259 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * fn-hebrew-date.c:  Built in hebrew date functions.
+ *
+ * Author:
+ *   Yaacov Zamir <kzamir walla co il>
+ *
+ * Based on Date functions by:
+ *   Miguel de Icaza (miguel gnu org)
+ *   Jukka-Pekka Iivonen (iivonen iki fi)
+ *   Morten Welinder <terra diku dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <gnumeric-config.h>
+#include <gnumeric.h>
+#include <gnm-i18n.h>
+#include <func.h>
+#include <value.h>
+
+#include <parse-util.h>
+#include <cell.h>
+#include <value.h>
+#include <mathfunc.h>
+#include <workbook.h>
+#include <sheet.h>
+
+#include <math.h>
+
+#include <glib.h>
+#include "hdate.h"
+#include <goffice/goffice.h>
+#include <gnm-plugin.h>
+
+GNM_PLUGIN_MODULE_HEADER;
+
+/***************************************************************************/
+
+static GnmFuncHelp const help_hdate[] = {
+	{ GNM_FUNC_HELP_NAME, F_("HDATE:Hebrew date") },
+        { GNM_FUNC_HELP_ARG, F_("year:year of date")},
+        { GNM_FUNC_HELP_ARG, F_("month:month of year")},
+        { GNM_FUNC_HELP_ARG, F_("day:day of month")},
+        { GNM_FUNC_HELP_EXAMPLES, "=HDATE(2001,3,30)" },
+        { GNM_FUNC_HELP_SEEALSO, "HDATE_HEB,DATE"},
+	{ GNM_FUNC_HELP_END }
+};
+
+static GnmValue *
+gnumeric_hdate (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
+{
+	int year, month, day;
+	int hyear, hmonth, hday;
+	char *res;
+
+	year = value_get_as_int (argv[0]);
+	month = value_get_as_int (argv[1]);
+	day = value_get_as_int (argv[2]);
+
+	hdate_gdate_to_hdate (day, month, year, &hday, &hmonth, &hyear);
+
+	res = g_strdup_printf ("%d %s %d",
+			       hday + 1,
+			       hdate_get_hebrew_month_name (hmonth),
+			       hyear);
+
+	return value_new_string_nocopy (res);
+}
+
+/***************************************************************************/
+
+static GnmFuncHelp const help_hdate_heb[] = {
+	{ GNM_FUNC_HELP_NAME, F_("HDATE_HEB:Hebrew date in Hebrew") },
+        { GNM_FUNC_HELP_ARG, F_("year:year of date")},
+        { GNM_FUNC_HELP_ARG, F_("month:month of year")},
+        { GNM_FUNC_HELP_ARG, F_("day:day of month")},
+        { GNM_FUNC_HELP_EXAMPLES, "=HDATE_HEB(2001,3,30)" },
+        { GNM_FUNC_HELP_SEEALSO, "HDATE,DATE"},
+	{ GNM_FUNC_HELP_END }
+};
+
+static GnmValue *
+gnumeric_hdate_heb (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
+{
+	int year, month, day;
+	int hyear, hmonth, hday;
+	GString *res;
+
+	year = value_get_as_int (argv[0]);
+	month = value_get_as_int (argv[1]);
+	day = value_get_as_int (argv[2]);
+
+	hdate_gdate_to_hdate (day, month, year, &hday, &hmonth, &hyear);
+
+	res = g_string_new (NULL);
+	hdate_int_to_hebrew (res, hday + 1);
+	g_string_append_c (res, ' ');
+	g_string_append (res, hdate_get_hebrew_month_name_heb (hmonth));
+	g_string_append_c (res, ' ');
+	hdate_int_to_hebrew (res, hyear);
+
+	return value_new_string_nocopy (g_string_free (res, FALSE));
+}
+
+/***************************************************************************/
+
+static GnmFuncHelp const help_hdate_month[] = {
+	{ GNM_FUNC_HELP_NAME, F_("HDATE_MONTH:Hebrew month of Gregorian date") },
+        { GNM_FUNC_HELP_ARG, F_("year:Gregorian year of date")},
+        { GNM_FUNC_HELP_ARG, F_("month:Gregorian month of year")},
+        { GNM_FUNC_HELP_ARG, F_("day:Gregorian day of month")},
+        { GNM_FUNC_HELP_EXAMPLES, "=HDATE_MONTH(2001,3,30)" },
+        { GNM_FUNC_HELP_SEEALSO, "HDATE_JULIAN"},
+	{ GNM_FUNC_HELP_END }
+};
+
+static GnmValue *
+gnumeric_hdate_month (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
+{
+	int year, month, day;
+	int hyear, hmonth, hday;
+
+	year = value_get_as_int (argv[0]);
+	month = value_get_as_int (argv[1]);
+	day = value_get_as_int (argv[2]);
+
+	hdate_gdate_to_hdate (day, month, year, &hday, &hmonth, &hyear);
+
+	return value_new_int (hmonth);
+}
+
+/***************************************************************************/
+
+static GnmFuncHelp const help_hdate_day[] = {
+	{ GNM_FUNC_HELP_NAME, F_("HDATE_DAY:Hebrew day of Gregorian date") },
+        { GNM_FUNC_HELP_ARG, F_("year:Gregorian year of date")},
+        { GNM_FUNC_HELP_ARG, F_("month:Gregorian month of year")},
+        { GNM_FUNC_HELP_ARG, F_("day:Gregorian day of month")},
+        { GNM_FUNC_HELP_EXAMPLES, "=HDATE_DAY(2001,3,30)" },
+        { GNM_FUNC_HELP_SEEALSO, "HDATE_JULIAN"},
+	{ GNM_FUNC_HELP_END }
+};
+
+static GnmValue *
+gnumeric_hdate_day (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
+{
+	int year, month, day;
+	int hyear, hmonth, hday;
+
+	year = value_get_as_int (argv[0]);
+	month = value_get_as_int (argv[1]);
+	day = value_get_as_int (argv[2]);
+
+	hdate_gdate_to_hdate (day, month, year, &hday, &hmonth, &hyear);
+
+	return value_new_int (hday + 1);
+}
+
+/***************************************************************************/
+
+static GnmFuncHelp const help_hdate_year[] = {
+	{ GNM_FUNC_HELP_NAME, F_("HDATE_YEAR:Hebrew year of Gregorian date") },
+        { GNM_FUNC_HELP_ARG, F_("year:Gregorian year of date")},
+        { GNM_FUNC_HELP_ARG, F_("month:Gregorian month of year")},
+        { GNM_FUNC_HELP_ARG, F_("day:Gregorian day of month")},
+        { GNM_FUNC_HELP_EXAMPLES, "=HDATE_YEAR(2001,3,30)" },
+        { GNM_FUNC_HELP_SEEALSO, "HDATE_JULIAN"},
+	{ GNM_FUNC_HELP_END }
+};
+
+static GnmValue *
+gnumeric_hdate_year (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
+{
+	int year, month, day;
+	int hyear, hmonth, hday;
+
+	year = value_get_as_int (argv[0]);
+	month = value_get_as_int (argv[1]);
+	day = value_get_as_int (argv[2]);
+
+	hdate_gdate_to_hdate (day, month, year, &hday, &hmonth, &hyear);
+
+	return value_new_int (hyear);
+}
+
+/***************************************************************************/
+
+static GnmFuncHelp const help_hdate_julian[] = {
+	{ GNM_FUNC_HELP_NAME, F_("HDATE_JULIAN:Julian day number for given Gregorian date") },
+        { GNM_FUNC_HELP_ARG, F_("year:Gregorian year of date")},
+        { GNM_FUNC_HELP_ARG, F_("month:Gregorian month of year")},
+        { GNM_FUNC_HELP_ARG, F_("day:Gregorian day of month")},
+        { GNM_FUNC_HELP_EXAMPLES, "=HDATE_JULIAN(2001,3,30)" },
+        { GNM_FUNC_HELP_SEEALSO, "HDATE"},
+	{ GNM_FUNC_HELP_END }
+};
+
+static GnmValue *
+gnumeric_hdate_julian (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
+{
+	int year, month, day;
+	int julian;
+
+	year = value_get_as_int (argv[0]);
+	month = value_get_as_int (argv[1]);
+	day = value_get_as_int (argv[2]);
+
+	julian = hdate_gdate_to_jd (day, month, year);
+
+	return value_new_int (julian);
+}
+
+/***************************************************************************/
+
+GnmFuncDescriptor const datetime_functions[] = {
+	{"hdate", "fff", help_hdate,
+	 gnumeric_hdate, NULL, NULL, NULL, NULL,
+	 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
+	 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
+	 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
+	{"hdate_heb", "fff", help_hdate_heb,
+	 gnumeric_hdate_heb, NULL, NULL, NULL, NULL,
+	 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
+	 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
+	 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
+	 {"hdate_day", "fff", help_hdate_day,
+	 gnumeric_hdate_day, NULL, NULL, NULL, NULL,
+	 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
+	 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
+	 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
+	 {"hdate_month", "fff", help_hdate_month,
+	 gnumeric_hdate_month, NULL, NULL, NULL, NULL,
+	 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
+	 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
+	 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
+	 {"hdate_year", "fff", help_hdate_year,
+	 gnumeric_hdate_year, NULL, NULL, NULL, NULL,
+	 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
+	 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
+	 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
+	 {"hdate_julian", "fff", help_hdate_julian,
+	 gnumeric_hdate_julian, NULL, NULL, NULL, NULL,
+	 GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
+	 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
+	 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
+	{NULL}
+};
diff --git a/plugins/fn-hebrew-date/hdate.h b/plugins/fn-hebrew-date/hdate.h
new file mode 100644
index 0000000..a9adb73
--- /dev/null
+++ b/plugins/fn-hebrew-date/hdate.h
@@ -0,0 +1,142 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * hdate_hdate.c: convert georgean and hebrew calendars.
+ *
+ * Author:
+ *   Yaacov Zamir <kzamir walla co il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef __HDATE_H__
+#define __HDATE_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ @brief Return the days from the start
+ 
+ @param y The years
+ @warning internal function.
+*/
+int
+hdate_days_from_start (int y);
+
+/**
+ @brief compute hebrew date from gregorian date
+
+ @param d Day of month 1..31
+ @param m Month 1..12 ,  if m or d is 0 return current date.
+ @param y Year in 4 digits e.g. 2001
+ */
+int
+hdate_gdate_to_hdate (int d, int m, int y, int *hd, int *hm, int *hy);
+
+/**
+ @brief compute general date structure from hebrew date
+
+ @param d Day of month 1..31
+ @param m Month 0..13 ,  if m or d is 0 return current date.
+ @param y Year in 4 digits e.g. 5731
+
+ @attention no sanity cheak !!
+ */
+int
+hdate_hdate_to_gdate (int d, int m, int y, int *gd, int *gm, int *gy);
+
+/**
+ @brief Compute Julian day (jd from Gregorian day, month and year (d, m, y)
+ Algorithm from 'Julian and Gregorian Day Numbers' by Peter Meyer 
+ @author Yaacov Zamir ( algorithm from Henry F. Fliegel and Thomas C. Van Flandern ,1968)
+
+ @param d Day of month 1..31
+ @param m Month 1..12
+ @param y Year in 4 digits e.g. 2001
+ */
+int
+hdate_gdate_to_jd (int d, int m, int y);
+
+/**
+ @brief Converting from the Julian day to the Gregorian day
+ Algorithm from 'Julian and Gregorian Day Numbers' by Peter Meyer 
+ @author Yaacov Zamir ( Algorithm, Henry F. Fliegel and Thomas C. Van Flandern ,1968)
+
+ @param jd Julian day
+ @param d Return Day of month 1..31
+ @param m Return Month 1..12
+ @param y Return Year in 4 digits e.g. 2001
+ */
+void
+hdate_jd_to_gdate (int jd, int *d, int *m, int *y);
+
+/**
+ @brief Converting from the Julian day to the Hebrew day
+ @author Amos Shapir 1984 (rev. 1985, 1992) Yaacov Zamir 2003-2005
+
+ @param jd Julian day
+ @param d Return Day of month 1..31
+ @param m Return Month 1..14
+ @param y Return Year in 4 digits e.g. 2001
+ */
+void
+hdate_jd_to_hdate (int jd, int *d, int *m, int *y);
+
+/**
+ @brief Compute Julian day (jd from Hebrew day, month and year (d, m, y)
+ @author Amos Shapir 1984 (rev. 1985, 1992) Yaacov Zamir 2003-2005
+
+ @param d Day of month 1..31
+ @param m Month 1..14
+ @param y Year in 4 digits e.g. 5753
+ */
+int
+hdate_hdate_to_jd (int d, int m, int y);
+
+/* string functions */
+
+/**
+ @brief convert an integer to hebrew string UTF-8 (logical)
+ 
+ @param n The int to convert
+ @attention ( 0 < n < 10000)
+ @warning uses a static string, so output should be copied away.
+*/
+void hdate_int_to_hebrew (GString *res, int n);
+
+/**
+ @brief Return a static string, with name of hebrew month.
+
+ @param month The number of the month 0..13 (0 - tishre, 12 - adar 1, 13 - adar 2).
+ @warning uses a static string, so output should be copied away.
+*/
+const char *hdate_get_hebrew_month_name (int month);
+
+/**
+ @brief Return a static string, with name of hebrew month in hebrew.
+
+ @param month The number of the month 0..13 (0 - tishre, 12 - adar 1, 13 - adar 2).
+ @warning uses a static string, so output should be copied away.
+*/
+const char *hdate_get_hebrew_month_name_heb (int month);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/plugins/fn-hebrew-date/hdate_hdate.c b/plugins/fn-hebrew-date/hdate_hdate.c
new file mode 100644
index 0000000..8486e2a
--- /dev/null
+++ b/plugins/fn-hebrew-date/hdate_hdate.c
@@ -0,0 +1,278 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * hdate_hdate.c: convert georgean and hebrew calendars.
+ *
+ * Author:
+ *   Yaacov Zamir <kzamir walla co il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gnumeric-config.h>
+#include <gnumeric.h>
+#include <stdio.h>
+
+#include "hdate.h"
+
+/* constants, in 1/18th of minute */
+#define HOUR 1080
+#define DAY  (24*HOUR)
+#define WEEK (7*DAY)
+#define M(h,p) ((h)*HOUR+p)
+#define MONTH (DAY+M(12,793))
+
+/**
+ @brief Return the days from the start
+ 
+ @param y The years
+ @warning internal function.
+*/
+int
+hdate_days_from_start (int y)
+{
+	int m, nm, dw, s, l;
+
+	l = y * 7 + 1;		/* no. of leap months */
+	m = y * 12 + l / 19;	/* total no. of months */
+	l %= 19;
+	nm = m * MONTH + M (1 + 6, 779);	/* molad new year 3744 (16BC) + 6 hours */
+	s = m * 28 + nm / DAY - 2;
+
+	nm %= WEEK;
+	dw = nm / DAY;
+	nm %= DAY;
+
+	/* special cases of Molad Zaken */
+	if ((l < 12 && dw == 3 && nm >= M (9 + 6, 204)) ||
+	    (l < 7 && dw == 2 && nm >= M (15 + 6, 589)))
+		s++, dw++;
+	/* ADU */
+	if (dw == 1 || dw == 4 || dw == 6)
+		s++;
+	return s;
+}
+
+/**
+ @brief compute hebrew date from gregorian date
+
+ @param d Day of month 1..31
+ @param m Month 1..12 ,  if m or d is 0 return current date.
+ @param y Year in 4 digits e.g. 2001
+ */
+int
+hdate_gdate_to_hdate (int d, int m, int y, int *hd, int *hm, int *hy)
+{
+	int jd;
+
+	/* sanity checks */
+	if (!(m >= 1 && m <= 12) ||
+	    !((d >= 1)
+	      && ((y >= 3000 && m == 6 && d <= 59)
+		  || (d <= 31))) || !(y > 0))
+		return 1;
+
+	/* end of cheking */
+
+	jd = hdate_gdate_to_jd (d, m, y);
+
+	hdate_jd_to_hdate (jd, hd, hm, hy);
+
+	return 0;
+
+}
+
+/**
+ @brief compute general date structure from hebrew date
+
+ @param d Day of month 1..31
+ @param m Month 0..13 ,  if m or d is 0 return current date.
+ @param y Year in 4 digits e.g. 5731
+
+ @attention no sanity cheak !!
+ */
+int
+hdate_hdate_to_gdate (int d, int m, int y, int *gd, int *gm, int *gy)
+{
+	int jd;
+
+	/* sanity checks */
+	if (!(m >= 1 && m <= 12) ||
+	    !((d >= 1)
+	      && ((y >= 3000 && m == 6 && d <= 59)
+		  || (d <= 31))) || !(y > 0))
+		return 1;
+
+	/* end of cheking */
+
+	jd = hdate_hdate_to_jd (d, m, y);
+
+	hdate_jd_to_gdate (jd, gd, gm, gy);
+
+	return 0;
+}
+
+/**
+ @brief Compute Julian day (jd from Gregorian day, month and year (d, m, y)
+ Algorithm from 'Julian and Gregorian Day Numbers' by Peter Meyer 
+ @author Yaacov Zamir ( algorithm from Henry F. Fliegel and Thomas C. Van Flandern ,1968)
+
+ @param d Day of month 1..31
+ @param m Month 1..12
+ @param y Year in 4 digits e.g. 2001
+ */
+int
+hdate_gdate_to_jd (int d, int m, int y)
+{
+	int jd;
+
+	jd = (1461 * (y + 4800 + (m - 14) / 12)) / 4 +
+		(367 * (m - 2 - 12 * ((m - 14) / 12))) / 12 -
+		(3 * ((y + 4900 + (m - 14) / 12) / 100)) / 4 + d - 32075;
+
+	return jd;
+}
+
+/**
+ @brief Converting from the Julian day to the Gregorian day
+ Algorithm from 'Julian and Gregorian Day Numbers' by Peter Meyer 
+ @author Yaacov Zamir ( Algorithm, Henry F. Fliegel and Thomas C. Van Flandern ,1968)
+
+ @param jd Julian day
+ @param d Return Day of month 1..31
+ @param m Return Month 1..12
+ @param y Return Year in 4 digits e.g. 2001
+ */
+void
+hdate_jd_to_gdate (int jd, int *d, int *m, int *y)
+{
+	int l, n, i, j;
+
+	l = jd + 68569;
+	n = (4 * l) / 146097;
+	l = l - (146097 * n + 3) / 4;
+	i = (4000 * (l + 1)) / 1461001;	/* that's 1,461,001 */
+	l = l - (1461 * i) / 4 + 31;
+	j = (80 * l) / 2447;
+	*d = l - (2447 * j) / 80;
+	l = j / 11;
+	*m = j + 2 - (12 * l);
+	*y = 100 * (n - 49) + i + l;	/* that's a lower-case L */
+}
+
+/**
+ @brief Converting from the Julian day to the Hebrew day
+ @author Amos Shapir 1984 (rev. 1985, 1992) Yaacov Zamir 2003-2005
+
+ @param jd Julian day
+ @param d Return Day of month 1..31
+ @param m Return Month 1..14
+ @param y Return Year in 4 digits e.g. 2001
+ */
+void
+hdate_jd_to_hdate (int jd, int *d, int *m, int *y)
+{
+	int s;
+	int l, n, i, j;
+
+	l = jd + 68569;
+	n = (4 * l) / 146097;
+	l = l - (146097 * n + 3) / 4;
+	i = (4000 * (l + 1)) / 1461001;	/* that's 1,461,001 */
+	l = l - (1461 * i) / 4 + 31;
+	j = (80 * l) / 2447;
+	l = j / 11;
+	*y = 100 * (n - 49) + i + l;	/* that's a lower-case L */
+
+	*d = jd - 1715119;	/* julean to days since 1 Tishrei 3744 */
+
+	*y += 16;
+	s = hdate_days_from_start (*y);
+	*m = hdate_days_from_start (*y + 1);
+
+	while (*d >= *m)
+	{			/* computed year was underestimated */
+		s = *m;
+		(*y)++;
+		*m = hdate_days_from_start (*y + 1);
+	}
+	*d -= s;
+	s = *m - s;		/* size of current year */
+	*y += 3744;
+
+	/* compute day and month */
+	if (*d >= s - 236)
+	{			/* last 8 months are regular */
+		*d -= s - 236;
+		*m = *d * 2 / 59;
+		*d -= (*m * 59 + 1) / 2;
+		*m += 4;
+		if (s > 365 && *m <= 5)	/* Adar of Meuberet */
+			*m += 8;
+	}
+	else
+	{
+		/* first 4 months have 117-119 days */
+		s = 114 + s % 10;
+		*m = *d * 4 / s;
+		*d -= (*m * s + 3) / 4;
+	}
+}
+
+/**
+ @brief Compute Julian day (jd from Hebrew day, month and year (d, m, y)
+ @author Amos Shapir 1984 (rev. 1985, 1992) Yaacov Zamir 2003-2005
+
+ @param d Day of month 1..31
+ @param m Month 1..14
+ @param y Year in 4 digits e.g. 5753
+ */
+int
+hdate_hdate_to_jd (int d, int m, int y)
+{
+	int s;
+
+	y -= 3744;
+	s = hdate_days_from_start (y);
+	d += s;
+	s = hdate_days_from_start (y + 1) - s;	/* length of year */
+
+	if (m == 13)
+	{
+		m = 6;
+	}
+	if (m == 14)
+	{
+		m = 6;
+		d += 30;
+	}
+
+	d += (59 * (m - 1) + 1) / 2;	/* regular months */
+	/* special cases */
+	if (s % 10 > 4 && m > 2)	/* long Heshvan */
+		d++;
+	if (s % 10 < 4 && m > 3)	/* short Kislev */
+		d--;
+
+	if (s > 365 && m > 6)	/* leap year */
+		d += 30;
+	d -= 6002;
+
+	y = (d + 36525) * 4 / 146097 - 1;
+	d -= y / 4 * 146097 + (y % 4) * 36524;
+
+	d += 1715119;		/* days since 1 Tishrei 3744 to julean */
+
+	return d;
+}
diff --git a/plugins/fn-hebrew-date/hdate_strings.c b/plugins/fn-hebrew-date/hdate_strings.c
new file mode 100644
index 0000000..9bc1336
--- /dev/null
+++ b/plugins/fn-hebrew-date/hdate_strings.c
@@ -0,0 +1,134 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * hdate_strings.c: convert libhdate internal numbers to readable hebrew strings.
+ *
+ * Author:
+ *   Yaacov Zamir <kzamir walla co il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gnumeric-config.h>
+#include <gnumeric.h>
+#include <gnm-i18n.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hdate.h"
+
+#define MAX_HNUMBER_SIZE 25
+
+/**
+ @brief convert an integer to hebrew string UTF-8 (logical)
+ 
+ @param n The int to convert
+ @attention ( 0 < n < 10000)
+ @warning uses a static string, so output should be copied away.
+*/
+void
+hdate_int_to_hebrew (GString *res, int n)
+{
+	int oldlen = res->len;
+	int length;
+	static const char *digits[3][10] = {
+		{" ", "×?", "×?", "×?", "×?", "×?", "×?", "×?", "×?", "×?"},
+		{"×?", "×?", "×?", "×?", "×?", "× ", "ס", "×¢", "פ", "צ"},
+		{" ", "ק", "ר", "ש", "ת"}
+	};
+
+	/* sanity checks */
+	if (n < 1 || n > 10000)
+	{
+		return;
+	}
+
+	if (n >= 1000)
+	{
+		g_string_append (res, digits[0][n / 1000]);
+		n %= 1000;
+	}
+	while (n >= 400)
+	{
+		g_string_append (res, digits[2][4]);
+		n -= 400;
+	}
+	if (n >= 100)
+	{
+		g_string_append (res, digits[2][n / 100]);
+		n %= 100;
+	}
+	if (n >= 10)
+	{
+		if (n == 15 || n == 16)
+			n -= 9;
+		g_string_append (res, digits[1][n / 10]);
+		n %= 10;
+	}
+	if (n > 0)
+		g_string_append (res, digits[0][n]);
+
+	length = g_utf8_strlen (res->str + oldlen, -1);
+
+	/* add the ' and " to hebrew numbers */
+	if (length <= 2)
+		g_string_append_c (res, '\'');
+	else
+		g_string_insert_c (res, length - 2, '"');
+}
+
+/**
+ @brief Return a static string, with name of hebrew month.
+
+ @param month The number of the month 0..13 (0 - tishre, 12 - adar 1, 13 - adar 2).
+ @warning uses a static string, so output should be copied away.
+*/
+const char *
+hdate_get_hebrew_month_name (int month)
+{
+	static const char *heb_months[] = {
+		N_("Tishre"), N_("Heshvan"), N_("Kislev"),
+		N_("Tevet"), N_("Shvat"), N_("Adar"),
+		N_("Nisan"), N_("Eyar"), N_("Sivan"), ("Tamuz"),
+		N_("Av"), N_("Elul"), N_("Adar I"), N_("Adar II")
+	};
+
+	if (month < 0 || month > 13)
+		return NULL;
+
+	return heb_months[month];
+}
+
+/**
+ @brief Return a static string, with name of hebrew month in hebrew.
+
+ @param month The number of the month 0..13 (0 - tishre, 12 - adar 1, 13 - adar 2).
+ @warning uses a static string, so output should be copied away.
+*/
+const char *
+hdate_get_hebrew_month_name_heb (int month)
+{
+	static const char *h_heb_months[] = {
+		N_("תשר×?"), N_("×?ש×?×?"), N_("×?ס×?×?"),
+		N_("×?×?ת"), N_("ש×?×?"), N_("×?×?ר"),
+		N_("× ×?ס×?"), N_("×?×?ר"), N_("ס×?×?×?"), N_("ת×?×?×?"),
+		N_("×?×?"), N_("×?×?×?×?"), N_("×?×?ר ×?"), N_("×?×?ר ×?")
+	};
+
+	if (month < 0 || month > 13)
+		return NULL;
+
+	return h_heb_months[month];
+}
diff --git a/plugins/fn-hebrew-date/plugin.xml.in b/plugins/fn-hebrew-date/plugin.xml.in
new file mode 100644
index 0000000..48f5d13
--- /dev/null
+++ b/plugins/fn-hebrew-date/plugin.xml.in
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin id="Gnumeric_fnhebdate">
+	<information>
+		<_name>Hebrew Date Functions</_name>
+		<_description>Functions manipulating Hebrew dates</_description>
+	</information>
+	<loader type="Gnumeric_Builtin:module">
+		<attribute name="module_file" value="plugin"/>
+	</loader>
+	<services>
+		<service type="function_group" id="datetime">
+			<_category>Date/Time</_category>
+			<functions textdomain="gnumeric-functions">
+				<function name="hdate"/>
+				<function name="hdate_heb"/>
+				<function name="hdate_month"/>
+				<function name="hdate_day"/>
+				<function name="hdate_year"/>
+				<function name="hdate_julian"/>
+			</functions>
+		</service>
+	</services>
+</plugin>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]