カレンダーの設定と出力(曜日,祝日等)

/*************************************************************/
/* カレンダーの設定と出力(曜日,祝日等)                    */
/*      使用方法                                             */
/*           cal y m : 西暦y年m月のカレンダを出力            */
/*           cal y m d : 西暦y年m月d日の曜日,祝日情報を出力 */
/*          (有効期間:1582年以降,ただし,祝日は別)       */
/*      coded by Y.Suganuma                                  */
/*************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/************************/
/* クラスcalendarの定義 */
/************************/
class Calendar {
		int y, m;   // 年と月
		int m_d;   // 一月の日数
		int day[31];   // 曜日(0:日曜,・・・,6:土曜)
		int hol[31];   // 祝日の種類
                       //   =-1 : 祝日でない
                       //   >=0 : 祝日番号
		char h_name[5][30];   // 祝日の名前
	public:
		Calendar(){}   // コンストラクタ

		/**********************************/
		/* クラスCalendarのコンストラクタ */
		/*      y_i, m_i : 年と月         */
		/**********************************/
		Calendar::Calendar(int y_i, int m_i)
		{
			int d, i1, k1, yo, y1, m1;
		/*
		     年と月の設定
		*/
			y = y_i;
			m = m_i;
		/*
		     日にちと曜日の設定
		*/
							// 1日の曜日
			y1 = y;
			m1 = m;
			d  = 1;
			if (m1 < 3) {
				y1--;
				m1 += 12;
			}
			yo = (y1 + (y1 / 4) - (y1 / 100) + (y1 / 400) + (13 * m1 + 8) / 5 + d) % 7;
							// 一月の日数
			if (m == 2) {
				if (y%4 == 0 && y%100 != 0 || y%400 == 0)
					m_d = 29;
				else
					m_d = 28;
			}
			else if (m == 4 || m == 6 || m == 9 || m == 11)
				m_d = 30;
			else
				m_d = 31;
							// 各日の曜日の設定
			for (i1 = 0; i1 < m_d; i1++) {
				day[i1] = yo;
				yo      = (yo + 1) % 7;
			}
		/*
		     祝日の設定
		*/
			for (i1 = 0; i1 < m_d; i1++)
				hol[i1] = -1;

			switch (m) {
							// 1月
				case 1:
								// 元日(1月1日)
					hol[0] = 0;
					strcpy(h_name[0], "元日");
					if (day[0] == 0) {
						hol[1] = 1;
						strcpy(h_name[1], "振替休日(元日)");
					}
								// 成人の日(1月の第2月曜日)
					k1 = 0;
					for (i1 = 0; i1 < m_d && k1 < 2; i1++) {
						if (day[i1] == 1) {
							k1++;
							if (k1 == 2) {
								hol[i1] = 2;
								strcpy(h_name[2], "成人の日");
							}
						}
					}
					break;
							// 2月
				case 2:
								// 建国記念日(2月11日)
					hol[10] = 0;
					strcpy(h_name[0], "建国記念日");
					if (day[10] == 0) {
						hol[11] = 1;
						strcpy(h_name[1], "振替休日(建国記念日)");
					}
					break;
							// 3月
				case 3:
								// 春分の日(3月20日頃)
					if (y < 2100)
						d = (int)(20.8431 + 0.242194 * (y - 1980) - (y - 1980) / 4) - 1;
					else
						d = (int)(21.8510 + 0.242194 * (y - 1980) - (y - 1980) / 4) - 1;
					hol[d] = 0;
					strcpy(h_name[0], "春分の日");
					if (day[d] == 0) {
						hol[d+1] = 1;
						strcpy(h_name[1], "振替休日(春分の日)");
					}
					break;
							// 4月
				case 4:
								// みどりの日(4月29日)
					hol[28] = 0;
					strcpy(h_name[0], "みどりの日");
					if (day[28] == 0) {
						hol[29] = 1;
						strcpy(h_name[1], "振替休日(みどりの日)");
					}
					break;
							// 5月
				case 5:
								// 憲法記念日,国民の休日,こどもの日(5月3,4,5日)
					hol[2] = 0;
					strcpy(h_name[0], "憲法記念日");
					hol[3] = 1;
					strcpy(h_name[1], "国民の休日");
					hol[4] = 2;
					strcpy(h_name[2], "こどもの日");
					if (day[4] == 0) {
						hol[5] = 3;
						strcpy(h_name[3], "振替休日(こどもの日)");
					}
					break;
							// 6月
				case 6:
					break;
							// 7月
				case 7:
								// 海の日(7月20日)
					hol[19] = 0;
					strcpy(h_name[0], "海の日");
					if (day[19] == 0) {
						hol[20] = 1;
						strcpy(h_name[1], "振替休日(海の日)");
					}
					break;
							// 8月
				case 8:
					break;
							// 9月
				case 9:
								// 敬老の日(9月15日)
					hol[14] = 0;
					strcpy(h_name[0], "敬老の日");
					if (day[14] == 0) {
						hol[15] = 1;
						strcpy(h_name[1], "振替休日(敬老の日)");
					}
								// 秋分の日(9月23日頃)
					if (y < 2100)
						d = (int)(23.2488 + 0.242194 * (y - 1980) - (y - 1980) / 4) - 1;
					else
						d = (int)(24.2488 + 0.242194 * (y - 1980) - (y - 1980) / 4) - 1;
					hol[d] = 2;
					strcpy(h_name[2], "秋分の日");
					if (day[d] == 0) {
						hol[d+1] = 3;
						strcpy(h_name[3], "振替休日(秋分の日)");
					}
					break;
							// 10月
				case 10:
								// 体育の日(10月の第2月曜日)
					k1 = 0;
					for (i1 = 0; i1 < m_d && k1 < 2; i1++) {
						if (day[i1] == 1) {
							k1++;
							if (k1 == 2) {
								hol[i1] = 0;
								strcpy(h_name[0], "体育の日");
							}
						}
					}
					break;
							// 11月
				case 11:
								// 文化の日(11月3日)
					hol[2] = 0;
					strcpy(h_name[0], "文化の日");
					if (day[2] == 0) {
						hol[3] = 1;
						strcpy(h_name[1], "振替休日(文化の日)");
					}
								// 勤労感謝の日(11月23日)
					hol[22] = 2;
					strcpy(h_name[2], "勤労感謝の日");
					if (day[22] == 0) {
						hol[23] = 3;
						strcpy(h_name[3], "振替休日(勤労感謝の日)");
					}
					break;
							// 12月
				case 12:
								// 天皇誕生日(12月23日)
					hol[22] = 0;
					strcpy(h_name[0], "天皇誕生日");
					if (day[22] == 0) {
						hol[23] = 1;
						strcpy(h_name[1], "振替休日(天皇誕生日)");
					}
					break;
			}
		}

