【mannen.cのソースコード】
/*
* 万年カレンダー mannen.c
* グレゴリオ暦上(1582年10月15日以降)、9999年12月31日以前で動作する。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strlen() */
#include <ctype.h> /* isdigit() */
#define BUF_SIZE 256
/*
* 自作のbool型の定義
*/
typedef enum {
false, /* 0 */
true /* 1 */
} bool;
/*
* ユーザー定義関数のプロトタイプ宣言
*/
void print_title(void);
void input_ym(void);
bool is_valid_number(char buf[]);
void calc_var(void);
int get_days_of_the_month(int year, int month);
bool is_leap_year(int year);
void print_calendar(void);
bool retry(void);
/*
* グローバル変数
*/
int year, month,
y, m, d, c, b, /* ツェラーの公式用の変数 */
day = 1, /* 日は当月の1日に固定 */
wd; /* 当月の1日の曜日[0,6] */
/*
* メイン関数
*/
int main(void)
{
while (1) {
/* 表題の表示 */
print_title();
/* 年、月の入力 */
input_ym();
/* 暦の各変数の計算 */
calc_var();
/* カレンダーの表示 */
print_calendar();
/* 操作を続けるかどうかの選択 */
if (!retry())
break;
}
return EXIT_SUCCESS;
}
/*
* 表題を表示する関数
*/
void print_title(void)
{
printf("【万年カレンダー】\n");
printf("グレゴリオ暦上(1582年10月15日以降)、9999年12月31日以前で\n");
printf("カレンダーを表示します。\n\n");
}
/*
* 年、月を入力する関数
* is_valid_number()関数を使用する。
*/
void input_ym(void)
{
char buf[BUF_SIZE], zz;
while (1) {
while (1) {
printf("年 = ?(西暦で) ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%d%c", &year, &zz);
buf[strlen(buf) - 1] = '\0';
if (!is_valid_number(buf)) {
printf("無効な入力です。\n");
printf("半角整数値を入力してください。\n\n");
continue;
} else if (year < 1582) {
printf("%d年はグレゴリオ暦の範囲外です。\n", year);
printf("1582年以降の年を入力してください。\n\n");
continue;
} else if (year > 9999) {
printf("無効な入力です。\n");
printf("9999年以前の年を入力してください。\n\n");
continue;
} else
break;
}
while (1) {
printf("月 = ? ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%d%c", &month, &zz);
buf[strlen(buf) - 1] = '\0';
if (!is_valid_number(buf)) {
printf("無効な入力です。\n");
printf("半角整数値を入力してください。\n\n");
continue;
} else if ((month < 1) || (12 < month)) {
printf("無効な入力です。\n");
printf("1から12の整数値を入力してください。\n\n");
continue;
} else
break;
}
/* 入力結果がグレゴリオ暦の範囲外となった場合の処理 */
if (100*year+month < 158210) {
printf("%d年%d月はグレゴリオ暦の範囲外です。\n", year, month);
printf("1582年10月以降の年月を入力してください。\n\n");
continue;
} else
break;
}
}
/*
* 文字列が正しい形式の数値かどうかを判定する関数
*/
bool is_valid_number(char buf[])
{
int i = 0;
/* 最初は符号(省略可) */
if ((buf[i] == '+') || (buf[i] == '-'))
i++;
/* 次に数字(省略可) */
if (!isdigit(buf[i]))
return false;
i++;
/* 次に数字列(省略可) */
while (isdigit(buf[i]))
i++;
/* ほかに余計な文字がなければ真を返す */
return buf[i] == '\0';
}
/*
* 暦の各変数を計算する関数
* get_days_of_the_month()関数を使用する。
*/
void calc_var(void)
{
d = get_days_of_the_month(year, month);
/* うるう月を最後に回すために、3月を1月、4月を2月、…と */
/* 数え直し、1月、2月はそれぞれ前年の11月、12月とする。 */
y = year;
m = month - 2;
if (m < 1) {
m += 12;
y--;
}
/* ツェラーの公式で曜日を求める。 */
c = y / 100; /* 年(西暦)の上2桁 */
b = y % 100; /* 年(西暦)の下2桁 */
wd = ((26 * m - 2) / 10 + day + b + b / 4 /* ツェラーの公式 */
+ 5 * c + c / 4) % 7;
}
/*
* year年month月に含まれる日数を返す関数
* is_lear_year()関数を使用する。
*/
int get_days_of_the_month(int year, int month)
{
int days;
if (is_leap_year(year) && (month == 2)) /* うるう年の2月 */
days = 29;
else if (!is_leap_year(year) && (month == 2)) /* うるう年でない2月 */
days = 28;
else if ((month == 4) || (month == 6) || /* 4、6、9、11月 */
(month == 9) || (month == 11))
days = 30;
else if ((month == 1) || (month == 3) || /* 1、3、5、7、8、10、12月 */
(month == 5) || (month == 7) ||
(month == 8) || (month == 10) ||
(month == 12))
days = 31;
return days;
}
/*
* うるう年の判定をする関数
*/
bool is_leap_year(int year)
{
/* 400で割り切れればうるう年 */
/* 400で割り切れず、100で割り切れればうるう年でない */
/* 100で割り切れず、4で割り切れればうるう年 */
/* 4で割り切れればうるう年でない */
return ((year % 400 == 0) || ((year % 100) && (year % 4 == 0)));
}
/*
* カレンダーを表示する関数
*/
void print_calendar(void)
{
int i;
if ((year == 1582) && (month == 10)) {
/* ツェラーの公式で1582年10月15日の曜日を求める。 */
c = y / 100; /* 年(西暦)の上2桁 */
b = y % 100; /* 年(西暦)の下2桁 */
wd = ((26 * m - 2) / 10 + 15 + b + b / 4 /* ツェラーの公式でday==15とする */
+ 5 * c + c / 4) % 7;
printf("%14d年%2d月\n", year, month);
printf(" 日 月 火 水 木 金 土\n");
for (i = 0; i < wd; i++)
printf(" ");
for (i = 15; i <= d; i++) { /* 15日以降を表示する */
printf("%4d", i);
if ((i + wd) % 7 == 0)
printf("\n");
}
printf("\n");
} else {
printf("%14d年%2d月\n", year, month);
printf(" 日 月 火 水 木 金 土\n");
for (i = 0; i < wd; i++)
printf(" ");
for (i = 1; i <= d; i++) {
printf("%4d", i);
if ((i + wd) % 7 == 0)
printf("\n");
}
printf("\n");
}
}
/*
* 操作を続けるかどうかを選択する関数
* true: 繰り返す、false: 終了する
*/
bool retry(void)
{
bool ret;
char buf[BUF_SIZE], ch, zz;
while (1) {
printf("続けますか?(y/n) ");
fgets(buf, sizeof buf, stdin);
sscanf(buf, "%c%c", &ch, &zz);
if (((ch == 'y') || (ch == 'Y')) && (zz == '\n')) {
printf("\n+++++\n\n");
ret = true;
break;
} else if (((ch == 'n') || (ch == 'N')) && (zz == '\n')) {
ret = false;
break;
}
printf("無効な入力です。\n");
printf("yまたはnを入力してください。\n\n");
}
return ret;
}
C:\Users\skonishi\Documents>mannen
【万年カレンダー】
グレゴリオ暦上(1582年10月15日以降)、9999年12月31日以前で
カレンダーを表示します。
年 = ?(西暦で) a
無効な入力です。 ←正しい形式の数値でなければ無効。
半角整数値を入力してください。
年 = ?(西暦で) 1
1年はグレゴリオ暦の範囲外です。 ←1,581年以前の年は無効。
1582年以降の年を入力してください。
年 = ?(西暦で) 10000
無効な入力です。 ←10,000年以降の年は無効。
9999年以前の年を入力してください。
年 = ?(西暦で) 1582
月 = ? 9
1582年9月はグレゴリオ暦の範囲外です。 ←年月はグレゴリオ暦の範囲内に限る。
1582年10月以降の年月を入力してください。
年 = ?(西暦で) 1582
月 = ? 10
1582年10月
日 月 火 水 木 金 土
15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
続けますか?(y/n) y
+++++
【万年カレンダー】
グレゴリオ暦上(1582年10月15日以降)、9999年12月31日以前で
カレンダーを表示します。
年 = ?(西暦で) 2023
月 = ? 7
2023年 7月
日 月 火 水 木 金 土
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
続けますか?(y/n) n