/* * event.c -- event manage * * Copyright (C) 1989,1997,1999,2001,2003 by Yoshifumi Mori * * tab:4 */ #include "cdefs.h" #include "extern.h" #define total_weekofyear 53 /* 年間53週 */ #define PARAM_COUNT 32 /* トークン最大分割数 */ #define SET_DAY '\xFF' #define CLEAR_DAY '\0' #define MAXHIT 8 #define MAXFLAG 64 #define WEEK(x) (((x) - 1) / 7 + 1) #define LVAR(x) event_level_var[(x)-'a'] #define EV_YEAR_ERR 0 #define EV_YEAR_YEAR 1 #define EV_YEAR_DATE 2 struct DATE_MD { int month; int day; }; char *event_filetbl[MAXEVENTFILE]; char *week_filetbl[MAXWEEKFILE]; char *event_sortorder; int event_notice_range = NOTICE_DEFAULT_RANGE; int event_notice_flag = NOTICE_MARK_ONLY; int event_range_flag = TRUE; char *event_level_str; static char pbuff[PARAM_COUNT * 8]; static char *param[PARAM_COUNT]; static struct SRANGE_T rangetbl[PARAM_COUNT]; static int event_sortflag; static int event_sortorder_tbl[MAXSORTITEM]; /* 今日_昨日_明日 */ static int message_counter; static int event_msg_level_default; static int event_msg_level; static char event_level_var[MAXLVAR]; static int endofmonth; static int endofyear; static int start_dayofyear, end_dayofyear; static int start_weekofyear, end_weekofyear; static int start_dayofweek, end_dayofweek; static long start_julian, end_julian; static int current_year; static int current_month; static int current_day; static int current_leap; static int current_offsetday; static int current_mode; static int current_weekcount; static int focus_flag; enum { EVENT_MODE, LC_EVENT_MODE, }; static int dayshift_direction; static int dayshift_skip_saturday; static char pinpoint_daytbl[MAX_DAYOFMONTH], pinpoint_masktbl[MAX_DAYOFMONTH]; static int pinpoint_hittbl[MAXHIT]; static unsigned char evflag[(MAXFLAG + 7) / 8]; static void setup_event_level(void); static void event_out(const char *msg, ...); static void event_main(void); static void setup_eventmode(int index); static void setup_lc_eventmode(int index); static void call_eventsearch(void); static int eventSearch(const char *filename); static void ctrl_msg_proc(char *bp); static int analysis_ev_day(char *bp); static int analysis_ev_whatday(char *bp); static int analysis_ev_week(char *bp); static int analysis_ev_month(char *bp); static int analysis_ev_year(char *bp); static int analysis_year_date(const char *p, int *year, long *jul); static int pickup_event(int notice_range); static int pickup_lc_event(int notice_range); static void pinpoint_dayclear(void); static void pinpoint_maskclear(void); static int pinpoint_day(void); static void event_week(void); static int weekSearch(const char *filename); static int check_week(struct DATE_MD *begin, struct DATE_MD *end); static void output_eventlist(int type, char *msg, int diffday, int rangeflag); static int skipHoliday(int day); static void makerange(char *msg); /* * イベントの表示 * * 各ファイルを順に処理する */ void event(void) { unsigned int hol_attr; char *hol_name; event_sortflag = TRUE; event_sortorder_tbl[0] = 0; event_sortorder_tbl[1] = 1; event_sortorder_tbl[2] = 2; message_counter = 0; if (event_notice_range < 0 || event_notice_range > MAX_DAYOFMONTH) { event_notice_range = NOTICE_DEFAULT_RANGE; errprint("event", ERR_WARN, "event_notice_range error, default %d set", event_notice_range); } event_sortflag = analysis_sortorder("event", event_sortorder, event_sortorder_tbl, event_sortflag); setup_event_level(); list_init(); hol_attr = holiday_tbl[calendar.day + monthtbl[CENTER_MONTH].offset_day - 1]; if ((hol_attr & SET_HOLID) == SET_HOLID) { hol_name = GetHolidayName(GET_HOLNAMEI(hol_attr)); if (hol_name != NULL) { event_msg_level = LVAR('a'); event_out(hol_name); free(hol_name); } } event_msg_level = LVAR('b'); memset(evflag, '\0', sizeof(evflag)); rekichu(evflag, event_out); event_main(); event_week(); output_eventlist(0, NULL, 0, FALSE); list_free(); } /* * レベル変数の設定 */ static void setup_event_level(void) { char *p; int i, n; memset(event_level_var, 99, sizeof(event_level_var)); if (event_level_str != NULL) { p = event_level_str; i = 0; while (*p != '\0' && i < MAXLVAR) { if (sscanf(p, "%02d", &n) != 1) { break; } event_level_var[i++] = (char)n; p += 2; } } } /* * イベントメッセージ表示処理の呼び出し */ static void event_out(const char *msg, ...) { char msgtmp[64]; va_list ap; va_start(ap, msg); vsprintf(msgtmp, msg, ap); va_end(ap); output_eventlist(1, msgtmp, 0, FALSE); } /* * 前後3か月分のイベント処理を起動(メイン) */ static void event_main(void) { int i; for (i = 0; i < MAX_MONTH_TBL; i++) { focus_flag = (i == CENTER_MONTH) ? TRUE : FALSE; setup_eventmode(i); call_eventsearch(); if (calendar.lc_valid == TRUE && calendar.lc_tbl == TRUE) { setup_lc_eventmode(i); call_eventsearch(); } } } /* * イベント検索/抽出用データの初期化 */ static void setup_eventmode(int index) { endofyear = GetDayofYear(calendar.year, 12, 31); endofmonth = monthtbl[index].dayofmonth; start_dayofyear = GetDayofYear(monthtbl[index].year, monthtbl[index].month, 1); end_dayofyear = GetDayofYear(monthtbl[index].year, monthtbl[index].month, monthtbl[index].dayofmonth); start_weekofyear = WEEK(start_dayofyear); end_weekofyear = WEEK(end_dayofyear); start_dayofweek = monthtbl[index].first_dayofweek; end_dayofweek = monthtbl[index].last_dayofweek; start_julian = Julian(monthtbl[index].year, monthtbl[index].month, 1); end_julian = Julian(monthtbl[index].year, monthtbl[index].month, monthtbl[index].dayofmonth); current_year = monthtbl[index].year; current_month = monthtbl[index].month; current_day = calendar.day; current_leap = monthtbl[index].leap; current_offsetday = monthtbl[index].offset_day; current_mode = EVENT_MODE; current_weekcount = 7; } /* * 旧暦イベント検索/抽出用データの初期化 */ static void setup_lc_eventmode(int index) { endofyear = 0; endofmonth = monthtbl[index].lc.dayofmonth; start_dayofyear = 0; end_dayofyear = 0; start_weekofyear = 0; end_weekofyear = 0; start_dayofweek = monthtbl[index].lc.first_dayofweek; end_dayofweek = monthtbl[index].lc.last_dayofweek; start_julian = 0L; end_julian = 0L; current_year = monthtbl[index].lc.year; current_month = monthtbl[index].lc.month; current_day = calendar.lc_day; current_leap = monthtbl[index].lc.leap; current_offsetday = monthtbl[index].lc.offset_day; current_mode = LC_EVENT_MODE; current_weekcount = 6; } /* * 各イベント登録ファイルを処理する */ static void call_eventsearch(void) { int i; const char *filename; event_msg_level_default = LVAR('i'); for (i = 0; i < MAXEVENTFILE; i++) { if (event_filetbl[i] != NULL) { filename = make_filename2(event_filetbl[i], current_year, current_month, current_day); eventSearch(filename); } } } /* * ファイルからイベントを検索/抽出する * * return value: * TRUE 正常終了 * FALSE エラー発生(ファイルオープン時) * * file format: * [+n] [<>|&]day whatday week month [year] message */ static int eventSearch(const char *infile) { char *bp; char *lasts; if (openfile(infile)) { return (FALSE); } event_msg_level = event_msg_level_default; while ((bp = getfile()) != NULL) { char *eventmessage; int flag_day, flag_whatday, flag_week; int notice_range; int notice_force_range; int rangeflag; int hitcnt; int i; int diffday; if (*bp == '$') { ctrl_msg_proc(bp); continue; } notice_range = 0; /* notice off */ notice_force_range = FALSE; if (*bp == '+') { lasts = NULL; bp = strtok_r(bp, fmt_sep3, &lasts); if (bp == NULL) { continue; } bp++; /* skip '+' */ notice_range = event_notice_range; if (isdigit((unsigned char)*bp) != 0) { notice_range = (int)strtol(bp, &bp, 10); notice_force_range = TRUE; } bp = NULL; } if (event_notice_flag == NOTICE_NO) { notice_range = 0; /* notice off */ } else if (event_notice_flag == NOTICE_ALL) { if (notice_range == 0 && notice_force_range == FALSE) { notice_range = event_notice_range; } } bp = strtok_r(bp, fmt_sep3, &lasts); if (bp == NULL) { continue; } dayshift_direction = 0; dayshift_skip_saturday = FALSE; switch (*bp) { case '&': /* 旧暦指定 */ if (current_mode == EVENT_MODE) { continue; } if (notice_range == 0 && focus_flag == FALSE) { continue; } bp++; break; case '<': dayshift_direction = -1; goto dayshift_check; case '>': dayshift_direction = 1; dayshift_check: if (current_mode == LC_EVENT_MODE) { continue; } bp++; if (bp[0] == bp[-1]) { dayshift_skip_saturday = TRUE; bp++; } break; default: if (current_mode == LC_EVENT_MODE) { continue; } if (notice_range == 0 && focus_flag == FALSE) { continue; } break; } pinpoint_dayclear(); flag_day = analysis_ev_day(bp); bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL) { continue; } flag_whatday = analysis_ev_whatday(bp); bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL) { continue; } flag_week = analysis_ev_week(bp); if (flag_day == FALSE && flag_whatday == FALSE && flag_week == FALSE) { continue; } bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL) { continue; } if (analysis_ev_month(bp) == FALSE) { continue; } bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL) { continue; } if (analysis_ev_year(bp) == FALSE) { continue; } bp = strtok_r(NULL, fmt_sep4, &lasts); if (bp == NULL) { continue; } eventmessage = strip(bp); rangeflag = FALSE; if (flag_day == TRUE && flag_whatday == FALSE && flag_week == FALSE && rangetbl[0].start != 0) { rangeflag = TRUE; } if (current_mode == EVENT_MODE) { hitcnt = pickup_event(notice_range); } else { hitcnt = pickup_lc_event(notice_range); } for (i = 0; i < hitcnt; i++) { diffday = pinpoint_hittbl[i]; if (diffday == 0) { output_eventlist(1, eventmessage, 0, rangeflag); } else { output_eventlist(3, eventmessage, diffday, rangeflag); } } } closefile(); return (TRUE); } /* * メッセージコントロール処理 * * ${ctrl} * * ctrl: Lnn メッセージレベル 0-99 * Lx メッセージレベル変数 a-z, A-Z * L@,L メッセージレベルリセット */ static void ctrl_msg_proc(char *bp) { char *ep; bp++; while (*bp != '\0') { switch (*bp) { case 'L': bp++; if (isdigit(*bp) != 0) { event_msg_level = strtol(bp, &ep, 10); bp = ep; } else if (isalpha(*bp) != 0) { event_msg_level = LVAR(tolower(*bp)); bp++; } else if (*bp == '@' || *bp == '\0') { event_msg_level = event_msg_level_default; } break; default: bp++; break; } } } /* * 日付の解析(旧暦対応) * * 旧暦時は !nn は使用できない * %n は予告および日にち変動ができない * * return value: * TRUE pinpoint_daytbl[] を更新 * FALSE 未更新 '0' が指定されたため、日は無視 */ static int analysis_ev_day(char *bp) { int change_masktbl = FALSE; int pcnt; int pc; pcnt = separate_param(bp, pbuff, param, PARAM_COUNT, rangetbl); pinpoint_maskclear(); for (pc = 0; pc < pcnt; pc++) { const char *pp; int pday; int pf; pp = param[pc]; if (*pp == '%') { /* 特殊日付 */ pf = atoi(pp + 1); if (pf < 1 || pf > MAXFLAG) { continue; } pf--; if (focus_flag == TRUE && CHKBIT(pf, evflag) != 0) { pday = calendar.day; } else { continue; } } else if (*pp == '!') { /* 年頭からの通算日 */ pday = atoi(pp + 1); if (pday < 0) { pday += endofyear + 1; } if (pday < start_dayofyear || pday > end_dayofyear) { continue; } pday -= start_dayofyear - 1; } else { /* 一般の日 */ pday = atoi(pp); if (pday < 0) { pday += endofmonth + 1; } } if (pday > 0 && pday <= endofmonth) { pinpoint_masktbl[pday - 1] = SET_DAY; change_masktbl = TRUE; } } if (change_masktbl == FALSE) { return (FALSE); } return (pinpoint_day()); } /* * 曜日の解析(旧暦対応) * * return value: * TRUE pinpoint_daytbl[] を更新 * FALSE 未更新 '0' が指定されたため、曜日は無視 */ static int analysis_ev_whatday(char *bp) { int change_masktbl = FALSE; int pcnt; int pc; pcnt = separate_param(bp, pbuff, param, PARAM_COUNT, NULL); pinpoint_maskclear(); for (pc = 0; pc < pcnt; pc++) { const char *pp; int pwhatday; pp = param[pc]; pwhatday = atoi(pp); if (pwhatday != 0) { int i; i = pwhatday - (start_dayofweek + 1) + 1; if (i < 1) { i += current_weekcount; } while (i > 0 && i <= endofmonth) { pinpoint_masktbl[i - 1] = SET_DAY; i += current_weekcount; change_masktbl = TRUE; } } } if (change_masktbl == FALSE) { return (FALSE); } return (pinpoint_day()); } /* * 週の解析(旧暦対応) * * 旧暦時は、 !nn, %nn, .nn は使用できない * * return value: * TRUE pinpoint_daytbl[] を更新 * FALSE 未更新 '0' が指定されたため、週は無視 */ static int analysis_ev_week(char *bp) { int change_masktbl = FALSE; int pcnt; int pc; pcnt = separate_param(bp, pbuff, param, PARAM_COUNT, NULL); pinpoint_maskclear(); for (pc = 0; pc < pcnt; pc++) { const char *pp; int pweek; int previously_change_masktbl = FALSE; int start_day_range = 0; pp = param[pc]; if (*pp == '!') { /* 年頭からの通算週 */ pweek = atoi(pp + 1); if (pweek < 0) { pweek += total_weekofyear + 1; } if (pweek < start_weekofyear || pweek > end_weekofyear) { continue; } start_day_range = (pweek - 1) * current_weekcount + 1 - start_dayofyear + 1; } else if (*pp == '%') { /* 隔週 */ pweek = atoi(pp + 1); if (pweek != 0) { int i; int mod_week; mod_week = pweek % 2; previously_change_masktbl = TRUE; for (i = 0; i < MAX_DAYOFMONTH; i++) { pweek = (start_dayofyear + i - 1) / current_weekcount + 1; if ((pweek % 2) == mod_week) { pinpoint_masktbl[i] = SET_DAY; change_masktbl = TRUE; } } } } else if (*pp == '.') { /* カレンダーの横の週 */ pweek = atoi(pp + 1); if (pweek == 0) { ; } else if (pweek < 0) { start_day_range = endofmonth - end_dayofweek + (pweek - 1) * current_weekcount; } else { start_day_range = 1 - start_dayofweek + (pweek - 1) * current_weekcount; } } else { /* 一般の週 */ pweek = atoi(pp); if (pweek == 0) { ; } else if (pweek < 0) { start_day_range = endofmonth + pweek * current_weekcount + 1; } else { start_day_range = 1 + (pweek - 1) * current_weekcount; } } if (pweek != 0 && previously_change_masktbl == FALSE) { int i; int end_day_range; end_day_range = start_day_range + current_weekcount; for (i = start_day_range; i < end_day_range; i++) { if (i > 0 && i <= endofmonth) { pinpoint_masktbl[i - 1] = SET_DAY; change_masktbl = TRUE; } } } } if (change_masktbl == FALSE) { return (FALSE); } return (pinpoint_day()); } /* * used analysis_ev_month(), analysis_ev_year() */ #define MASKBIT(x) (1 << (x)) /* * 月の解析(旧暦対応) * * %1,%2 と 月,%4,%5 を同時に指定した場合は AND 処理となる * %1,%2 を同時に指定すると %0 と等価となる * 0,1,2,5 と指定すると 0 は無視する * * return value: * TRUE 対象月 * FALSE 未対象 */ static int analysis_ev_month(char *bp) { int pcnt; int pc; int monthmap = 0; /* 月有効ビットマップ bit0:1 - bit11:12 */ int leaptype = 0; /* bit0:閏年/月でない, bit1:閏年/月 */ pcnt = separate_param(bp, pbuff, param, PARAM_COUNT, NULL); for (pc = 0; pc < pcnt; pc++) { const char *p; int pmon; p = param[pc]; if (*p == '%') { pmon = atoi(p + 1); switch (pmon) { case 1: /* %1 閏年/月でない */ leaptype |= 1; break; case 2: /* %2 閏年/月 */ leaptype |= 2; break; case 4: /* %4 偶数月 */ monthmap |= 0x0AAA; break; case 5: /* %5 奇数月 */ monthmap |= 0x0555; break; } } else { pmon = atoi(p); if (pmon >= 1 && pmon <= 12) { monthmap |= MASKBIT(pmon - 1); } } } if (monthmap == 0 || (monthmap & MASKBIT(current_month - 1)) != 0) { if (leaptype == 0 || leaptype == 3 || (leaptype == (current_leap + 1))) { return (TRUE); } } return (FALSE); } /* * 年(日付)の解析(旧暦対応) * * 日付を指定して期間を指定できる * 旧暦時の日付は使用できない * * %1,%2 と 年,%4,%5 を同時に指定した場合は AND 処理となる * %1,%2 を同時に指定すると閏年評価はしない * %4,%5 を同時に指定すると奇偶数評価はしない * 0,1995,1997 と指定すると 0 は無視する * * return value: * TRUE 対象年(日付) * FALSE 未対象 */ static int analysis_ev_year(char *bp) { int change_masktbl = FALSE; int pcnt; int pc; int leaptype = 0; /* bit0:閏年でない, bit1:閏年 */ int monthtype = 0; /* bit0:偶数年, bit1:奇数年 */ pcnt = separate_param2(bp, param, PARAM_COUNT); pinpoint_maskclear(); for (pc = 0; pc < pcnt; pc++) { const char *p; const char *q; int pyear; int pyear2; long pjul; long pjul2; p = param[pc]; if (*p == '%') { pyear = atoi(p + 1); switch (pyear) { case 1: /* %1 閏年でない */ leaptype |= 1; break; case 2: /* %2 閏年 */ leaptype |= 2; break; case 4: /* %4 偶数年 */ monthtype |= 1; break; case 5: /* %5 奇数年 */ monthtype |= 2; break; } } else if (*p == '-') { switch (analysis_year_date(p + 1, &pyear, &pjul)) { case EV_YEAR_ERR: default: continue; case EV_YEAR_YEAR: /* -n 指定年以前 */ pyear2 = pyear; pyear = INT_MIN; goto year_check; case EV_YEAR_DATE: /* -yy/mm/dd 指定日付以前 */ pjul2 = pjul; pjul = LONG_MIN; goto date_check; } } else { switch (analysis_year_date(p, &pyear, &pjul)) { case EV_YEAR_ERR: default: continue; case EV_YEAR_YEAR: q = strchr(p, '-'); if (q == NULL) { /* n 指定年のみ */ pyear2 = pyear; } else if (q[1] == '\0') { /* n- 指定年以降 */ pyear2 = INT_MAX; } else { /* n-m 範囲指定 */ if (analysis_year(q + 1, &pyear2, NULL) == YEAR_NG) { continue; } } year_check: if (pyear == 0) { continue; } if (pyear == INT_MIN) { pjul = LONG_MIN; } else { pjul = Julian(pyear, 1, 1); } if (pyear2 == INT_MAX) { pjul2 = LONG_MAX; } else { pjul2 = Julian(pyear2, 12, 31); } goto date_check; case EV_YEAR_DATE: q = strchr(p, '-'); if (q == NULL) { /* yy/mm/dd 指定日付のみ */ pjul2 = pjul; } else if (q[1] == '\0') { /* yy/mm/dd- 指定日付以降 */ pjul2 = LONG_MAX; } else { /* yy/mm/dd-yy/mm/dd 範囲指定 */ switch (analysis_year_date(q + 1, &pyear2, &pjul2)) { case EV_YEAR_ERR: case EV_YEAR_YEAR: default: continue; case EV_YEAR_DATE: break; } } date_check: change_masktbl = TRUE; if (start_julian <= pjul2 && pjul <= end_julian) { int js; int je; if (pjul <= start_julian) { js = 0; } else { js = (int)(pjul - start_julian); } if (pjul2 > end_julian) { je = endofmonth - 1; } else { je = (int)(pjul2 - start_julian); } while (js <= je) { pinpoint_masktbl[js++] = SET_DAY; } } break; } } } /* change_masktbl == FALSE 時は 0 が指定されている */ if (change_masktbl == FALSE || pinpoint_day() != FALSE) { if (monthtype == 0 || monthtype == 3 || ((monthtype - 1) == (current_year & 1))) { if (leaptype == 0 || leaptype == 3 || (leaptype == (current_leap + 1))) { return (TRUE); } } } return (FALSE); } /* * 年(日付)の抽出(旧暦未対応) * * return value: * EV_YEAR_ERR 構文エラー * EV_YEAR_YEAR 年のみ指定 * EV_YEAR_DATE 日付指定 */ static int analysis_year_date(const char *p, int *year, long *jul) { char *q; int yy; int mm; int dd; if (analysis_year(p, &yy, NULL) == YEAR_NG) { return (EV_YEAR_ERR); } /* AD, BC, 元号の略記号スキップ */ while (isalpha(*p) != 0) { p++; } /* 数値(年)スキップ */ while (isdigit(*p) != 0) { p++; } *year = yy; if (*p != '/') { return (EV_YEAR_YEAR); } mm = (int)strtol(p + 1, &q, 10); if (*q != '/') { return (EV_YEAR_ERR); } dd = (int)strtol(q + 1, &q, 10); #if 0 if (current_mode == LC_EVENT_MODE) { int leap = 0; const struct DATE_T *nowcal; if (*q == '.') { leap = 1; } nowcal = LunarToNowCalendar(yy, mm, dd, leap); yy = nowcal->year; mm = nowcal->month; dd = nowcal->day; } #endif *jul = Julian(yy, mm, dd); return (EV_YEAR_DATE); } /* * イベントの対象日を探し出す * * return value: * 対象数 * * pinpoint_hittbl[n] = diffday - イベントまでの期間(最大1か月間) */ static int pickup_event(int notice_range) { int cday; int hitcnt; int i; cday = calendar.day + monthtbl[CENTER_MONTH].offset_day; hitcnt = 0; for (i = 0; i < endofmonth; i++) { int cmpday; int diffdays; if (pinpoint_daytbl[i] == CLEAR_DAY) { continue; } cmpday = i + current_offsetday + 1; if (dayshift_direction != 0) { cmpday = skipHoliday(cmpday); } diffdays = cmpday - cday; if (diffdays == 0 || (notice_range != 0 && diffdays >= -1 && diffdays <= notice_range)) { if (diffdays >= 28) { if (diffdays > monthtbl[CENTER_MONTH].dayofmonth) { continue; } if (cmpday == calendar.day) { diffdays = NOTICE_MONTH(1); } } pinpoint_hittbl[hitcnt++] = diffdays; if (hitcnt >= MAXHIT) { break; } } } return (hitcnt); } /* * イベントの対象日を探し出す(旧暦用) * * return value: * 対象数 * * pinpoint_hittbl[n] = diffday - イベントまでの期間(最大1か月間) */ static int pickup_lc_event(int notice_range) { int cday; int hitcnt; int i; cday = calendar.lc_day + monthtbl[CENTER_MONTH].lc.offset_day; hitcnt = 0; for (i = 0; i < endofmonth; i++) { int cmpday; int diffdays; if (pinpoint_daytbl[i] == CLEAR_DAY) { continue; } cmpday = i + current_offsetday + 1; diffdays = cmpday - cday; if (diffdays == 0 || (notice_range != 0 && diffdays >= -1 && diffdays <= notice_range)) { if (diffdays >= 28) { /* これで良いか不明 */ const struct DATE_T *date; int cmpyear, cmpmonth, cmpleap; if (diffdays > monthtbl[CENTER_MONTH].dayofmonth) { continue; } cmpday -= monthtbl[CENTER_MONTH].lc.offset_day; cmpyear = calendar.lc_year; cmpmonth = calendar.lc_month; cmpleap = calendar.lc_leap; if (cmpday < 1) { cmpyear = monthtbl[CENTER_MONTH - 1].lc.year; cmpmonth = monthtbl[CENTER_MONTH - 1].lc.month; cmpday += monthtbl[CENTER_MONTH - 1].lc.dayofmonth; cmpleap = monthtbl[CENTER_MONTH - 1].lc.leap; } else if (cmpday > monthtbl[CENTER_MONTH].lc.dayofmonth) { cmpyear = monthtbl[CENTER_MONTH + 1].lc.year; cmpmonth = monthtbl[CENTER_MONTH + 1].lc.month; cmpday -= monthtbl[CENTER_MONTH].lc.dayofmonth; cmpleap = monthtbl[CENTER_MONTH + 1].lc.leap; } date = LunarToNowCalendar(cmpyear, cmpmonth, cmpday, cmpleap); if (date == NULL) { continue; } if (date->day == calendar.day) { diffdays = NOTICE_MONTH(1); } } pinpoint_hittbl[hitcnt++] = diffdays; if (hitcnt >= MAXHIT) { break; } } } return (hitcnt); } /* * イベント対象日を求める為のテーブルを初期化する */ static void pinpoint_dayclear(void) { memset(pinpoint_daytbl, SET_DAY, sizeof(pinpoint_daytbl)); } /* * イベント対象日を絞り込むためのマスクテーブルを初期化する */ static void pinpoint_maskclear(void) { memset(pinpoint_masktbl, CLEAR_DAY, sizeof(pinpoint_masktbl)); } /* * イベント対象日を絞り込む (and) * * return: * FALSE: 対象イベント無し * TRUE : 対象イベントあり */ static int pinpoint_day(void) { int i; int flag = 0; for (i = 0; i < MAX_DAYOFMONTH; i++) { pinpoint_daytbl[i] &= pinpoint_masktbl[i]; flag |= pinpoint_daytbl[i]; } return ((flag == 0) ? FALSE : TRUE); } /* * 週間情報の処理 * * 各週間登録ファイルを処理 */ static void event_week(void) { int i; const char *filename; event_msg_level_default = LVAR('r'); for (i = 0; i < MAXWEEKFILE; i++) { if (week_filetbl[i] != NULL) { filename = make_filename(week_filetbl[i]); weekSearch(filename); } } } /* * ファイルから週間情報を検索/抽出する * * return value: * FALSE エラー発生(ファイルオープン時) * TRUE 正常終了 * * file format: * month/day month/day message */ static int weekSearch(const char *infile) { char *bp; char *lasts; char *weekmessage; struct DATE_MD begin, end; if (openfile(infile)) { return (FALSE); } current_mode = EVENT_MODE; /* makerange */ event_msg_level = event_msg_level_default; while ((bp = getfile()) != NULL) { if (*bp == '$') { ctrl_msg_proc(bp); continue; } lasts = NULL; bp = strtok_r(bp, fmt_sep1, &lasts); if (bp == NULL) { continue; } begin.month = atoi(bp); bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL) { continue; } begin.day = atoi(bp); bp = strtok_r(NULL, fmt_sep1, &lasts); if (bp == NULL) { continue; } end.month = atoi(bp); bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL) { continue; } end.day = atoi(bp); if (begin.month == 0 || begin.day == 0 || end.month == 0 || end.day == 0) { continue; } weekmessage = strtok_r(NULL, fmt_sep4, &lasts); if (weekmessage == NULL) { continue; } if (check_week(&begin, &end) == FALSE) { continue; } rangetbl[0].bmonth = begin.month; rangetbl[0].start = begin.day; rangetbl[0].emonth = end.month; rangetbl[0].end = end.day; rangetbl[1].bmonth = rangetbl[1].emonth = 0; rangetbl[1].start = rangetbl[1].end = 0; output_eventlist(2, strip(weekmessage), 0, TRUE); } closefile(); return (TRUE); } /* * 週間情報が期間内か確認する * * return value: * TRUE 期間内 * FALSE 期間外 */ static int check_week(struct DATE_MD *begin, struct DATE_MD *end) { long jd1, jd2; jd1 = Julian(calendar.year, begin->month, begin->day); jd2 = Julian(calendar.year, end->month, end->day); if (jd1 > jd2) { if (jd1 <= calendar.julian_day) { jd2 = Julian(calendar.year + 1, end->month, end->day); } else if (jd2 >= calendar.julian_day) { jd1 = Julian(calendar.year - 1, begin->month, begin->day); } } if (jd1 <= calendar.julian_day && calendar.julian_day <= jd2) { return (TRUE); } return (FALSE); } /* * イベントメッセージをリスト構造に格納する * リスト構造からメッセージをページャーに出力する * * type: * 0: メッセージをページャーに出力する * 1: イベントメッセージをリスト構造に格納する * 2: 週間情報メッセージをリスト構造に格納する * 3: 予告メッセージをリスト構造に格納する * * リスト構造格納方法(ソートしないときは全て No.0) * No.0: 今日 * No.1: 昨日 * No.2: 明日 */ static void output_eventlist(int type, char *msg, int diffday, int rangeflag) { static const char *title_message[2] = { #ifdef MSG_STYLE "****** きょうは何の日かな? ******", "****** きょうは何の日でもありません ******" #else "*** きょうは何の日かな? ***", "*** きょうは何の日でもありません. ***" #endif }; const char *notice_msg; char *end_msg; char *ep; int sortorder_no; int period = FALSE; int i; switch (type) { case 0: /* messages flush */ if (event_sortflag == FALSE) { list_output(0, pager_output); } else { for (i = 0; i < MAXSORTITEM; i++) { if (event_sortorder_tbl[i] >= 0) { list_output(event_sortorder_tbl[i], pager_output); } } } if (message_counter > 0) { #ifdef MSG_STYLE pager_output("--- %d件 ---", message_counter); #else pager_output("--- %2d件 ---", message_counter); #endif } else { pager_output_skip(); pager_output("%s", title_message[1]); } break; case 1: /* event */ case 2: /* week */ case 3: /* event notice */ sortorder_no = 0; /* 今日 */ if (diffday < 0) { sortorder_no = 1; /* 昨日 */ } else if (diffday > 0) { sortorder_no = 2; /* 明日 */ } for (i = 0; i < MAXSORTITEM; i++) { if (event_sortorder_tbl[i] == sortorder_no) { break; } } if (i >= MAXSORTITEM) { return ; } if (message_counter == 0) { pager_output_skip(); pager_output("%s", title_message[0]); } message_counter++; for (; *msg == ' ' || *msg == '\t'; msg++) ; ep = strlastp(msg); if (ep[-1] == '.') { ep[-1] = '\0'; period = TRUE; } (void)xstrescape(msg); notice_msg = Notice_Message(msg, diffday, &end_msg); if (type != 3) { strcpy(msgbuf, msg); } else { strcpy(msgbuf, notice_msg); strcat(msgbuf, msg); } if (rangeflag == TRUE) { makerange(msgbuf); } if (period == FALSE) { strcat(msgbuf, end_msg); } strcat(msgbuf, MSG_PERIOD); if (event_sortflag == FALSE) { list_add(0, 0, 0, event_msg_level, msgbuf); } else { list_insert(sortorder_no, diffday, 0, event_msg_level, msgbuf); } break; } } /* * 日付の移動 * * 日付が日曜・祝日の場合、その前後にずらす * 指定によっては、土曜日も対象にする * * ずらす方向: dayshift_direction < 0: 前 > 0: 後 * 土曜日対象: dayshift_skip_saturday == TRUE * * return value: * 移動後の日付(holiday_tbl の位置 + 1) * テーブルから溢れた場合 0 を返す */ static int skipHoliday(int day) { day--; /* day:1-31 を holiday_tbl の範囲 0-30 に変換 */ while (day >= 0 && day < (MAX_DAYOFMONTH * MAX_MONTH_TBL)) { if (holiday_tbl[day] == 0 || ((holiday_tbl[day] & SET_SATID) != 0 && (holiday_tbl[day] & SET_HOLID) == 0 && dayshift_skip_saturday == FALSE)) { return (day + 1); } day += dayshift_direction; } return (0); } /* * イベント期間を付ける * * rangetbl[] を使用して msgbuff の最後に (mm/dd〜mm/dd) を付ける * msgbuff のオーバーは考慮していないので、十分に大きいこと */ static void makerange(char *msgbuff) { char *lastp; int modify_flag = FALSE; int i; if (event_range_flag == FALSE) { return ; } lastp = strlastp(msgbuff); lastp[0] = '('; lastp[1] = '\0'; if (current_mode == LC_EVENT_MODE) { strcat(lastp, "旧暦:"); } for (i = 0; i < PARAM_COUNT; i++) { int bmonth, emonth; if (rangetbl[i].start == 0) { break; } bmonth = rangetbl[i].bmonth; if (bmonth == 0) { bmonth = current_month; } emonth = rangetbl[i].emonth; if (emonth == 0) { emonth = current_month; } if (rangetbl[i].start < 0) { rangetbl[i].start = endofmonth + rangetbl[i].start + 1; } if (rangetbl[i].end < 0) { rangetbl[i].end = endofmonth + rangetbl[i].end + 1; } sprintf(strlastp(msgbuff), "%d/%d〜%d/%d,", bmonth, rangetbl[i].start, emonth, rangetbl[i].end); modify_flag = TRUE; } if (modify_flag == TRUE) { lastp = strlastp(msgbuff); lastp[-1] = ')'; } else { *lastp = '\0'; } }