/* * misc.c -- miscellaneous * * Copyright (C) 1989,1999,2003 by Yoshifumi Mori * * tab:4 */ #include "cdefs.h" #include "extern.h" #ifndef INCLUDE_CALENDAR #define MAXTBL_SUFFIX 64 /* 接尾語 登録数 */ #define DEFAULT_SUFFIXLEN 64 /* 接尾語バッファデフォルトサイズ */ #define SWAP(a,b) { int tmp_value; tmp_value = a; a = b; b = tmp_value; } #endif /* !INCLUDE_CALENDAR */ #define MAX_ERANAME 8 /* 元号の最大文字数(漢字で4文字まで) */ #define MAX_SPHOLIDAY 2 /* 特殊休日数 */ struct ERATBL { char nameofera[((MAX_ERANAME + 2) + 1) & ~1]; /* 元号は漢字で2文字 */ char symbol[2]; /* 略記号 */ struct DATE_T begin; struct DATE_T end; struct ERATBL FAR *next; }; struct HOLIDAYTBL { int yy1; /* 開始年 */ int yy2; /* 終了年 */ int mm; /* 月 */ int dd; /* 日 */ int week; /* 曜日 */ const char FAR *name; /* 名前 */ }; static int gengo_loading_flag = FALSE; static struct ERATBL FAR *gengo_first_tbl = NULL; const char *gengo_file = "gengo.tbl"; const char *holiday_file = "holiday.tbl"; #ifndef INCLUDE_CALENDAR const char *flower_file = "flower.tbl"; unsigned int holiday_tbl[MAX_DAYOFMONTH * MAX_MONTH_TBL]; char *suffix_file; static char FAR *tbl_suffix[MAXTBL_SUFFIX][2]; static int tbl_suffix_cnt = 0; static char *suffix_bufptr[2] = { NULL, NULL }; static int suffix_buflen[2] = { 0, 0 }; static const char *defSuffix[2] = { "です", "でした" }; #endif /* !INCLUDE_CALENDAR */ int mkfile_status; static int max_holiday; static struct HOLIDAYTBL FAR *holidayTbl = NULL; static long spHolspanJDTbl[MAX_SPHOLIDAY][2]; /* * 閏年の判定 * * return value: * 0 平年 * 1 閏年 */ int isleap(int year) { return ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)); } /* * 曜日を求める */ int GetDayofWeek(int year, int month, int day) { if (month < 3) { year--; month += 12; } return ((year + year / 4 - year / 100 + year / 400 + (month * 13 + 8) / 5 + day) % 7); } /* * 月の日数を求める */ int GetDayofMonth(int year, int month) { static const char days_per_month[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int dayofmonth; if (month < 1 || month > 12) { return (-1); } dayofmonth = (int)days_per_month[month - 1]; if (month == 2) { dayofmonth += isleap(year); } return (dayofmonth); } #ifndef INCLUDE_CALENDAR /* * 年頭からの通算日を求める * 1月1日は 1 */ int GetDayofYear(int year, int month, int day) { static const short daycount[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; int dayofyear; if (month < 1 || month > 12) { return (-1); } dayofyear = (int)daycount[month - 1] + day; if (month > 2) { dayofyear += isleap(year); } return (dayofyear); } #endif /* !INCLUDE_CALENDAR */ /* * ユリウス通日を求める */ long Julian(int year, int month, int day) { #if 0 #define JULIAN 1720994 #define MONTH 30.6001 #define YEAR 365.25 int yy, mm; int tmp; yy = year; mm = month; if (month < 3) { yy--; mm += 12; } if ((year < 1582) || (year == 1582 && month < 10) || ((year == 1582 && month == 10) && day <= 4)) { tmp = 0; /* ユリウス暦 */ } else if ((year == 1582 && month == 10) && day < 15) { errprint("Julian", ERR_ERROR, "DATE %d/%02d/%02d: 日が存在しません", year, month, day); return (0L); /* 日本は1872年に改暦 */ } else { tmp = 2 - (yy / 100) + (yy / 100) / 4; /* グレゴリオ暦 */ } return (JULIAN + (int)(MONTH * (mm + 1)) + (long)(YEAR * yy) + day + tmp); #else /* * 《出典》 * ALGORITHM 199 * CONVERSIONS BETWEEN CALENDAR DATE AND JULIAN DAY NUMBER * Robert G. Tantzen * Air Force Missile Development Center, Holloman AFB, New Mex. * * 「COLLECTED ALGORITHMS FROM ACM Volume I Algorithms 1-220」 * Copyright (C) 1980, Association for Computing Machinery, Inc. * ISBN: 0-89791-017-6 * * 上記アルゴリズムの一部の式と定数(1721119 -> 1721118)を変更。 */ div_t c; int t; month -= 3; if (month < 0) { month += 12; year--; } c = div(year, 100); t = (153 * month + 2) / 5 + day; return (((146097L * c.quot) >> 2L) + ((1461L * c.rem) >> 2L) + t + 1721118L); #endif } #ifndef INCLUDE_CALENDAR /* * 旧暦(太陰暦)の2つの日付の差(日単位;日数)を求める DATE2 - DATE1 */ int GetDiffLCDate(int year2, int month2, int day2, int leap2, int year1, int month1, int day1, int leap1) { const struct DATE_T *date; long jd; date = LunarToNowCalendar(year1, month1, day1, leap1); if (date == NULL) { goto err_return; } jd = Julian(date->year, date->month, date->day); date = LunarToNowCalendar(year2, month2, day2, leap2); if (date == NULL) { err_return:; errprint("GetDiffLCDate", ERR_ERROR, "サポート範囲オーバーです"); return (0); } return ((int)(Julian(date->year, date->month, date->day) - jd)); } /* * 日付を指定分、進める(戻す) */ void date_inc(struct DATE_T *date, int offset) { int year, month, day; int daycnt; year = date->year; month = date->month; day = date->day + offset; while (day > (daycnt = GetDayofMonth(year, month))) { day -= daycnt; if (++month > 12) { year++; month = 1; } } while (day < 1) { if (--month < 1) { year--; month = 12; } day += GetDayofMonth(year, month); } date->year = year; date->month = month; date->day = day; date->dayofweek = GetDayofWeek(year, month, day); } #endif /* !INCLUDE_CALENDAR */ /* * 日付を読み取る * * fmt : 日付フォーマット指定(bitmap) * 00000001 - YY / MM / DD * 00000010 - YY / MM / ** * 00000100 - YY / ** / DD * 00001000 - YY / ** / ** * 00010000 - ** / MM / DD * 00100000 - ** / MM / ** * 01000000 - ** / ** / DD * 10000000 - ** / ** / ** * * 100000000 - DD に曜日指定可能 (ex. Sun, 2Mon) * * return value: * DATE_OK 正常終了 * DATE_NG フォーマットが異常 * * wflag = TRUE 和暦指定(NULL指定可能) */ int read_date(int fmt, char *bp, struct DATE_T *date, int *wflag) { static const char *montbl = "JanFebMarAprMayJunJulAugSepOctNovDec"; static const char *weektbl = "SunMonTueWedThuFriSat"; char *lasts = NULL; char *pp; char *q; int i; int bit; pp = strtok_r(bp, "/", &lasts); if (pp == NULL) { return (DATE_NG); } if (analysis_year(pp, &(date->year), wflag) == YEAR_NG) { return (DATE_NG); } pp = strtok_r(NULL, "/", &lasts); if (pp == NULL) { return (DATE_NG); } if (*pp == '*') { date->month = 0; } else if (isdigit(*pp) != 0) { date->month = atoi(pp); if (date->month < 0 || date->month > 12) { return (DATE_NG); } } else { for (i = 0; i < 12; i++) { if (strnicmp(pp, &montbl[i * 3], 3) == 0) { date->month = i + 1; break; } } if (i >= 12) { return (DATE_NG); } } pp = strtok_r(NULL, "", &lasts); if (pp == NULL) { return (DATE_NG); } if (*pp == '*') { date->day = 0; } else { date->day = (int)strtol(pp, &q, 10); if (*q != '\0') { for (i = 0; i < 7; i++) { if (strnicmp(q, &weektbl[i * 3], 3) == 0) { if (date->day < 0) { date->day = -date->day + 5; } date->day = -((i + 1) + date->day * 10 + 100); break; } } if ((fmt & 0x0100) == 0 || i >= 7) { return (DATE_NG); } } } bit = 0; if (date->year == 0) { bit |= 4; } if (date->month == 0) { bit |= 2; } if (date->day == 0) { bit |= 1; } date->dayofweek = 0; return ((fmt & (1 << bit)) ? DATE_OK : DATE_NG); } /* * 年号を確認し値を得る * * return value: * YEAR_OK 年号が正常 * YEAR_NG 年号が異常 * * wflag = TRUE 和暦指定(NULL指定可能) */ int analysis_year(const char *p, int *year, int *wflag) { struct ERATBL FAR *era_tbl; int c1, c2; if (wflag != NULL) { *wflag = FALSE; } if (isdigit((unsigned char)*p) != 0 || (p[0] == '-' && isdigit((unsigned char)p[1]) != 0)) { *year = atoi(p); return (YEAR_OK); } /* B.C. 紀元前 before Christ */ /* A.D. キリスト紀元後,西暦 anno Domini */ c1 = tolower(p[0]); c2 = tolower(p[1]); if ((c1 == 'b' && c2 == 'c') || (c1 == 'a' && c2 == 'd')) { int bc_flag = FALSE; int y; if (c1 == 'b') { bc_flag = TRUE; } y = atoi(p + 2); if (bc_flag == TRUE) { y = -y; } *year = y; return (YEAR_OK); } if (p[0] == '?' || p[0] == '*') { /* ???? -> 0 */ *year = 0; return (YEAR_OK); } if (gengo_loading_flag == FALSE) { return (YEAR_NG); } /* 元号の略記号により変換 */ era_tbl = gengo_first_tbl; while (era_tbl != NULL) { if (*p == era_tbl->symbol[0] || *p == era_tbl->symbol[1]) { *year = atoi(p + 1) + era_tbl->begin.year - 1; if (wflag != NULL) { *wflag = TRUE; } return (YEAR_OK); } era_tbl = era_tbl->next; } return (YEAR_NG); } #ifndef INCLUDE_CALENDAR /* * ソート方法を解析し、順序をテーブルに設定する * * return value: * TRUE ソートする * FALSE ソートしない */ int analysis_sortorder(const char *type, const char *string, int *sortorder_tbl, int org_sortflag) { static const char *statname[MAXSORTITEM] = { "今日", "昨日", "明日", }; int statflag[MAXSORTITEM]; int i; char *sp; char *lasts; const char *ip; const char *sep_str = "_ ,/-:"; if (string == NULL || *string == '\0') { return (org_sortflag); } if (strcmp(string, "なし") == 0) { return (FALSE); } for (i = 0; i < MAXSORTITEM; i++) { sortorder_tbl[i] = UNUSE; statflag[i] = UNUSE; } sp = xstrdup(string); lasts = NULL; ip = strtok_r(sp, sep_str, &lasts); for (i = 0; ip != NULL && i < MAXSORTITEM; ) { int j; int hit_flag = FALSE; for (j = 0; j < MAXSORTITEM; j++) { if (strcmp(ip, statname[j]) == 0) { hit_flag = TRUE; if (statflag[j] == UNUSE) { sortorder_tbl[i] = j; statflag[j] = i; i++; break; } else { errprint(type, ERR_ERROR, "%s_sort = %s, duplicate %s", type, string, ip); } } } if (hit_flag == FALSE) { errprint(type, ERR_ERROR, "%s_sort = %s, unknown %s", type, string, ip); } ip = strtok_r(NULL, sep_str, &lasts); } free(sp); return (TRUE); } #endif /* !INCLUDE_CALENDAR */ #if !defined(INCLUDE_CALENDAR) || (defined(INCLUDE_CALENDAR) && defined(_T_WINDOWS)) /* * '_' を ' ' に変換する */ char *undertospace(char *chrptr) { unsigned char *p; #if defined(_T_MSDOS) #define _INT unsigned short #endif #if defined(_T_HUMAN68K) || defined(_T_UNIX) || defined(_T_WIN32CONSOLE) || defined(_T_WINDOWS) #define _INT int #endif p = (unsigned char *)chrptr; while ((p = jstrchr(p, (_INT)'_')) != '\0') { *p = ' '; } return (chrptr); } #endif /* !INCLUDE_CALENAR || (INCLUDE_CALENDAR && _T_WINDOWS) */ /* * 文字列の最後までスキップし、その位置を返す */ char *strlastp(char *p) { while (*p != '\0') { p++; } return (p); } /* * 元号変換テーブルを読み込む * * use file: gengo.tbl * * file format: * gengo year/month/day year/month/day sc * * return value: * LOAD_OK 読み込み成功 * LOAD_NG エラー発生 */ int Loading_GengoTbl(void) { struct ERATBL FAR *now_tbl; char *bp; char *lasts; if (gengo_loading_flag == TRUE) { return (LOAD_OK); } if (openfile(gengo_file)) { return (LOAD_NG); } now_tbl = NULL; while ((bp = getfile()) != NULL) { struct DATE_T rdate; struct ERATBL FAR *p; lasts = NULL; bp = strtok_r(bp, fmt_sep3, &lasts); if (bp == NULL) { continue; } p = (struct ERATBL FAR *)XMALLOC(sizeof(struct ERATBL)); FMEMSET(p, '\0', sizeof(struct ERATBL)); #if 0 /* memset でクリアしているから要らない */ p->next = NULL; #endif FSTRNCPY(p->nameofera, (char FAR *)bp, MAX_ERANAME); bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL || read_date(0x01, bp, &rdate, NULL) == DATE_NG) { free_mem: XFREE(p); continue; } rdate.dayofweek = 0; p->begin = rdate; bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL || read_date(0x81, bp, &rdate, NULL) == DATE_NG) { goto free_mem; } rdate.dayofweek = 0; p->end = rdate; bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp != NULL) { FSTRNCPY(p->symbol, (char FAR *)bp, 2); } if (gengo_first_tbl == NULL) { gengo_first_tbl = p; } else { now_tbl->next = p; } now_tbl = p; } closefile(); if (gengo_first_tbl == NULL) { return (LOAD_NG); } gengo_loading_flag = TRUE; return (LOAD_OK); } #ifndef INCLUDE_CALENDAR /* * 曜日名を日本語/英語で返す */ const char *GetNameofWhatday(int languagetype, int dayofweek) { static const char *name_e_dayofweek[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", }; static const char *name_j_dayofweek = "日月火水木金土"; static char buf[8]; dayofweek %= 7; if (languagetype == LANG_J) { memset(buf, '\0', sizeof(buf)); strncpy(buf, &name_j_dayofweek[dayofweek * 2], 2); strcat(buf, "曜日"); return (buf); } return (name_e_dayofweek[dayofweek]); } /* * 和暦(元号)を求める * * languagetype = LANG_J:元号名, LANG_E:略称(英大文字) * * 正常の場合は元号名を返す * エラーの場合は NULL を返す * wareki は 0 に初期化されるので注意 */ const char *GetNameofEra(int languagetype, int year, int month, int day, int *wareki) { static char erabuf[((MAX_ERANAME + 2) + 1) & ~1]; struct ERATBL FAR *p; *wareki = 0; if (gengo_loading_flag == FALSE) { return (NULL); } p = gengo_first_tbl; do { if (year > p->begin.year || (year == p->begin.year && (month > p->begin.month || (month == p->begin.month && day >= p->begin.day)))) { if (p->end.year == 0 || year < p->end.year || (year == p->end.year && (month < p->end.month || (month == p->end.month && day <= p->end.day)))) { *wareki = year - p->begin.year + 1; switch (languagetype) { case LANG_J: /* 元号名 */ default: FSTRNCPY((char FAR *)erabuf, p->nameofera, MAX_ERANAME); break; case LANG_E: /* 略称(英大文字) */ if (isalpha(p->symbol[0]) != 0) { erabuf[0] = toupper(p->symbol[0]); } else { erabuf[0] = '?'; } erabuf[1] = '\0'; break; } return (erabuf); } } p = p->next; } while (p != NULL); return (NULL); } #endif /* !INCLUDE_CALENDAR */ /* * 月の名前を日本語/英語で返す */ const char *GetNameofMonth(int languagetype, int month) { static const char *monthname[2][12] = { { "睦月", "如月", "弥生", "卯月", "皐月", "水無月", "文月", "葉月", "長月", "神無月", "霜月", "師走" }, { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" } }; if (month < 1 || month > 12) { return (NULL); } return (monthname[languagetype][month - 1]); } #ifndef INCLUDE_CALENDAR /* * 誕生石名を返す */ const char *GetNameofBirthstone(int month) { static const char *stonetable[12] = { "ざくろ石", "紫水晶", "藍玉,血石", "ダイヤモンド", "エメラルド", "真珠,月長石", "ルビー", "赤しまめのう", "サファイア", "オパール,電気石", "トパーズ", "トルコ石,ジルコン", }; if (month < 1 || month > 12) { return (NULL); } return (stonetable[month - 1]); } /* * 誕生月の花の名前を返す */ const char *GetNameofBirthflowers(int month) { static const char *flowerstable[12] = { "カーネーション,スノードロップ", "スミレ,サクラソウ", "キズイセン,スミレ", "ヒナギク,スイートピー", "サンザシ,スズラン", "バラ,スイカズラ", "ヒエンソウ,スイレン", "グラジオラス,ケシ", "アサガオ,シオン", "キンセンカ,コスモス", "キク", "スイセン,セイヨウヒイラギ,ポインセチア", }; if (month < 1 || month > 12) { return (NULL); } return (flowerstable[month - 1]); } /* * 星座名を返す */ const char *GetNameofConstellation(int month, int day) { struct DATE_MD_T { char month; char day; }; static const struct CONSTELLATION { struct DATE_MD_T begin; /* 開始月日 */ struct DATE_MD_T end; /* 終了月日 */ const char *constel; /* 星座名 */ } consteltable[12] = { { { 3, 21 }, { 4, 20 }, "牡羊座" }, { { 4, 21 }, { 5, 21 }, "牡牛座" }, { { 5, 22 }, { 6, 21 }, "双子座" }, { { 6, 22 }, { 7, 23 }, "蟹座" }, { { 7, 24 }, { 8, 23 }, "獅子座" }, { { 8, 24 }, { 9, 23 }, "乙女座" }, { { 9, 24 }, { 10, 23 }, "天秤座" }, { { 10, 24 }, { 11, 22 }, "蠍座" }, { { 11, 23 }, { 12, 22 }, "射手座" }, { { 12, 23 }, { 1, 20 }, "山羊座" }, { { 1, 21 }, { 2, 19 }, "水瓶座" }, { { 2, 20 }, { 3, 20 }, "魚座" } }; int i; for (i = 0; i < 12; i++) { if ((month == (int)consteltable[i].begin.month && day >= (int)consteltable[i].begin.day) || (month == (int)consteltable[i].end.month && day <= (int)consteltable[i].end.day)) { return (consteltable[i].constel); } } return (NULL); } /* * 誕生日の花の名前と花言葉を返す * * 正常の場合は、構造体 flower 内に有効な文字列がある * エラーの場合は、構造体 flower 内は '\0' を指している * * use file: flower.tbl * * file format: * month day name language */ const struct FLOWER_T *GetLanguageofFlower(int month, int day) { #define MAXFLOWERNAME 64 /* 花の名前、花言葉バッファ */ static char namebuf[MAXFLOWERNAME]; static char langbuf[MAXFLOWERNAME]; static const struct FLOWER_T flower = { namebuf, langbuf }; char *bp; char *lasts; memset(namebuf, '\0', sizeof(namebuf)); memset(langbuf, '\0', sizeof(langbuf)); if (openfile(flower_file)) { return (&flower); } while ((bp = getfile()) != NULL) { lasts = NULL; bp = strtok_r(bp, fmt_sep1, &lasts); if (bp == NULL || month != atoi(bp)) { continue; } bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL || day != atoi(bp)) { continue; } bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL) { continue; } strncpy(namebuf, bp, sizeof(namebuf) - 1); bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL) { continue; } strncpy(langbuf, bp, sizeof(langbuf) - 1); break; } closefile(); return (&flower); } /* * 時間に応じたメッセージを返す */ const char *GetTimemessage(int hour) { static const char *timemessage[4] = { "おはようございます" MSG_PERIOD, /* 0 */ "こんにちは" MSG_PERIOD, /* 1 */ "こんばんは" MSG_PERIOD, /* 2 */ "お勤め御苦労様です" MSG_PERIOD, /* 3 */ }; static const unsigned char time_tbl[24] = { 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 1, 1, /* 日本語 0時 〜 11時 */ 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, /* 12時 〜 23時 */ }; return (timemessage[time_tbl[hour % 24]]); } /* * 接尾語テーブルを読み込む * * file format: * suffix_now:suffix_past * * return value: * LOAD_OK 読み込み成功 * LOAD_NG エラー発生 */ int Loading_SuffixTbl(void) { char *half[2]; char FAR *p; int i; for (i = 0; i < 2; i++) { if (suffix_buflen[i] == 0) { suffix_buflen[i] = DEFAULT_SUFFIXLEN; suffix_bufptr[i] = xmalloc(suffix_buflen[i]); } } if (suffix_file == NULL) { return (LOAD_OK); } if (openfile(suffix_file)) { return (LOAD_NG); } while ((half[0] = getfile()) != NULL && tbl_suffix_cnt < MAXTBL_SUFFIX) { half[1] = (char *)jstrchr((unsigned char *)half[0], ':'); if (half[1] == NULL) { continue; } *half[1]++ = '\0'; for (i = 0; i < 2; i++) { int slen; slen = strlen(strip(half[i])) + 1; p = XMALLOC(slen); tbl_suffix[tbl_suffix_cnt][i] = p; FSTRCPY(p, (char FAR *)half[i]); if (slen > suffix_buflen[i]) { free(suffix_bufptr[i]); suffix_bufptr[i] = xmalloc(slen); suffix_buflen[i] = slen; } } tbl_suffix_cnt++; } closefile(); return (LOAD_OK); } /* * デフォルトの接尾語を返す * * type = 0:現在形 * 1:過去形 * * Notice_Message() とバッファ suffix_bufptr[] を * 共有しているので呼び出しには注意が必要 */ const char *GetDefaultSuffix(int type) { const char FAR *sp; int slen; type &= 1; if (tbl_suffix_cnt == 0) { return (defSuffix[type]); } /* * 使用する接尾語を suffix_bufptr[] に設定する * 接尾語の最後に . が付いていると接尾語を消す */ sp = tbl_suffix[0][type]; slen = FSTRLEN(sp); if (slen != 0 && sp[slen - 1] == '.') { *suffix_bufptr[type] = '\0'; } else { FSTRCPY((char FAR *)suffix_bufptr[type], sp); } return (suffix_bufptr[type]); } /* * メッセージの接尾語をテーブルより検索し、 * 該当する接尾語を suffix_bufptr[] にコピーする */ static void check_suffix(char *word) { char *wp; char *wep; char FAR *sp; int i; int wlen; int slen; char *find_ptr = NULL; int find_index = -1; int find_len = 0; wep = strlastp(word); wlen = strlen(word); for (i = 0; i < tbl_suffix_cnt; i++) { sp = tbl_suffix[i][0]; slen = FSTRLEN(sp); if (slen != 0 && sp[slen - 1] == '.') { slen--; } if (wlen >= slen) { wp = wep - slen; /* より長い文字列との一致を試みる */ if (slen > find_len && FSTRNCMP((char FAR *)wp, sp, slen) == 0) { find_ptr = wp; find_index = i; find_len = slen; } } } /* * 接尾語を発見したらそれ以降を削除する * Notice_Message が接尾語を呼出元へ返し、呼出元で結合するため * * 接尾語が無い場合は、接尾語テーブルの最初の組み合わせを * システムのデフォルトの接尾語セットとして使用する */ if (find_index != -1) { *find_ptr = '\0'; /* 接尾語削除 */ } else { if (tbl_suffix_cnt == 0) { strcpy(suffix_bufptr[0], defSuffix[0]); strcpy(suffix_bufptr[1], defSuffix[1]); goto end_proc; } else { find_index = 0; /* 接尾語テーブルの最初の組み合わせを使う */ } } /* * 使用する接尾語を suffix_bufptr[] に設定する * 接尾語の最後に . が付いていると接尾語を消す */ for (i = 0; i < 2; i++) { sp = tbl_suffix[find_index][i]; slen = FSTRLEN(sp); if (slen != 0 && sp[slen - 1] == '.') { *suffix_bufptr[i] = '\0'; } else { FSTRCPY((char FAR *)suffix_bufptr[i], sp); } } end_proc:; } /* * 時期予告メッセージを作る * * diffday: 期間(日単位) ただし、NOTICE_MONTH(0) より大きい場合は月単位 */ const char *Notice_Message(char *msg, int diffday, char **end_msg) { #define MAXNOTICEBUF 32 /* 時期予告メッセージバッファ */ static const char *weeknum = "〇一二三四五六七八九"; static char buf[MAXNOTICEBUF]; check_suffix(msg); *end_msg = suffix_bufptr[0]; memset(buf, '\0', sizeof(buf)); switch (diffday) { case 0: return ("今日は"); case -1: *end_msg = suffix_bufptr[1]; return ("昨日は"); case 1: return ("明日は"); case 7: case 14: case 21: case 28: strncpy(buf, &weeknum[(diffday / 7) * 2], 2); strcat(buf, "週間後は"); break; default: if (diffday > NOTICE_MONTH(0)) { strncpy(buf, &weeknum[(diffday - NOTICE_MONTH(0)) * 2], 2); #if 0 strcat(buf, "ヶ月後は"); #else strcat(buf, "か月後は"); #endif } else { #if 0 char tmp[4]; static const char *numtbl = "0123456789"; if (diffday < 10) { memset(tmp, '\0', sizeof(tmp)); strncpy(tmp, &numtbl[diffday * 2], 2); } else { sprintf(tmp, "%d", diffday); } sprintf(buf, "あと%s日で", tmp); #else sprintf(buf, "あと%d日で", diffday); #endif } break; } return (buf); } /* * 現在の日付を利用してファイル名を作る * * call make_filename2() */ const char *make_filename(const char *basename) { return (make_filename2(basename, calendar.year, calendar.month, calendar.day)); } #endif /* !INCLUDE_CALENDAR */ /* * ユーザー指定の日付を利用してファイル名を作る * * ファイル名中に %c, %y, %m, %d が現れると * それぞれ、世紀、年、月、日に置き換える * %p は プロセスID(5桁) に置き換える * 年月日ともに2桁の文字に変換, 年は下位2桁 * * mkfile_status: %c, %y, %m, %d, %p を使用するとフラグを設定 */ const char *make_filename2(const char *basename, int year, int month, int day) { static char fnamebuf[_T_MAXFNAMEBUF]; const char *bp; char *dp; int cnt; mkfile_status = 0; bp = basename; dp = fnamebuf; cnt = sizeof(fnamebuf) - 1; while (cnt > 0 && *bp != '\0') { int n; if (*bp != '%') { *dp++ = *bp++; cnt--; continue; } bp++; switch (*bp) { case '\0': goto exit_loop; case '%': *dp++ = '%'; cnt--; break; case 'c': /* year nnXX */ mkfile_status |= SET_MKF_CC; n = year / 100; goto store_2num; case 'y': /* year XXnn */ mkfile_status |= SET_MKF_YY; n = year % 100; store_2num: *dp++ = (char)(n / 10 + '0'); cnt--; if (cnt <= 0) { goto exit_loop; } *dp++ = (char)((n % 10) + '0'); cnt--; break; case 'm': /* month nn */ mkfile_status |= SET_MKF_MM; n = month; goto store_2num; case 'd': /* day nn */ mkfile_status |= SET_MKF_DD; n = day; goto store_2num; case 'p': /* process id nnnnn */ { char pbuf[12]; const char *pb; int i; mkfile_status |= SET_MKF_PID; #if defined(_T_HUMAN68K) sprintf(pbuf, "%06d", getpid() >> 4); pb = pbuf + strlen(pbuf) - 5; #endif #if defined(_T_MSDOS) || defined(_T_UNIX) #ifndef __FreeBSD__ sprintf(pbuf, "%05d", getpid()); #else sprintf(pbuf, "%05ld", getpid()); #endif pb = pbuf; #endif #if defined(_T_WIN32CONSOLE) || defined(_T_WINDOWS) sprintf(pbuf, "%05d", getpid() & 0xFFFF); pb = pbuf; #endif for (i = 0; i < 5; i++) { if (*pb == '\0') { break; } *dp++ = *pb++; cnt--; if (cnt <= 0) { goto exit_loop; } } } break; default: *dp++ = '%'; cnt--; if (cnt <= 0) { goto exit_loop; } *dp++ = *bp; cnt--; break; } bp++; } exit_loop: *dp = '\0'; return (fnamebuf); } #ifndef INCLUDE_CALENDAR /* * 文字列の先頭より文字コードを取り出す * * return value: * 文字コード * * int *byte; 文字コードの構成バイト数 * int *width; 文字コードの文字幅 * * 文字コードが異常な場合は、構成バイト数と文字幅を 0 にする */ unsigned int getcharcode(const unsigned char *ptr, int *byte, int *width) { #ifdef _T_SJIS int b, w; unsigned int c; b = 0; w = 0; c = *ptr; if (iskanji(c) != 0) { int c2; c2 = *(ptr + 1); if (iskanji2(c2) != 0) { c = (c << 8) | c2; b = 2; w = 2; } } else { b = 1; w = 1; } #endif /* _T_SJIS */ #ifdef _T_EUC int b, w; unsigned int c; b = 0; /* skip bytes */ w = 0; /* code width */ c = *ptr; if (c == 0x8E) { /* SS2 コードセット2 */ int c2; c2 = *(ptr + 1); if (c2 != '\0' && c2 >= 0xA0 && c2 <= 0xDF) { c = (c << 8) | c2; b = 2; w = 1; } } else if (c == 0x8F) { /* SS3 コードセット3 */ int c2, c3; c2 = *(ptr + 1); if (c2 != '\0' && c2 >= 0x80) { c3 = *(ptr + 2); if (c3 != '\0' && c3 >= 0x80) { c = (c << 16) | (c2 << 8) | c3; b = 3; w = 2; } } } else if (c >= 0xA0) { /* コードセット1 */ int c2; c2 = *(ptr + 1); if (c2 != '\0' && c2 >= 0x80) { c = (c << 8) | c2; b = 2; w = 2; } } else { b = 1; w = 1; } #endif /* _T_EUC */ if (byte != NULL) { *byte = b; } if (width != NULL) { *width = w; } return (b != 0 ? c : 0); } /* * 文字列に文字コードを埋め込む */ unsigned char *putcharcode(unsigned char *ptr, unsigned int code, int byte) { #ifdef _T_SJIS if (byte > 1) { *ptr++ = (unsigned char)(code >> 8); } *ptr++ = (unsigned char)code; #endif #ifdef _T_EUC while (byte-- > 0) { *ptr++ = (unsigned char)(code >> (8 * byte)); } #endif return (ptr); } #ifdef _T_EUC /* * 文字列中から文字を検索しその位置を返す * * use undertospace, Loading_SuffixTbl, message_fold(pager.c) */ unsigned char *jstrchr(const unsigned char *string, int code) { while (*string != '\0') { unsigned int cmpcode; int byte; cmpcode = getcharcode(string, &byte, NULL); if (byte == 0) { break; } if (cmpcode == (unsigned int)code) { return ((unsigned char *)string); } string += byte; } if (code == 0 && *string == '\0') { return ((unsigned char *)string); } return (NULL); } #endif /* _T_EUC */ #endif /* !INCLUDE_CALENDAR */ /* * メモリ確保 */ void *xmalloc(size_t size) { void *buf; buf = malloc(size); if (buf == NULL) { memerr("xmalloc"); } return (buf); } /* * 文字列の複写 */ char *xstrdup(const char *str) { size_t len; char *buf; len = strlen(str) + 1; buf = malloc(len); if (buf == NULL) { memerr("xmalloc"); } strcpy(buf, str); return (buf); } #if defined(_T_MSDOS) /* * far ヒープ領域からのメモリ確保 */ void FAR *far_xmalloc(size_t size) { void FAR *buf; buf = farmalloc(size); if (buf == NULL) { errprint("far_xmalloc", ERR_PANIC, "virtual memory exhausted, program stop."); terminate_program(TERM_MEMERROR); } return (buf); } /* * far ヒープ領域への文字列の複写 */ char FAR *far_xstrdup(const char FAR *str) { size_t len; char FAR *buf; len = FSTRLEN(str) + 1; buf = farmalloc(len); if (buf == NULL) { errprint("far_xstrdup", ERR_PANIC, "virtual memory exhausted, program stop."); terminate_program(TERM_MEMERROR); } FSTRCPY(buf, str); return (buf); } #endif /* _T_MSDOS */ /* * 「振替休日」が有効か判断 * * return value: * TRUE 有効 * FALSE 無効 */ int checkTransferHolidayJD(long jd) { if (spHolspanJDTbl[0][0] <= jd && jd <= spHolspanJDTbl[0][1]) { return (TRUE); } return (FALSE); } /* * 「国民の休日」が有効か判断 * * return value: * TRUE 有効 * FALSE 無効 */ int checkNationalHolidayJD(long jd) { if (spHolspanJDTbl[1][0] <= jd && jd <= spHolspanJDTbl[1][1]) { return (TRUE); } return (FALSE); } /* * 祝日・休日データを読み込む * * use file: holiday.tbl * * file format: * 00/nn yy/mm/dd-yy/mm/dd special_holiday_name * * month/day yaer1-year2 holiday_name * month/day year holiday_name * month/day year1- holiday_name * month/nWeek year1-year2 holiday_name * month/nWeek year holiday_name * month/nWeek year1- holiday_name * * return value: * LOAD_OK 読み込み成功 * LOAD_NG エラー発生 */ int Loading_HolidayTbl(void) { #define ALLOC_HOLTBL 10 static const char *weektbl = "SunMonTueWedThuFriSat"; char *bp; char *lasts; char *dp; char *dp2; char weekbuf[4]; int alloc; int use; int i; int yy1; int yy2; int mm; int dd; int week; struct DATE_T begin; struct DATE_T end; if (openfile(holiday_file)) { return (LOAD_NG); } alloc = 0; use = 0; while ((bp = getfile()) != NULL) { lasts = NULL; bp = strtok_r(bp, fmt_sep3, &lasts); if (bp == NULL) { continue; } week = -1; switch (sscanf(bp, "%d/%d%3s", &mm, &dd, weekbuf)) { case 2: break; case 3: for (i = 0; i < 7; i++) { if (strnicmp(weekbuf, &weektbl[i * 3], 3) == 0) { week = i; break; } } if (week == -1) { continue; } break; default: continue; } bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL) { continue; } if (mm == 0) { /* 特殊休日: 振替休日,国民の休日 */ if (dd < 1 || dd > MAX_SPHOLIDAY) { continue; } dp = bp; dp2 = strchr(bp, '-'); if (dp2 == NULL) { continue; } *dp2++ = '\0'; if (read_date(0x01, dp, &begin, NULL) == DATE_NG || read_date(0x01, dp2, &end, NULL) == DATE_NG) { continue; } spHolspanJDTbl[dd - 1][0] = Julian(begin.year, begin.month, begin.day); spHolspanJDTbl[dd - 1][1] = Julian(end.year, end.month, end.day); yy1 = 0; yy2 = 0; } else { if (analysis_year(bp, &yy1, NULL) == YEAR_NG) { continue; } yy2 = yy1; dp = strchr(bp, '-'); if (dp != NULL) { dp++; if (*dp == '\0') { yy2 = 9999; } else { if (analysis_year(dp, &yy2, NULL) == YEAR_NG) { continue; } } } } bp = strtok_r(NULL, fmt_sep3, &lasts); if (bp == NULL) { continue; } if (use >= alloc) { alloc += ALLOC_HOLTBL; holidayTbl = (struct HOLIDAYTBL FAR *)FREALLOC(holidayTbl, alloc * sizeof(struct HOLIDAYTBL)); if (holidayTbl == NULL) { memerr("Loading_HolidayTbl"); } } holidayTbl[use].yy1 = yy1; holidayTbl[use].yy2 = yy2; holidayTbl[use].mm = mm; holidayTbl[use].dd = dd; holidayTbl[use].week = week; holidayTbl[use].name = XSTRDUP((const char FAR *)bp); use++; } closefile(); max_holiday = use; return (LOAD_OK); } /* * 祝日・休日の日付テーブルを得る * * 使用後に free すること */ int *GetHolidayTbl(int year, int month) { int i; int *tbl; int dayofmonth; int first_dayofweek; int last_dayofweek; int day; int dayofweek; if (holidayTbl == NULL) { return (NULL); } tbl = NULL; dayofmonth = GetDayofMonth(year, month); first_dayofweek = GetDayofWeek(year, month, 1); last_dayofweek = GetDayofWeek(year, month, dayofmonth); for (i = 0; i < max_holiday; i++) { if (holidayTbl[i].mm == month && holidayTbl[i].yy1 <= year && year <= holidayTbl[i].yy2) { day = holidayTbl[i].dd; dayofweek = holidayTbl[i].week; if (dayofweek != -1) { if (day > 0) { dayofweek = dayofweek - first_dayofweek + 1; if (dayofweek <= 0) { dayofweek += 7; } day = dayofweek + (day - 1) * 7; } else if (day < 0) { dayofweek = last_dayofweek - dayofweek; if (dayofweek < 0) { dayofweek += 7; } day = dayofmonth - dayofweek + (day + 1) * 7; } } else if (day == 0) { switch (month) { case 3: /* 春分 */ GetSB(year, &day, NULL); break; case 9: /* 秋分 */ GetSB(year, NULL, &day); break; } } else if (day < 0) { day = day + dayofmonth + 1; } if (day > 0 && day <= dayofmonth && (tbl == NULL || tbl[day - 1] == 0)) { if (tbl == NULL) { tbl = malloc(sizeof(int) * MAX_DAYOFMONTH); if (tbl == NULL) { goto exit_proc; } memset(tbl, '\0', sizeof(int) * MAX_DAYOFMONTH); } tbl[day - 1] = i; } } } exit_proc: return (tbl); } #ifndef INCLUDE_CALENDAR /* * 祝日をテーブルに登録する * なお、祝日が日曜日の場合は振替休日を設定する */ static void setholiday(unsigned int *pHolTbl, int nameindex, long jd) { pHolTbl[0] &= ~(MASK_HOLNAMEI | SET_OVRID); /* 休日が続いた場合の振替休日の解除 */ pHolTbl[0] |= SET_HOLID | SET_HOLNAMEI(nameindex); if ((pHolTbl[0] & SET_SUNID) != 0 && checkTransferHolidayJD(jd + 1) == TRUE) { pHolTbl[1] &= ~MASK_HOLNAMEI; pHolTbl[1] |= SET_OVRID | SET_HOLID | SET_HOLNAMEI(0); /* 振替休日 */ /* * event.skipHoliday() では、土曜日許可の判断に SET_OVRID を見ていない * 現実的に考えて、土曜日の振替休日はありえないのだが * 安全のため SET_HOLID を設定する */ } } /* * 祝日/休日テーブルを初期化する */ void makeHolidayTbl(void) { #define MAX_HOLTBLDAYS (MAX_DAYOFMONTH * (MAX_MONTH_TBL + 2)) unsigned int *tmpHolTbl; unsigned int flag; unsigned int *pHolTbl; int yy; int mm; int dayofweek; int dayofmonth; int first_dayofmonth; int i; int j; int *tbl; long jd; long first_jd; tmpHolTbl = malloc(sizeof(unsigned int) * MAX_HOLTBLDAYS); if (tmpHolTbl == NULL) { memset(holiday_tbl, 0, sizeof(holiday_tbl)); return ; } yy = monthtbl[0].year; mm = monthtbl[0].month - 1; if (mm < 1) { mm = 12; yy--; } /* 曜日を設定 日曜/土曜 */ dayofweek = GetDayofWeek(yy, mm, 1); for (i = 0; i < MAX_HOLTBLDAYS; i++) { switch (dayofweek) { case 0: /* sunday */ flag = SET_SUNID; break; case 6: /* saturday */ flag = SET_SATID; break; default: flag = 0; break; } tmpHolTbl[i] = flag; dayofweek = (dayofweek + 1) % 7; } first_jd = Julian(yy, mm, 1); first_dayofmonth = GetDayofMonth(yy, mm); /* 祝日を登録 */ pHolTbl = tmpHolTbl; jd = first_jd; for (j = 0; j < (MAX_MONTH_TBL + 2); j++) { dayofmonth = GetDayofMonth(yy, mm); tbl = GetHolidayTbl(yy, mm); if (tbl != NULL) { for (i = 0; i < dayofmonth; i++) { if (tbl[i] != 0) { setholiday(pHolTbl + i, tbl[i], jd + i); } } free(tbl); } pHolTbl += dayofmonth; jd += dayofmonth; mm++; if (mm > 12) { mm = 1; yy++; } } /* 「国民の休日」を登録 */ jd = first_jd; for (i = 0; i < (MAX_HOLTBLDAYS - 2); i++) { if ((tmpHolTbl[i + 0] & SET_HOLID) != 0 && (tmpHolTbl[i + 2] & SET_HOLID) != 0 && (tmpHolTbl[i + 1] & (SET_HOLID | SET_OVRID | SET_SUNID)) == 0 && checkNationalHolidayJD(jd + 1) == TRUE) { tmpHolTbl[i + 1] &= MASK_HOLNAMEI; tmpHolTbl[i + 1] |= SET_HOLID | SET_HOLNAMEI(1); /* 国民の休日 */ } jd++; } memcpy(holiday_tbl, &tmpHolTbl[first_dayofmonth], sizeof(holiday_tbl)); free(tmpHolTbl); } #endif /* !INCLUDE_CALENDAR */ #if !defined(INCLUDE_CALENDAR) || (defined(_T_WINDOWS) && defined(INCLUDE_CALENDAR)) /* * 祝日・休日の名前を得る * * 使用後に free すること */ char *GetHolidayName(int holiday_index) { const char FAR *name; char *buf; if (holiday_index >= 0 && holiday_index < max_holiday) { name = holidayTbl[holiday_index].name; if (name != NULL) { buf = malloc(FSTRLEN(name) + 1); if (buf != NULL) { FSTRCPY((char FAR *)buf, name); return (buf); } } } return (NULL); } #endif /* !INCLUDE_CALENDAR || (_T_WINDOWS && INCLUDE_CALENDAR) */ #ifndef _T_HAVE_STRTOK_R /* * 文字列のトークンへの分解 */ char *strtok_r(char *s, const char *sep, char **lasts) { char *p; char c; if (s == NULL) { s = *lasts; if (s == NULL) { return (NULL); } } while ((c = *s) != '\0') { if (!strchr(sep, c)) { break; } s++; } if (c == '\0') { *lasts = NULL; return (NULL); } for (p = s; (c = *++p) != '\0'; ) { if (strchr(sep, c)) { break; } } if (c == '\0') { *lasts = NULL; } else { *p++ = '\0'; *lasts = p; } return (s); } #endif /* !_T_HAVE_STRTOK_R */