		/*****************************************/
		/* 日にち情報の取得                      */
		/*      d : 日にち                       */
		/*      sw : =0 : 祝日でない             */
		/*           =1 : 祝日                   */
		/*      name : 祝日の名前                */
		/*      return : 曜日(0:日,・・・,6:土) */
		/*               (-1:エラー)            */
		/*****************************************/
		int Calendar::Inf_day(int d, int *sw, char name[])
		{
			int yo = -1;

			if (d < 1 || d > m_d) {
				printf("***error  日にちが不適当です\n");
				exit(1);
			}

			d--;
			*sw = 0;
			yo  = day[d];
			if (hol[d] >= 0) {
				*sw = 1;
				strcpy(name, h_name[hol[d]]);
			}

			return yo;
		}

		/********************/
		/* カレンダーの出力 */
		/*      下線は祝日  */
		/*******************/
		void Calendar::Out_cal()
		{
			int i1, i2, k = 0, k1;

			printf(" 日 月 火 水 木 金 土\n\n");

			while (k < day[0]) {
				printf("   ");
				k++;
			}

			k1 = -day[0];
			for (i1 = 0; i1 < m_d; i1++) {
				printf(" %2d", i1+1);
				k++;
				if (k == 7 || i1 == m_d-1) {
					printf("\n");
					for (i2 = 0; i2 < 7 && k1 <= m_d-1; i2++) {
						if (k1 >= 0) {
							if (hol[k1] < 0)
								printf("   ");
							else
								printf("  ̄");
						}
						else
							printf("   ");
						k1++;
					}
					printf("\n");
					k  = 0;
					k1 = i1 + 1;
				}
			}
		}
};

/****************/
/* main program */
/****************/
int main(int argc, char *argv[])
{
	int y, m, d, yo, sw;
	char name[30];
	char y_n[7][7] = {"日曜日", "月曜日", "火曜日", "水曜日",
                      "木曜日", "金曜日", "土曜日"};
					// 引数の数のチェック
	if (argc != 3 && argc != 4) {
		printf("***error  年,月等を入力してください\n");
		exit(1);
	}
					// 引数の数OK
	else {
						// 年,月のチェック
		y = atoi(argv[1]);
		if (y < 2001 || y > 2150) {
			printf("***error  2001≦年≦2150\n");
			exit(1);
		}
		m = atoi(argv[2]);
		if (m < 1 || m > 12) {
			printf("***error  月が不適当です\n");
			exit(1);
		}
						// 年,月の値OK
		Calendar cal(y, m);
							// 日にち情報の取得
		if (argc == 4) {
			d  = atoi(argv[3]);
			yo = cal.Inf_day(d, &sw, name);
			if (yo >= 0) {
				printf("%d年%d月%d日 %s", y, m, d, y_n[yo]);
				if (sw == 0)
					printf("\n");
				else
					printf(" %s\n", name);
			}
		}
							// カレンダーの出力
		else
			cal.Out_cal();
	}

	return 0;
}