RosettaCodeData/Task/Calendar/Pike/calendar.pike
2023-07-01 13:44:08 -04:00

119 lines
3.6 KiB
Text

#!/bin/env pike
int main(int argc, array(string) argv)
{
object cal = Calendar;
object year;
string region = "us";
array date = argv[1..];
if (sizeof(date) && objectp(Calendar[date[0]]) && Calendar[date[0]]->Day)
{
cal = Calendar[date[0]];
date = Array.shift(date)[1];
}
if (sizeof(date) && (int)date[0])
{
year = cal.Year((int)date[0]);
date = Array.shift(date)[1];
}
if (sizeof(date))
region = date[0];
if (!year)
year = cal.Year();
print_year(year, region);
}
array make_month(object month, int field_width, void|string region)
{
array out =({});
mapping holidays = ([]);
object today = Calendar.Day();
if (region)
holidays = Calendar.Events.find_region(region)->scan_events(month);
array weekday_names =
sprintf("%*.*s", field_width, field_width, month->week()->days()->week_day_shortname()[*]);
out += ({ ({ month->month_name(), month->month_no(), month->year_name() }) });
out += ({ weekday_names });
out += showday(month->weeks()->days()[*][*], month, today, holidays, field_width);
out += ({ ({ " "*field_width })*sizeof(weekday_names) });
return out;
}
string print_month(object _month, void|int field_width, void|string region)
{
if (!field_width)
field_width = 2;
array month = make_month(_month, field_width, region);
string out = "";
out += sprintf("%|*s\n", (field_width+1)*sizeof(month[1])-1, sprintf("%s", month[0][0]));
out += sprintf((month[1..][*]*" ")*"\n");
return out;
}
string print_year(object year, void|string region)
{
array output = ({});
int day_width = 2;
int columns = Stdio.stdout.tcgetattr()->columns;
int month_width = sizeof(make_month(year->month(), day_width)[1]) * (day_width+1) - 1;
if (columns < month_width)
columns = month_width;
// try to find an optimal good looking solution to spread the months
// across the terminal width
// for the common calendar of 12 months this is easy but we need to
// account for caledars that have more than 12 months
float max_width = (float)((columns+2)/(month_width+2));
float max_height = ceil(year->number_of_months()/max_width);
float w = max_width;
while(ceil(year->number_of_months()/(w-1)) == max_height)
w--;
foreach(print_month(year->months()[*], day_width, region)/w;; array row)
{
array rows = row[*]/"\n";
int l = max(@sizeof(rows[*]));
foreach(rows; int i;)
{
// the last line of each month is an empty line.
// repeat the line as many times as needed to make the months equally long
rows[i]+=({ rows[i][-1] })*(l-sizeof(rows[i]));
}
rows = Array.transpose(rows);
output += rows[*]*" ";
}
write("%*|s\n", sizeof(output[1]), year->format_nice());
write(output * "\n");
write("\n");
}
string showday(object day, object month, object today, mapping holidays, int field_width)
{
string dayname;
if (day->month() == month)
{
dayname = (string)day->month_day();
dayname = " "*(sizeof((string)month->number_of_days())-sizeof(dayname))+dayname;
if (day == today)
dayname = sprintf("%|*.*s", field_width, field_width, dayname);
else
dayname = sprintf("%|*.*s", field_width, field_width, dayname);
if (holidays[day])
dayname = sprintf("%|s", dayname);
}
else
dayname = " "*field_width;
return dayname;
}