C :: Aufgabe #91

1 Lösung Lösung öffentlich

BashCal - grafischer Konsolenkalender

Anfänger - C von Michi - 07.09.2015 um 14:34 Uhr
Schreiben Sie ein Programm das einen simplen Kalender grafisch in der Konsole darstellt.

Folgende Befehle mit Parametern sollen zur Verfügung stehen
- cal -m -> bestimmten Monat aus dem aktuellen Jahr anzeigen
- cal -y -> alle Kalender für ausgewähltes Jahr anzeigen
- cal -my -> bestimmten Monat aus bestimmten Jahr anzeigen

Beispiel:
"cal -m 2" zeigt den Kalender Februar des aktuellen Jahres
"cal -y 2013" zeigt alle Monate von Januar bis Dezember des Jahres 2013
"cal -my 2 2011" zeigt den Kalender Februar des Jahres 2011

Im Anhang befindet sich ein Beispiel der möglichen grafischen Ausgabe in der Konsole.

Lösungen:

vote_ok
von devnull (8870 Punkte) - 01.01.2016 um 19:20 Uhr

Konsolenausgabe:

$ ./cal -my 9 2015
September 2015
So Mo Di Mi Do Fr Sa
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

Quellcode ausblenden C-Code
/**************************
 * cal.c       Kalender
 **************************/
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <time.h>

#define LOCALE "de_DE.UTF-8"

#define ARG_ERR_1  "Parameter Monat und Jahr erforderlich"
#define ARG_ERR_2  "Optionen -m und -y erforderlich"
#define ARG_ERR_3  "Ungültiger Monat"
#define ARG_ERR_4  "Ungültiges Jahr"

typedef enum _date_part {MONTH, YEAR} date_part_t;
typedef enum _direction {LEFT, DOWN, UP} direction_t;


/**************
 *  Funktionen
 **************/
/* Hilfe */
void usage_ex(int exit_code) {
  fprintf( stderr, "Usage: cal [-my] [[month] year]\n" );
  exit(exit_code);
}

/* Cursor verschieben mit ANSI Escape Sequenzen */
void move_cur(direction_t dir, int steps) {
  char strmv[10];
  switch (dir) {
	  case LEFT: sprintf(strmv, "\033[%dC", steps);	break;
	  case DOWN: sprintf(strmv, "\033[%dB", steps);	break;
	  case UP:	 sprintf(strmv, "\033[%dA", steps);	break;
  }
  printf("%s", strmv);
}				

/* Schaltjahr-Test */
int is_leapyear(int year) {
  return (((year%4==0) && (year%100!=0)) || (year%400==0));
}

/* Anzahl Tage im Monat ermitteln */
int get_days_per_month(int month, int year) {
  switch (month) {	
    case 2:
			return (is_leapyear(year))?29:28; 
	case 4:
	case 6:
	case 9:
	case 11:
			return 30;
	default:
			return 31;
  }
}

/* Wert (num.) fuer aktuellen Monat oder Jahr */
int get_current_date(date_part_t dp) {
  struct tm *tm;
  time_t t;
  
  t = time(NULL);
  if ((tm = localtime(&t)) != NULL)
	switch(dp) {
	  case MONTH: return tm->tm_mon+1;
	  case  YEAR: return tm->tm_year+1900;
    }
  return -1;
}	  

/* erster Wochentag im Monat (0=Sonntag) */
int get_first_day_in_month(int month, int year) {
  char sdate[12];
  struct tm tm;

  memset(&tm, 0, sizeof(struct tm));
  sprintf(sdate, "%d-%d-01", year, month);
  strptime(sdate, "%Y-%m-%d", &tm);
  return tm.tm_wday;	
}

/* voller Name des Monats */
char * get_name_of_month(int month) {
  static char smonth[10];	
  char sdate[12];
  struct tm tm;

  memset(&tm, 0, sizeof(struct tm));
  sprintf(sdate, "2000-%d-01", month);
  strptime(sdate, "%Y-%m-%d", &tm);
  strftime(smonth, 10, "%B", &tm);
  return smonth;
}

