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