xref: /PHP-5.5/ext/calendar/calendar.c (revision 73c1be26)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2015 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Shane Caraveo             <shane@caraveo.com>               |
16    |          Colin Viebrock            <colin@easydns.com>               |
17    |          Hartmut Holzgraefe        <hholzgra@php.net>                |
18    |          Wez Furlong               <wez@thebrainroom.com>            |
19    +----------------------------------------------------------------------+
20  */
21 /* $Id$ */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #ifdef PHP_WIN32
28 #define _WINNLS_
29 #endif
30 
31 #include "php.h"
32 #include "ext/standard/info.h"
33 #include "php_calendar.h"
34 #include "sdncal.h"
35 
36 #include <stdio.h>
37 
38 /* {{{ arginfo */
39 ZEND_BEGIN_ARG_INFO_EX(arginfo_unixtojd, 0, 0, 0)
40 	ZEND_ARG_INFO(0, timestamp)
41 ZEND_END_ARG_INFO()
42 
43 ZEND_BEGIN_ARG_INFO(arginfo_jdtounix, 0)
44 	ZEND_ARG_INFO(0, jday)
45 ZEND_END_ARG_INFO()
46 
47 ZEND_BEGIN_ARG_INFO_EX(arginfo_cal_info, 0, 0, 0)
48 	ZEND_ARG_INFO(0, calendar)
49 ZEND_END_ARG_INFO()
50 
51 ZEND_BEGIN_ARG_INFO(arginfo_cal_days_in_month, 0)
52 	ZEND_ARG_INFO(0, calendar)
53 	ZEND_ARG_INFO(0, month)
54 	ZEND_ARG_INFO(0, year)
55 ZEND_END_ARG_INFO()
56 
57 ZEND_BEGIN_ARG_INFO(arginfo_cal_to_jd, 0)
58 	ZEND_ARG_INFO(0, calendar)
59 	ZEND_ARG_INFO(0, month)
60 	ZEND_ARG_INFO(0, day)
61 	ZEND_ARG_INFO(0, year)
62 ZEND_END_ARG_INFO()
63 
64 ZEND_BEGIN_ARG_INFO(arginfo_cal_from_jd, 0)
65 	ZEND_ARG_INFO(0, jd)
66 	ZEND_ARG_INFO(0, calendar)
67 ZEND_END_ARG_INFO()
68 
69 ZEND_BEGIN_ARG_INFO(arginfo_jdtogregorian, 0)
70 	ZEND_ARG_INFO(0, juliandaycount)
71 ZEND_END_ARG_INFO()
72 
73 ZEND_BEGIN_ARG_INFO(arginfo_gregoriantojd, 0)
74 	ZEND_ARG_INFO(0, month)
75 	ZEND_ARG_INFO(0, day)
76 	ZEND_ARG_INFO(0, year)
77 ZEND_END_ARG_INFO()
78 
79 ZEND_BEGIN_ARG_INFO(arginfo_jdtojulian, 0)
80 	ZEND_ARG_INFO(0, juliandaycount)
81 ZEND_END_ARG_INFO()
82 
83 ZEND_BEGIN_ARG_INFO(arginfo_juliantojd, 0)
84 	ZEND_ARG_INFO(0, month)
85 	ZEND_ARG_INFO(0, day)
86 	ZEND_ARG_INFO(0, year)
87 ZEND_END_ARG_INFO()
88 
89 ZEND_BEGIN_ARG_INFO_EX(arginfo_jdtojewish, 0, 0, 1)
90 	ZEND_ARG_INFO(0, juliandaycount)
91 	ZEND_ARG_INFO(0, hebrew)
92 	ZEND_ARG_INFO(0, fl)
93 ZEND_END_ARG_INFO()
94 
95 ZEND_BEGIN_ARG_INFO(arginfo_jewishtojd, 0)
96 	ZEND_ARG_INFO(0, month)
97 	ZEND_ARG_INFO(0, day)
98 	ZEND_ARG_INFO(0, year)
99 ZEND_END_ARG_INFO()
100 
101 ZEND_BEGIN_ARG_INFO(arginfo_jdtofrench, 0)
102 	ZEND_ARG_INFO(0, juliandaycount)
103 ZEND_END_ARG_INFO()
104 
105 ZEND_BEGIN_ARG_INFO(arginfo_frenchtojd, 0)
106 	ZEND_ARG_INFO(0, month)
107 	ZEND_ARG_INFO(0, day)
108 	ZEND_ARG_INFO(0, year)
109 ZEND_END_ARG_INFO()
110 
111 ZEND_BEGIN_ARG_INFO_EX(arginfo_jddayofweek, 0, 0, 1)
112 	ZEND_ARG_INFO(0, juliandaycount)
113 	ZEND_ARG_INFO(0, mode)
114 ZEND_END_ARG_INFO()
115 
116 ZEND_BEGIN_ARG_INFO(arginfo_jdmonthname, 0)
117 	ZEND_ARG_INFO(0, juliandaycount)
118 	ZEND_ARG_INFO(0, mode)
119 ZEND_END_ARG_INFO()
120 
121 ZEND_BEGIN_ARG_INFO_EX(arginfo_easter_date, 0, 0, 0)
122 	ZEND_ARG_INFO(0, year)
123 ZEND_END_ARG_INFO()
124 
125 ZEND_BEGIN_ARG_INFO_EX(arginfo_easter_days, 0, 0, 0)
126 	ZEND_ARG_INFO(0, year)
127 	ZEND_ARG_INFO(0, method)
128 ZEND_END_ARG_INFO()
129 
130 /* }}} */
131 
132 const zend_function_entry calendar_functions[] = {
133 	PHP_FE(jdtogregorian, arginfo_jdtogregorian)
134 	PHP_FE(gregoriantojd, arginfo_gregoriantojd)
135 	PHP_FE(jdtojulian, arginfo_jdtojulian)
136 	PHP_FE(juliantojd, arginfo_juliantojd)
137 	PHP_FE(jdtojewish, arginfo_jdtojewish)
138 	PHP_FE(jewishtojd, arginfo_jewishtojd)
139 	PHP_FE(jdtofrench, arginfo_jdtofrench)
140 	PHP_FE(frenchtojd, arginfo_frenchtojd)
141 	PHP_FE(jddayofweek, arginfo_jddayofweek)
142 	PHP_FE(jdmonthname, arginfo_jdmonthname)
143 	PHP_FE(easter_date, arginfo_easter_date)
144 	PHP_FE(easter_days, arginfo_easter_days)
145 	PHP_FE(unixtojd, arginfo_unixtojd)
146 	PHP_FE(jdtounix, arginfo_jdtounix)
147 	PHP_FE(cal_to_jd, arginfo_cal_to_jd)
148 	PHP_FE(cal_from_jd, arginfo_cal_from_jd)
149 	PHP_FE(cal_days_in_month, arginfo_cal_days_in_month)
150 	PHP_FE(cal_info, arginfo_cal_info)
151 	PHP_FE_END
152 };
153 
154 
155 zend_module_entry calendar_module_entry = {
156 	STANDARD_MODULE_HEADER,
157 	"calendar",
158 	calendar_functions,
159 	PHP_MINIT(calendar),
160 	NULL,
161 	NULL,
162 	NULL,
163 	PHP_MINFO(calendar),
164 	NO_VERSION_YET,
165 	STANDARD_MODULE_PROPERTIES,
166 };
167 
168 #ifdef COMPILE_DL_CALENDAR
169 ZEND_GET_MODULE(calendar)
170 #endif
171 
172 /* this order must match the conversion table below */
173 enum cal_name_type_t {
174 	CAL_GREGORIAN = 0,
175 	CAL_JULIAN,
176 	CAL_JEWISH,
177 	CAL_FRENCH,
178 	CAL_NUM_CALS
179 };
180 
181 typedef long int (*cal_to_jd_func_t) (int month, int day, int year);
182 typedef void (*cal_from_jd_func_t) (long int jd, int *year, int *month, int *day);
183 typedef char *(*cal_as_string_func_t) (int year, int month, int day);
184 
185 struct cal_entry_t {
186 	char *name;
187 	char *symbol;
188 	cal_to_jd_func_t to_jd;
189 	cal_from_jd_func_t from_jd;
190 	int num_months;
191 	int max_days_in_month;
192 	char **month_name_short;
193 	char **month_name_long;
194 };
195 
196 static struct cal_entry_t cal_conversion_table[CAL_NUM_CALS] = {
197 	{"Gregorian", "CAL_GREGORIAN", GregorianToSdn, SdnToGregorian, 12, 31,
198 	 MonthNameShort, MonthNameLong},
199 	{"Julian", "CAL_JULIAN", JulianToSdn, SdnToJulian, 12, 31,
200 	 MonthNameShort, MonthNameLong},
201 	{"Jewish", "CAL_JEWISH", JewishToSdn, SdnToJewish, 13, 30,
202 	 JewishMonthNameLeap, JewishMonthNameLeap},
203 	{"French", "CAL_FRENCH", FrenchToSdn, SdnToFrench, 13, 30,
204 	 FrenchMonthName, FrenchMonthName}
205 };
206 
207 #define JEWISH_MONTH_NAME(year) 	((monthsPerYear[((year)-1) % 19] == 13)?JewishMonthNameLeap:JewishMonthName)
208 #define JEWISH_HEB_MONTH_NAME(year) ((monthsPerYear[((year)-1) % 19] == 13)?JewishMonthHebNameLeap:JewishMonthHebName)
209 
210 /* For jddayofweek */
211 enum { CAL_DOW_DAYNO, CAL_DOW_LONG, CAL_DOW_SHORT };
212 
213 /* For jdmonthname */
214 enum { CAL_MONTH_GREGORIAN_SHORT, CAL_MONTH_GREGORIAN_LONG,
215 	CAL_MONTH_JULIAN_SHORT, CAL_MONTH_JULIAN_LONG, CAL_MONTH_JEWISH,
216 	CAL_MONTH_FRENCH
217 };
218 
219 /* for heb_number_to_chars */
220 static char alef_bet[25] = "0����������������������";
221 
222 #define CAL_JEWISH_ADD_ALAFIM_GERESH 0x2
223 #define CAL_JEWISH_ADD_ALAFIM 0x4
224 #define CAL_JEWISH_ADD_GERESHAYIM 0x8
225 
PHP_MINIT_FUNCTION(calendar)226 PHP_MINIT_FUNCTION(calendar)
227 {
228 	REGISTER_LONG_CONSTANT("CAL_GREGORIAN", CAL_GREGORIAN, CONST_CS | CONST_PERSISTENT);
229 	REGISTER_LONG_CONSTANT("CAL_JULIAN", CAL_JULIAN, CONST_CS | CONST_PERSISTENT);
230 	REGISTER_LONG_CONSTANT("CAL_JEWISH", CAL_JEWISH, CONST_CS | CONST_PERSISTENT);
231 	REGISTER_LONG_CONSTANT("CAL_FRENCH", CAL_FRENCH, CONST_CS | CONST_PERSISTENT);
232 	REGISTER_LONG_CONSTANT("CAL_NUM_CALS", CAL_NUM_CALS, CONST_CS | CONST_PERSISTENT);
233 /* constants for jddayofweek */
234 	REGISTER_LONG_CONSTANT("CAL_DOW_DAYNO", CAL_DOW_DAYNO, CONST_CS | CONST_PERSISTENT);
235 	REGISTER_LONG_CONSTANT("CAL_DOW_SHORT", CAL_DOW_SHORT, CONST_CS | CONST_PERSISTENT);
236 	REGISTER_LONG_CONSTANT("CAL_DOW_LONG", CAL_DOW_LONG, CONST_CS | CONST_PERSISTENT);
237 /* constants for jdmonthname */
238 	REGISTER_LONG_CONSTANT("CAL_MONTH_GREGORIAN_SHORT", CAL_MONTH_GREGORIAN_SHORT, CONST_CS | CONST_PERSISTENT);
239 	REGISTER_LONG_CONSTANT("CAL_MONTH_GREGORIAN_LONG", CAL_MONTH_GREGORIAN_LONG, CONST_CS | CONST_PERSISTENT);
240 	REGISTER_LONG_CONSTANT("CAL_MONTH_JULIAN_SHORT", CAL_MONTH_JULIAN_SHORT, CONST_CS | CONST_PERSISTENT);
241 	REGISTER_LONG_CONSTANT("CAL_MONTH_JULIAN_LONG", CAL_MONTH_JULIAN_LONG, CONST_CS | CONST_PERSISTENT);
242 	REGISTER_LONG_CONSTANT("CAL_MONTH_JEWISH", CAL_MONTH_JEWISH, CONST_CS | CONST_PERSISTENT);
243 	REGISTER_LONG_CONSTANT("CAL_MONTH_FRENCH", CAL_MONTH_FRENCH, CONST_CS | CONST_PERSISTENT);
244 /* constants for easter calculation */
245 	REGISTER_LONG_CONSTANT("CAL_EASTER_DEFAULT", CAL_EASTER_DEFAULT, CONST_CS | CONST_PERSISTENT);
246 	REGISTER_LONG_CONSTANT("CAL_EASTER_ROMAN", CAL_EASTER_ROMAN, CONST_CS | CONST_PERSISTENT);
247 	REGISTER_LONG_CONSTANT("CAL_EASTER_ALWAYS_GREGORIAN", CAL_EASTER_ALWAYS_GREGORIAN, CONST_CS | CONST_PERSISTENT);
248 	REGISTER_LONG_CONSTANT("CAL_EASTER_ALWAYS_JULIAN", CAL_EASTER_ALWAYS_JULIAN, CONST_CS | CONST_PERSISTENT);
249 /* constants for Jewish date formatting */
250 	REGISTER_LONG_CONSTANT("CAL_JEWISH_ADD_ALAFIM_GERESH", CAL_JEWISH_ADD_ALAFIM_GERESH, CONST_CS | CONST_PERSISTENT);
251 	REGISTER_LONG_CONSTANT("CAL_JEWISH_ADD_ALAFIM", CAL_JEWISH_ADD_ALAFIM, CONST_CS | CONST_PERSISTENT);
252 	REGISTER_LONG_CONSTANT("CAL_JEWISH_ADD_GERESHAYIM", CAL_JEWISH_ADD_GERESHAYIM, CONST_CS | CONST_PERSISTENT);
253 	return SUCCESS;
254 }
255 
PHP_MINFO_FUNCTION(calendar)256 PHP_MINFO_FUNCTION(calendar)
257 {
258 	php_info_print_table_start();
259 	php_info_print_table_row(2, "Calendar support", "enabled");
260 	php_info_print_table_end();
261 }
262 
_php_cal_info(int cal,zval ** ret)263 static void _php_cal_info(int cal, zval **ret)
264 {
265 	zval *months, *smonths;
266 	int i;
267 	struct cal_entry_t *calendar;
268 
269 	calendar = &cal_conversion_table[cal];
270 	array_init(*ret);
271 
272 	MAKE_STD_ZVAL(months);
273 	MAKE_STD_ZVAL(smonths);
274 	array_init(months);
275 	array_init(smonths);
276 
277 	for (i = 1; i <= calendar->num_months; i++) {
278 		add_index_string(months, i, calendar->month_name_long[i], 1);
279 		add_index_string(smonths, i, calendar->month_name_short[i], 1);
280 	}
281 	add_assoc_zval(*ret, "months", months);
282 	add_assoc_zval(*ret, "abbrevmonths", smonths);
283 	add_assoc_long(*ret, "maxdaysinmonth", calendar->max_days_in_month);
284 	add_assoc_string(*ret, "calname", calendar->name, 1);
285 	add_assoc_string(*ret, "calsymbol", calendar->symbol, 1);
286 
287 }
288 
289 /* {{{ proto array cal_info([int calendar])
290    Returns information about a particular calendar */
PHP_FUNCTION(cal_info)291 PHP_FUNCTION(cal_info)
292 {
293 	long cal = -1;
294 
295 
296 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &cal) == FAILURE) {
297 		RETURN_FALSE;
298 	}
299 
300 	if (cal == -1) {
301 		int i;
302 		zval *val;
303 
304 		array_init(return_value);
305 
306 		for (i = 0; i < CAL_NUM_CALS; i++) {
307 			MAKE_STD_ZVAL(val);
308 			_php_cal_info(i, &val);
309 			add_index_zval(return_value, i, val);
310 		}
311 		return;
312 	}
313 
314 
315 	if (cal != -1 && (cal < 0 || cal >= CAL_NUM_CALS)) {
316 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid calendar ID %ld.", cal);
317 		RETURN_FALSE;
318 	}
319 
320 	_php_cal_info(cal, &return_value);
321 
322 }
323 /* }}} */
324 
325 /* {{{ proto int cal_days_in_month(int calendar, int month, int year)
326    Returns the number of days in a month for a given year and calendar */
PHP_FUNCTION(cal_days_in_month)327 PHP_FUNCTION(cal_days_in_month)
328 {
329 	long cal, month, year;
330 	struct cal_entry_t *calendar;
331 	long sdn_start, sdn_next;
332 
333 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &cal, &month, &year) == FAILURE) {
334 		RETURN_FALSE;
335 	}
336 
337 	if (cal < 0 || cal >= CAL_NUM_CALS) {
338 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid calendar ID %ld.", cal);
339 		RETURN_FALSE;
340 	}
341 
342 	calendar = &cal_conversion_table[cal];
343 
344 	sdn_start = calendar->to_jd(year, month, 1);
345 
346 	if (sdn_start == 0) {
347 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid date.");
348 		RETURN_FALSE;
349 	}
350 
351 	sdn_next = calendar->to_jd(year, 1 + month, 1);
352 
353 	if (sdn_next == 0) {
354 		/* If the next month is invalid, then we need to try the first month of
355 		 * the next year, bearing in mind that the next year after 1 BCE is
356 		 * actually 1 AD and not 0. */
357 		if (year == -1) {
358 			sdn_next = calendar->to_jd(1, 1, 1);
359 		}
360 		else {
361 			sdn_next = calendar->to_jd(year + 1, 1, 1);
362 		}
363 	}
364 
365 	RETURN_LONG(sdn_next - sdn_start);
366 }
367 /* }}} */
368 
369 /* {{{ proto int cal_to_jd(int calendar, int month, int day, int year)
370    Converts from a supported calendar to Julian Day Count */
PHP_FUNCTION(cal_to_jd)371 PHP_FUNCTION(cal_to_jd)
372 {
373 	long cal, month, day, year;
374 
375 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "llll", &cal, &month, &day, &year) != SUCCESS) {
376 		RETURN_FALSE;
377 	}
378 
379 	if (cal < 0 || cal >= CAL_NUM_CALS) {
380 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid calendar ID %ld.", cal);
381 		RETURN_FALSE;
382 	}
383 
384 	RETURN_LONG(cal_conversion_table[cal].to_jd(year, month, day));
385 }
386 /* }}} */
387 
388 /* {{{ proto array cal_from_jd(int jd, int calendar)
389    Converts from Julian Day Count to a supported calendar and return extended information */
PHP_FUNCTION(cal_from_jd)390 PHP_FUNCTION(cal_from_jd)
391 {
392 	long jd, cal;
393 	int month, day, year, dow;
394 	char date[16];
395 	struct cal_entry_t *calendar;
396 
397 	if (zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC, "ll", &jd, &cal) == FAILURE) {
398 		RETURN_FALSE;
399 	}
400 
401 	if (cal < 0 || cal >= CAL_NUM_CALS) {
402 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid calendar ID %ld", cal);
403 		RETURN_FALSE;
404 	}
405 	calendar = &cal_conversion_table[cal];
406 
407 	array_init(return_value);
408 
409 	calendar->from_jd(jd, &year, &month, &day);
410 
411 	snprintf(date, sizeof(date), "%i/%i/%i", month, day, year);
412 	add_assoc_string(return_value, "date", date, 1);
413 
414 	add_assoc_long(return_value, "month", month);
415 	add_assoc_long(return_value, "day", day);
416 	add_assoc_long(return_value, "year", year);
417 
418 /* day of week */
419 	dow = DayOfWeek(jd);
420 	add_assoc_long(return_value, "dow", dow);
421 	add_assoc_string(return_value, "abbrevdayname", DayNameShort[dow], 1);
422 	add_assoc_string(return_value, "dayname", DayNameLong[dow], 1);
423 /* month name */
424 	if(cal == CAL_JEWISH) {
425 		/* special case for Jewish calendar */
426 		add_assoc_string(return_value, "abbrevmonth", JEWISH_MONTH_NAME(year)[month], 1);
427 		add_assoc_string(return_value, "monthname", JEWISH_MONTH_NAME(year)[month], 1);
428 	} else {
429 		add_assoc_string(return_value, "abbrevmonth", calendar->month_name_short[month], 1);
430 		add_assoc_string(return_value, "monthname", calendar->month_name_long[month], 1);
431 	}
432 }
433 /* }}} */
434 
435 /* {{{ proto string jdtogregorian(int juliandaycount)
436    Converts a julian day count to a gregorian calendar date */
PHP_FUNCTION(jdtogregorian)437 PHP_FUNCTION(jdtogregorian)
438 {
439 	long julday;
440 	int year, month, day;
441 	char date[16];
442 
443 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &julday) == FAILURE) {
444 		RETURN_FALSE;
445 	}
446 
447 	SdnToGregorian(julday, &year, &month, &day);
448 	snprintf(date, sizeof(date), "%i/%i/%i", month, day, year);
449 
450 	RETURN_STRING(date, 1);
451 }
452 /* }}} */
453 
454 /* {{{ proto int gregoriantojd(int month, int day, int year)
455    Converts a gregorian calendar date to julian day count */
PHP_FUNCTION(gregoriantojd)456 PHP_FUNCTION(gregoriantojd)
457 {
458 	long year, month, day;
459 
460 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &month, &day, &year) == FAILURE) {
461 		RETURN_FALSE;
462 	}
463 
464 	RETURN_LONG(GregorianToSdn(year, month, day));
465 }
466 /* }}} */
467 
468 /* {{{ proto string jdtojulian(int juliandaycount)
469    Convert a julian day count to a julian calendar date */
PHP_FUNCTION(jdtojulian)470 PHP_FUNCTION(jdtojulian)
471 {
472 	long julday;
473 	int year, month, day;
474 	char date[16];
475 
476 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &julday) == FAILURE) {
477 		RETURN_FALSE;
478 	}
479 
480 	SdnToJulian(julday, &year, &month, &day);
481 	snprintf(date, sizeof(date), "%i/%i/%i", month, day, year);
482 
483 	RETURN_STRING(date, 1);
484 }
485 /* }}} */
486 
487 /* {{{ proto int juliantojd(int month, int day, int year)
488    Converts a julian calendar date to julian day count */
PHP_FUNCTION(juliantojd)489 PHP_FUNCTION(juliantojd)
490 {
491 	long year, month, day;
492 
493 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &month, &day, &year) == FAILURE) {
494 		RETURN_FALSE;
495 	}
496 
497 	RETURN_LONG(JulianToSdn(year, month, day));
498 }
499 /* }}} */
500 
501 /* {{{ heb_number_to_chars*/
502 /*
503 caution: the Hebrew format produces non unique result.
504 for example both: year '5' and year '5000' produce '�'.
505 use the numeric one for calculations.
506  */
heb_number_to_chars(int n,int fl,char ** ret)507 static char *heb_number_to_chars(int n, int fl, char **ret)
508 {
509 	char *p, old[18], *endofalafim;
510 
511 	p = endofalafim = old;
512 /*
513    prevents the option breaking the jewish beliefs, and some other
514    critical resources ;)
515  */
516 	if (n > 9999 || n < 1) {
517 		*ret = NULL;
518 		return NULL;
519 	}
520 
521 /* alafim (thousands) case */
522 	if (n / 1000) {
523 		*p = alef_bet[n / 1000];
524 		p++;
525 
526 		if (CAL_JEWISH_ADD_ALAFIM_GERESH & fl) {
527 			*p = '\'';
528 			p++;
529 		}
530 		if (CAL_JEWISH_ADD_ALAFIM & fl) {
531 			strcpy(p, " ����� ");
532 			p += 7;
533 		}
534 
535 		endofalafim = p;
536 		n = n % 1000;
537 	}
538 
539 /* tav-tav (tav=400) case */
540 	while (n >= 400) {
541 		*p = alef_bet[22];
542 		p++;
543 		n -= 400;
544 	}
545 
546 /* meot (hundreads) case */
547 	if (n >= 100) {
548 		*p = alef_bet[18 + n / 100];
549 		p++;
550 		n = n % 100;
551 	}
552 
553 /* tet-vav & tet-zain case (special case for 15 and 16) */
554 	if (n == 15 || n == 16) {
555 		*p = alef_bet[9];
556 		p++;
557 		*p = alef_bet[n - 9];
558 		p++;
559 	} else {
560 /* asarot (tens) case */
561 		if (n >= 10) {
562 			*p = alef_bet[9 + n / 10];
563 			p++;
564 			n = n % 10;
565 		}
566 
567 /* yehidot (ones) case */
568 		if (n > 0) {
569 			*p = alef_bet[n];
570 			p++;
571 		}
572 	}
573 
574 	if (CAL_JEWISH_ADD_GERESHAYIM & fl) {
575 		switch (p - endofalafim) {
576 		case 0:
577 			break;
578 		case 1:
579 			*p = '\'';
580 			p++;
581 			break;
582 		default:
583 			*(p) = *(p - 1);
584 			*(p - 1) = '"';
585 			p++;
586 		}
587 	}
588 
589 	*p = '\0';
590 	*ret = estrndup(old, (p - old) + 1);
591 	p = *ret;
592 	return p;
593 }
594 /* }}} */
595 
596 /* {{{ proto string jdtojewish(int juliandaycount [, bool hebrew [, int fl]])
597    Converts a julian day count to a jewish calendar date */
PHP_FUNCTION(jdtojewish)598 PHP_FUNCTION(jdtojewish)
599 {
600 	long julday, fl = 0;
601 	zend_bool heb   = 0;
602 	int year, month, day;
603 	char date[16], hebdate[32];
604 	char *dayp, *yearp;
605 
606 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|bl", &julday, &heb, &fl) == FAILURE) {
607 		RETURN_FALSE;
608 	}
609 
610 	SdnToJewish(julday, &year, &month, &day);
611 	if (!heb) {
612 		snprintf(date, sizeof(date), "%i/%i/%i", month, day, year);
613 		RETURN_STRING(date, 1);
614 	} else {
615 		if (year <= 0 || year > 9999) {
616 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Year out of range (0-9999).");
617 			RETURN_FALSE;
618 		}
619 
620 		snprintf(hebdate, sizeof(hebdate), "%s %s %s", heb_number_to_chars(day, fl, &dayp), JEWISH_HEB_MONTH_NAME(year)[month], heb_number_to_chars(year, fl, &yearp));
621 
622 		if (dayp) {
623 			efree(dayp);
624 		}
625 		if (yearp) {
626 			efree(yearp);
627 		}
628 
629 		RETURN_STRING(hebdate, 1);
630 
631 	}
632 }
633 /* }}} */
634 
635 /* {{{ proto int jewishtojd(int month, int day, int year)
636    Converts a jewish calendar date to a julian day count */
PHP_FUNCTION(jewishtojd)637 PHP_FUNCTION(jewishtojd)
638 {
639 	long year, month, day;
640 
641 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &month, &day, &year) == FAILURE) {
642 		RETURN_FALSE;
643 	}
644 
645 	RETURN_LONG(JewishToSdn(year, month, day));
646 }
647 /* }}} */
648 
649 /* {{{ proto string jdtofrench(int juliandaycount)
650    Converts a julian day count to a french republic calendar date */
PHP_FUNCTION(jdtofrench)651 PHP_FUNCTION(jdtofrench)
652 {
653 	long julday;
654 	int year, month, day;
655 	char date[16];
656 
657 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &julday) == FAILURE) {
658 		RETURN_FALSE;
659 	}
660 
661 	SdnToFrench(julday, &year, &month, &day);
662 	snprintf(date, sizeof(date), "%i/%i/%i", month, day, year);
663 
664 	RETURN_STRING(date, 1);
665 }
666 /* }}} */
667 
668 /* {{{ proto int frenchtojd(int month, int day, int year)
669    Converts a french republic calendar date to julian day count */
PHP_FUNCTION(frenchtojd)670 PHP_FUNCTION(frenchtojd)
671 {
672 	long year, month, day;
673 
674 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &month, &day, &year) == FAILURE) {
675 		RETURN_FALSE;
676 	}
677 
678 	RETURN_LONG(FrenchToSdn(year, month, day));
679 }
680 /* }}} */
681 
682 /* {{{ proto mixed jddayofweek(int juliandaycount [, int mode])
683    Returns name or number of day of week from julian day count */
PHP_FUNCTION(jddayofweek)684 PHP_FUNCTION(jddayofweek)
685 {
686 	long julday, mode = CAL_DOW_DAYNO;
687 	int day;
688 	char *daynamel, *daynames;
689 
690 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &julday, &mode) == FAILURE) {
691 		RETURN_FALSE;
692 	}
693 
694 	day = DayOfWeek(julday);
695 	daynamel = DayNameLong[day];
696 	daynames = DayNameShort[day];
697 
698 	switch (mode) {
699 	case CAL_DOW_LONG:
700 		RETURN_STRING(daynamel, 1);
701 		break;
702 	case CAL_DOW_SHORT:
703 		RETURN_STRING(daynames, 1);
704 		break;
705 	case CAL_DOW_DAYNO:
706 	default:
707 		RETURN_LONG(day);
708 		break;
709 	}
710 }
711 /* }}} */
712 
713 /* {{{ proto string jdmonthname(int juliandaycount, int mode)
714    Returns name of month for julian day count */
PHP_FUNCTION(jdmonthname)715 PHP_FUNCTION(jdmonthname)
716 {
717 	long julday, mode;
718 	char *monthname = NULL;
719 	int month, day, year;
720 
721 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &julday, &mode) == FAILURE) {
722 		RETURN_FALSE;
723 	}
724 
725 	switch (mode) {
726 	case CAL_MONTH_GREGORIAN_LONG:	/* gregorian or julian month */
727 		SdnToGregorian(julday, &year, &month, &day);
728 		monthname = MonthNameLong[month];
729 		break;
730 	case CAL_MONTH_JULIAN_SHORT:	/* gregorian or julian month */
731 		SdnToJulian(julday, &year, &month, &day);
732 		monthname = MonthNameShort[month];
733 		break;
734 	case CAL_MONTH_JULIAN_LONG:	/* gregorian or julian month */
735 		SdnToJulian(julday, &year, &month, &day);
736 		monthname = MonthNameLong[month];
737 		break;
738 	case CAL_MONTH_JEWISH:		/* jewish month */
739 		SdnToJewish(julday, &year, &month, &day);
740 		monthname = JEWISH_MONTH_NAME(year)[month];
741 		break;
742 	case CAL_MONTH_FRENCH:		/* french month */
743 		SdnToFrench(julday, &year, &month, &day);
744 		monthname = FrenchMonthName[month];
745 		break;
746 	default:					/* default gregorian */
747 	case CAL_MONTH_GREGORIAN_SHORT:	/* gregorian or julian month */
748 		SdnToGregorian(julday, &year, &month, &day);
749 		monthname = MonthNameShort[month];
750 		break;
751 	}
752 
753 	RETURN_STRING(monthname, 1);
754 }
755 /* }}} */
756 
757 /*
758  * Local variables:
759  * tab-width: 4
760  * c-basic-offset: 4
761  * End:
762  * vim600: sw=4 ts=4 fdm=marker
763  * vim<600: sw=4 ts=4
764  */
765