php-src/ext/calendar/calendar.c

643 lines
18 KiB
C
Raw Normal View History

/*
+----------------------------------------------------------------------+
2001-12-11 15:32:16 +00:00
| PHP Version 4 |
+----------------------------------------------------------------------+
2001-12-11 15:32:16 +00:00
| Copyright (c) 1997-2002 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 2.02 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| http://www.php.net/license/2_02.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Shane Caraveo <shane@caraveo.com> |
2002-09-19 21:51:34 +00:00
| Colin Viebrock <colin@easydns.com> |
| Hartmut Holzgraefe <hartmut@six.de> |
| Wez Furlong <wez@thebrainroom.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2001-07-06 09:51:03 +00:00
#ifdef PHP_WIN32
#define _WINNLS_
#endif
#include "php.h"
2000-10-08 10:55:09 +00:00
#include "ext/standard/info.h"
#include "php_calendar.h"
#include "sdncal.h"
#include <stdio.h>
function_entry calendar_functions[] = {
PHP_FE(jdtogregorian, NULL)
PHP_FE(gregoriantojd, NULL)
PHP_FE(jdtojulian, NULL)
PHP_FE(juliantojd, NULL)
PHP_FE(jdtojewish, NULL)
PHP_FE(jewishtojd, NULL)
PHP_FE(jdtofrench, NULL)
PHP_FE(frenchtojd, NULL)
PHP_FE(jddayofweek, NULL)
PHP_FE(jdmonthname, NULL)
PHP_FE(easter_date, NULL)
PHP_FE(easter_days, NULL)
PHP_FE(unixtojd, NULL)
PHP_FE(jdtounix, NULL)
PHP_FE(cal_to_jd, NULL)
PHP_FE(cal_from_jd, NULL)
PHP_FE(cal_days_in_month, NULL)
PHP_FE(cal_info, NULL)
{NULL, NULL, NULL}
};
zend_module_entry calendar_module_entry = {
STANDARD_MODULE_HEADER,
"calendar",
calendar_functions,
PHP_MINIT(calendar),
NULL,
NULL,
NULL,
PHP_MINFO(calendar),
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES,
};
2000-05-23 13:46:16 +00:00
#ifdef COMPILE_DL_CALENDAR
ZEND_GET_MODULE(calendar)
#endif
/* this order must match the conversion table below */
enum cal_name_type_t {
CAL_GREGORIAN = 0,
CAL_JULIAN,
CAL_JEWISH,
CAL_FRENCH,
CAL_NUM_CALS
};
typedef long int (*cal_to_jd_func_t)(int month, int day, int year);
typedef void (*cal_from_jd_func_t)(long int jd, int* year, int* month, int* day);
typedef char* (*cal_as_string_func_t)(int year, int month, int day);
struct cal_entry_t {
char * name;
char * symbol;
cal_to_jd_func_t to_jd;
cal_from_jd_func_t from_jd;
int num_months;
int max_days_in_month;
char ** month_name_short;
char ** month_name_long;
};
static struct cal_entry_t cal_conversion_table[CAL_NUM_CALS] = {
{ "Gregorian", "CAL_GREGORIAN", GregorianToSdn, SdnToGregorian, 12, 31, MonthNameShort, MonthNameLong },
{ "Julian", "CAL_JULIAN", JulianToSdn, SdnToJulian, 12, 31, MonthNameShort, MonthNameLong },
{ "Jewish", "CAL_JEWISH", JewishToSdn, SdnToJewish, 13, 30, JewishMonthName, JewishMonthName },
{ "French", "CAL_FRENCH", FrenchToSdn, SdnToFrench, 13, 30, FrenchMonthName, FrenchMonthName }
};
/* For jddayofweek */
enum { CAL_DOW_DAYNO, CAL_DOW_SHORT, CAL_DOW_LONG };
/* For jdmonthname */
enum { CAL_MONTH_GREGORIAN_SHORT, CAL_MONTH_GREGORIAN_LONG,
CAL_MONTH_JULIAN_SHORT, CAL_MONTH_JULIAN_LONG, CAL_MONTH_JEWISH,
CAL_MONTH_FRENCH };
/* for heb_number_to_chars */
char alef_bet[25] = "0<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
PHP_MINIT_FUNCTION(calendar)
{
REGISTER_LONG_CONSTANT("CAL_GREGORIAN", CAL_GREGORIAN, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_JULIAN", CAL_JULIAN, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_JEWISH", CAL_JEWISH, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_FRENCH", CAL_FRENCH, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_NUM_CALS", CAL_NUM_CALS, CONST_CS|CONST_PERSISTENT);
/* constants for jddayofweek */
REGISTER_LONG_CONSTANT("CAL_DOW_DAYNO", CAL_DOW_DAYNO, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_DOW_SHORT", CAL_DOW_SHORT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_DOW_LONG", CAL_DOW_LONG, CONST_CS|CONST_PERSISTENT);
/* constants for jdmonthname */
REGISTER_LONG_CONSTANT("CAL_MONTH_GREGORIAN_SHORT", CAL_MONTH_GREGORIAN_SHORT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_MONTH_GREGORIAN_LONG", CAL_MONTH_GREGORIAN_LONG, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_MONTH_JULIAN_SHORT", CAL_MONTH_JULIAN_SHORT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_MONTH_JULIAN_LONG", CAL_MONTH_JULIAN_LONG, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_MONTH_JEWISH", CAL_MONTH_JEWISH, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_MONTH_FRENCH", CAL_MONTH_FRENCH, CONST_CS|CONST_PERSISTENT);
/* constants for easter calculation */
REGISTER_LONG_CONSTANT("CAL_EASTER_DEFAULT", CAL_EASTER_DEFAULT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_EASTER_ROMAN", CAL_EASTER_ROMAN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_EASTER_ALWAYS_GREGORIAN", CAL_EASTER_ALWAYS_GREGORIAN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_EASTER_ALWAYS_JULIAN", CAL_EASTER_ALWAYS_JULIAN, CONST_CS | CONST_PERSISTENT);
return SUCCESS;
}
PHP_MINFO_FUNCTION(calendar)
{
2000-10-08 10:55:09 +00:00
php_info_print_table_start();
php_info_print_table_row(2, "Calendar support", "enabled");
php_info_print_table_end();
}
/* {{{ proto array cal_info(int calendar)
2001-09-04 21:07:17 +00:00
Returns information about a particular calendar */
PHP_FUNCTION(cal_info)
{
zval ** cal;
zval * months, *smonths;
int i;
struct cal_entry_t * calendar;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &cal) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(cal);
if (Z_LVAL_PP(cal) < 0 || Z_LVAL_PP(cal) >= CAL_NUM_CALS) {
2001-07-30 08:24:42 +00:00
zend_error(E_WARNING, "%s(): invalid calendar ID %d", get_active_function_name(TSRMLS_C), Z_LVAL_PP(cal));
RETURN_FALSE;
}
calendar = &cal_conversion_table[Z_LVAL_PP(cal)];
array_init(return_value);
MAKE_STD_ZVAL(months);
MAKE_STD_ZVAL(smonths);
array_init(months);
array_init(smonths);
for (i=1; i<= calendar->num_months; i++) {
add_index_string(months, i, calendar->month_name_long[i], 1);
add_index_string(smonths, i, calendar->month_name_short[i], 1);
}
add_assoc_zval(return_value, "months", months);
add_assoc_zval(return_value, "abbrevmonths", smonths);
add_assoc_long(return_value, "maxdaysinmonth", calendar->max_days_in_month);
add_assoc_string(return_value, "calname", calendar->name, 1);
add_assoc_string(return_value, "calsymbol", calendar->symbol, 1);
}
/* }}} */
/* {{{ proto int cal_days_in_month(int calendar, int month, int year)
2001-09-04 21:07:17 +00:00
Returns the number of days in a month for a given year and calendar */
PHP_FUNCTION(cal_days_in_month)
{
zval ** cal, **month, **year;
struct cal_entry_t * calendar;
long sdn_start, sdn_next;
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &cal, &month, &year) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(cal);
convert_to_long_ex(month);
convert_to_long_ex(year);
if (Z_LVAL_PP(cal) < 0 || Z_LVAL_PP(cal) >= CAL_NUM_CALS) {
2001-07-30 08:24:42 +00:00
zend_error(E_WARNING, "%s(): invalid calendar ID %d", get_active_function_name(TSRMLS_C), Z_LVAL_PP(cal));
RETURN_FALSE;
}
calendar = &cal_conversion_table[Z_LVAL_PP(cal)];
sdn_start = calendar->to_jd(Z_LVAL_PP(year), Z_LVAL_PP(month), 1);
sdn_next = calendar->to_jd(Z_LVAL_PP(year), 1 + Z_LVAL_PP(month), 1);
if (sdn_next == 0) {
/* if invalid, try first month of the next year... */
sdn_next = calendar->to_jd(Z_LVAL_PP(year) + 1, 1, 1);
}
RETURN_LONG(sdn_next - sdn_start);
}
/* }}} */
/* {{{ proto int cal_to_jd(int calendar, int month, int day, int year)
2001-09-04 21:07:17 +00:00
Converts from a supported calendar to Julian Day Count */
PHP_FUNCTION(cal_to_jd)
{
zval ** cal, **month, **day, **year;
long jdate;
if (ZEND_NUM_ARGS() != 4 || zend_get_parameters_ex(4, &cal, &month, &day, &year) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(cal);
convert_to_long_ex(month);
convert_to_long_ex(day);
convert_to_long_ex(year);
if (Z_LVAL_PP(cal) < 0 || Z_LVAL_PP(cal) >= CAL_NUM_CALS) {
2001-07-30 08:24:42 +00:00
zend_error(E_WARNING, "%s(): invalid calendar ID %d", get_active_function_name(TSRMLS_C), Z_LVAL_PP(cal));
RETURN_FALSE;
}
jdate = cal_conversion_table[Z_LVAL_PP(cal)].to_jd(
Z_LVAL_PP(year), Z_LVAL_PP(month), Z_LVAL_PP(day));
RETURN_LONG(jdate);
}
/* }}} */
/* {{{ proto array cal_from_jd(int jd, int calendar)
2001-09-04 21:07:17 +00:00
Converts from Julian Day Count to a supported calendar and return extended information */
PHP_FUNCTION(cal_from_jd)
{
zval ** jd, ** cal;
int month, day, year, dow;
char date[16];
struct cal_entry_t * calendar;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &jd, &cal) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(jd);
convert_to_long_ex(cal);
if (Z_LVAL_PP(cal) < 0 || Z_LVAL_PP(cal) >= CAL_NUM_CALS) {
2001-07-30 08:24:42 +00:00
zend_error(E_WARNING, "%s(): invalid calendar ID %d", get_active_function_name(TSRMLS_C), Z_LVAL_PP(cal));
RETURN_FALSE;
}
calendar = &cal_conversion_table[Z_LVAL_PP(cal)];
array_init(return_value);
calendar->from_jd(
Z_LVAL_PP(jd),
&year, &month, &day);
sprintf(date, "%i/%i/%i", month, day, year);
add_assoc_string(return_value, "date", date, 1);
add_assoc_long(return_value, "month", month);
add_assoc_long(return_value, "day", day);
add_assoc_long(return_value, "year", year);
/* day of week */
dow = DayOfWeek(Z_LVAL_PP(jd));
add_assoc_long(return_value, "dow", dow);
add_assoc_string(return_value, "abbrevdayname", DayNameShort[dow], 1);
add_assoc_string(return_value, "dayname", DayNameLong[dow], 1);
/* month name */
add_assoc_string(return_value, "abbrevmonth", calendar->month_name_short[month], 1);
add_assoc_string(return_value, "monthname", calendar->month_name_long[month], 1);
}
/* }}} */
/* {{{ proto string jdtogregorian(int juliandaycount)
2001-09-04 21:07:17 +00:00
Converts a julian day count to a gregorian calendar date */
PHP_FUNCTION(jdtogregorian)
{
pval **julday;
int year, month, day;
char date[10];
if (zend_get_parameters_ex(1, &julday) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(julday);
SdnToGregorian(Z_LVAL_PP(julday), &year, &month, &day);
sprintf(date, "%i/%i/%i", month, day, year);
2001-08-11 16:39:07 +00:00
RETURN_STRING(date, 1);
}
/* }}} */
/* {{{ proto int gregoriantojd(int month, int day, int year)
2001-09-04 21:07:17 +00:00
Converts a gregorian calendar date to julian day count */
PHP_FUNCTION(gregoriantojd)
{
pval **year, **month, **day;
int jdate;
if (zend_get_parameters_ex(3, &month, &day, &year) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(month);
convert_to_long_ex(day);
convert_to_long_ex(year);
jdate = GregorianToSdn(Z_LVAL_PP(year), Z_LVAL_PP(month), Z_LVAL_PP(day));
RETURN_LONG(jdate);
}
/* }}} */
/* {{{ proto string jdtojulian(int juliandaycount)
Convert a julian day count to a julian calendar date */
PHP_FUNCTION(jdtojulian)
{
pval **julday;
int year, month, day;
char date[10];
if (zend_get_parameters_ex(1, &julday) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(julday);
SdnToJulian(Z_LVAL_PP(julday), &year, &month, &day);
sprintf(date, "%i/%i/%i", month, day, year);
2001-08-11 16:39:07 +00:00
RETURN_STRING(date, 1);
}
/* }}} */
/* {{{ proto int juliantojd(int month, int day, int year)
2001-09-04 21:07:17 +00:00
Converts a julian calendar date to julian day count */
PHP_FUNCTION(juliantojd)
{
pval **year, **month, **day;
int jdate;
if (zend_get_parameters_ex(3, &month, &day, &year) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(month);
convert_to_long_ex(day);
convert_to_long_ex(year);
jdate = JulianToSdn(Z_LVAL_PP(year), Z_LVAL_PP(month), Z_LVAL_PP(day));
RETURN_LONG(jdate);
}
/* }}} */
/*
caution: the hebrew format product non unique result.
for example both: year '5' and year '5000' product '<EFBFBD>'.
use the numeric one for calculations.
*/
char* heb_number_to_chars(int n) {
char *p, *old, *ret;
p = emalloc(10);
old = p;
/*
prevents the option breaking the jewish beliefs, and some other
critical resources ;)
*/
if (n > 9999 || n < 1) return NULL;
/* alafim case */
if (n / 1000) {
*p = alef_bet[n / 1000];
p++;
n = n % 1000;
}
/* taf-taf case */
while (n >= 400) {
*p = alef_bet[22];
p++;
n-=400;
}
/* meot case */
if (n >= 100) {
*p = alef_bet[18+n/100];
p++;
n = n % 100;
}
/* tet-vav tet-zain case */
if (n == 15 || n == 16) {
*p = alef_bet[9];
p++;
*p = alef_bet[n-9];
p++;
} else {
/* asarot case */
if (n >= 10) {
*p = alef_bet[9+n/10];
p++;
n = n % 10;
}
/* yeihot case */
if (n > 0) {
*p = alef_bet[n];
p++;
}
}
*p = '\0';
ret = emalloc((int) (p - old) + 1);
strncpy(ret, old, (int) (p - old) + 1);
return ret;
}
/* {{{ proto string jdtojewish(int juliandaycount)
2001-09-04 21:07:17 +00:00
Converts a julian day count to a jewish calendar date */
PHP_FUNCTION(jdtojewish)
{
long julday, fl;
int year, month, day;
char date[10], hebdate[25];
if (ZEND_NUM_ARGS() == 1) {
if (zend_parse_parameters(1 TSRMLS_CC,"l", &julday) != SUCCESS) {
RETURN_FALSE;
}
fl=0;
} else if (ZEND_NUM_ARGS() == 2) {
if (zend_parse_parameters(2 TSRMLS_CC,"ll", &julday, &fl) != SUCCESS) {
RETURN_FALSE;
}
} else {
WRONG_PARAM_COUNT;
}
SdnToJewish(julday, &year, &month, &day);
if(!fl) {
sprintf(date, "%i/%i/%i", month, day, year);
RETURN_STRING(date, 1);
} else {
if (year <= 0 || year > 9999) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Out of range year.");
RETURN_FALSE;
}
sprintf(hebdate, "%s %s %s", \
heb_number_to_chars(day), \
JewishMonthHebName[month], \
heb_number_to_chars(year));
RETURN_STRING(hebdate, 1);
}
}
/* }}} */
/* {{{ proto int jewishtojd(int month, int day, int year)
2001-09-04 21:07:17 +00:00
Converts a jewish calendar date to a julian day count */
PHP_FUNCTION(jewishtojd)
{
pval **year, **month, **day;
int jdate;
if (zend_get_parameters_ex(3, &month, &day, &year) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(month);
convert_to_long_ex(day);
convert_to_long_ex(year);
jdate = JewishToSdn(Z_LVAL_PP(year), Z_LVAL_PP(month), Z_LVAL_PP(day));
RETURN_LONG(jdate);
}
/* }}} */
/* {{{ proto string jdtofrench(int juliandaycount)
2001-09-04 21:07:17 +00:00
Converts a julian day count to a french republic calendar date */
PHP_FUNCTION(jdtofrench)
{
pval **julday;
int year, month, day;
char date[10];
if (zend_get_parameters_ex(1, &julday) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(julday);
SdnToFrench(Z_LVAL_PP(julday), &year, &month, &day);
sprintf(date, "%i/%i/%i", month, day, year);
2001-08-11 16:39:07 +00:00
RETURN_STRING(date, 1);
}
/* }}} */
/* {{{ proto int frenchtojd(int month, int day, int year)
2001-09-04 21:07:17 +00:00
Converts a french republic calendar date to julian day count */
PHP_FUNCTION(frenchtojd)
{
pval **year, **month, **day;
int jdate;
if (zend_get_parameters_ex(3, &month, &day, &year) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(month);
convert_to_long_ex(day);
convert_to_long_ex(year);
jdate = FrenchToSdn(Z_LVAL_PP(year), Z_LVAL_PP(month), Z_LVAL_PP(day));
RETURN_LONG(jdate);
}
/* }}} */
2000-04-16 16:02:31 +00:00
/* {{{ proto mixed jddayofweek(int juliandaycount [, int mode])
Returns name or number of day of week from julian day count */
PHP_FUNCTION(jddayofweek)
{
pval *julday, *mode;
int day;
char *daynamel, *daynames;
2001-08-11 16:39:07 +00:00
int myargc=ZEND_NUM_ARGS(), mymode=0;
2001-08-11 16:39:07 +00:00
if ((myargc < 1) || (myargc > 2) || (zend_get_parameters(ht, myargc, &julday, &mode) != SUCCESS)) {
WRONG_PARAM_COUNT;
}
convert_to_long(julday);
if(myargc==2) {
convert_to_long(mode);
mymode = Z_LVAL_P(mode);
}
day = DayOfWeek(Z_LVAL_P(julday));
daynamel = DayNameLong[day];
daynames = DayNameShort[day];
switch (mymode) {
case CAL_DOW_SHORT:
2001-08-11 16:39:07 +00:00
RETURN_STRING(daynamel, 1);
break;
case CAL_DOW_LONG:
2001-08-11 16:39:07 +00:00
RETURN_STRING(daynames, 1);
break;
case CAL_DOW_DAYNO:
default:
RETURN_LONG(day);
break;
}
}
/* }}} */
/* {{{ proto string jdmonthname(int juliandaycount, int mode)
Returns name of month for julian day count */
PHP_FUNCTION(jdmonthname)
{
pval **julday, **mode;
char *monthname = NULL;
int month, day, year;
if (zend_get_parameters_ex(2, &julday, &mode) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(julday);
convert_to_long_ex(mode);
switch(Z_LVAL_PP(mode)) {
case CAL_MONTH_GREGORIAN_LONG: /* gregorian or julian month */
SdnToGregorian(Z_LVAL_PP(julday), &year, &month, &day);
monthname = MonthNameLong[month];
break;
case CAL_MONTH_JULIAN_SHORT: /* gregorian or julian month */
SdnToJulian(Z_LVAL_PP(julday), &year, &month, &day);
monthname = MonthNameShort[month];
break;
case CAL_MONTH_JULIAN_LONG: /* gregorian or julian month */
SdnToJulian(Z_LVAL_PP(julday), &year, &month, &day);
monthname = MonthNameLong[month];
break;
case CAL_MONTH_JEWISH: /* jewish month */
SdnToJewish(Z_LVAL_PP(julday), &year, &month, &day);
monthname = JewishMonthName[month];
break;
case CAL_MONTH_FRENCH: /* french month */
SdnToFrench(Z_LVAL_PP(julday), &year, &month, &day);
monthname = FrenchMonthName[month];
break;
default: /* default gregorian */
case CAL_MONTH_GREGORIAN_SHORT: /* gregorian or julian month */
SdnToGregorian(Z_LVAL_PP(julday), &year, &month, &day);
monthname = MonthNameShort[month];
break;
}
2001-08-11 16:39:07 +00:00
RETURN_STRING(monthname, 1);
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/