/* Monatskalender ausgeben */
int print_calendar_month(int month, int year, int column, int print_year) {
  char header[16];
  int day, day1, maxday;
  int col, row, ind;

  /* Monatsname + Jahr(optional) zentriert */
  if (print_year)
	sprintf(header, "%s %d", get_name_of_month(month), year);
  else	
	sprintf(header, "%s", get_name_of_month(month));
  ind = (20-strlen(header))/2;
  move_cur(LEFT, column+ind);
  printf("%s\n", header);	
  move_cur(LEFT, column);
  printf("So Mo Di Mi Do Fr Sa\n");
  row=3;
	
  /* Einrueckung 1. Zeile */
  move_cur(LEFT, column);
  day1 = get_first_day_in_month(month, year);
  for (day=0; day<day1; day++)
	printf("   ");

  /* Ausgabe der Tage */	
  maxday = get_days_per_month(month, year);
  col = day1;	
  for (day=1; day<=maxday; day++) {
	printf("%2d ", day);
	if (++col % 7 == 0) {
		printf("\n");
		move_cur(LEFT, column);
		row++;
	}
  }
  printf("\n");
  return row;
}

/* Jahreskalender ausgeben */
void print_calendar_year(int year) {
	int month, qmonth, quart; 
	int colmn, rows;

	/* Jahrszahl zentriert */
	printf("%33d\n", year);
	
	/* Monatskalender in 3x4 Matrix (Quartale) anordnen */
	for (quart=0; quart<4; quart++) {
	  for (qmonth=0; qmonth<3; qmonth++) {
		month = quart*3 + qmonth + 1;
		colmn = qmonth*22 + 1;
		rows = print_calendar_month(month, year, colmn, 0);
		move_cur(UP, rows);	
	  }
	  move_cur(DOWN, 11);	
	  printf("\n");
	}
}

/*********
 *  main
 *********/
int main( int argc, char **argv )
{
    int opt_month = 0;
    int opt_year = 0;
    int month = -1;
    int year = -1;
    int opt;

	/* lokale Zeitumgebung setzen (LC_TIME) */
	if ((setlocale(LC_TIME, LOCALE)) == NULL) {
		fprintf(stderr, "Kann lokale Umgebung (LC_TIME) nicht setzen\n");
		exit(EXIT_FAILURE);
	}
	
    /* Check Optionen */
    while ((opt = getopt(argc, argv, "myh")) != -1) {
      switch(opt) {
          case 'm' : opt_month=1; break;
          case 'y' : opt_year=1;  break;
          case 'h' : usage_ex(EXIT_SUCCESS); break;
          default  : usage_ex(EXIT_FAILURE);
      }
    }

	/* Check Parameter: Monat und/oder Jahr */
	switch (argc-optind) {
	case 0:
			month = get_current_date(MONTH);
			year = get_current_date(YEAR);
			break;
	case 1:
			if (opt_month && opt_year) {
				fprintf(stderr, "%s\n", ARG_ERR_1);
				exit(EXIT_FAILURE);
			}
			if (opt_month) {
				month = atoi(argv[optind]);
				year = get_current_date(YEAR);
			} else	
				year = atoi(argv[optind]);
			break;	
	case 2:
			if (opt_month ^ opt_year) {
				fprintf(stderr, "%s\n", ARG_ERR_2);
				exit(EXIT_FAILURE);
			}
			month = atoi(argv[optind]);
			year = atoi(argv[optind+1]);
			break;
	}

	/* Werte pruefen */
	if (month == 0 || month > 12) {
		fprintf(stderr, "%s\n", ARG_ERR_3);
		exit(EXIT_FAILURE);
	}
	if (year < 1900 || year > 2099) {
		fprintf(stderr, "%s\n", ARG_ERR_4);
		exit(EXIT_FAILURE);
	}

	/* Kalender-Ausgabe */
	if (month < 0)
		print_calendar_year(year);
	else
		print_calendar_month(month, year, 1, 1);

	return 0;
}