diff options
Diffstat (limited to '.local/bin')
| -rwxr-xr-x | .local/bin/rem2html | 790 |
1 files changed, 790 insertions, 0 deletions
diff --git a/.local/bin/rem2html b/.local/bin/rem2html new file mode 100755 index 0000000..f298fb3 --- /dev/null +++ b/.local/bin/rem2html | |||
| @@ -0,0 +1,790 @@ | |||
| 1 | #!/usr/bin/env perl | ||
| 2 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 3 | |||
| 4 | use strict; | ||
| 5 | use warnings; | ||
| 6 | |||
| 7 | use Getopt::Long; | ||
| 8 | use JSON::MaybeXS; | ||
| 9 | |||
| 10 | my %Options; | ||
| 11 | |||
| 12 | my $rem2html_version = '2.1'; | ||
| 13 | |||
| 14 | my($days, $shades, $moons, $classes, $Month, $Year, $Numdays, $Firstwkday, $Mondayfirst, $weeks, | ||
| 15 | @Daynames, $Nextmon, $Nextlen, $Prevmon, $Prevlen); | ||
| 16 | |||
| 17 | my $TIDY_PROGNAME = $0; | ||
| 18 | $TIDY_PROGNAME =~ s|^.*/||; | ||
| 19 | |||
| 20 | # rem2html -- convert the output of "remind -pp" to HTML | ||
| 21 | |||
| 22 | =head1 NAME | ||
| 23 | |||
| 24 | rem2html - Convert the output of "remind -pp" to HTML | ||
| 25 | |||
| 26 | =head1 SYNOPSIS | ||
| 27 | |||
| 28 | remind -pp ... | rem2html [options] | ||
| 29 | |||
| 30 | You can also use the old interchange format as below, but the -pp | ||
| 31 | version is preferred. | ||
| 32 | |||
| 33 | remind -p ... | rem2html [options] | ||
| 34 | |||
| 35 | =head1 OPTIONS | ||
| 36 | |||
| 37 | =over 4 | ||
| 38 | |||
| 39 | =item --help, -h | ||
| 40 | |||
| 41 | Print usage information | ||
| 42 | |||
| 43 | =item --version | ||
| 44 | |||
| 45 | Print version | ||
| 46 | |||
| 47 | =item --backurl I<url> | ||
| 48 | |||
| 49 | When producing the small calendar for the previous month, make the | ||
| 50 | month name a link to I<url>. | ||
| 51 | |||
| 52 | =item --forwurl I<url> | ||
| 53 | |||
| 54 | When producing the small calendar for the next month, make the | ||
| 55 | month name a link to I<url>. | ||
| 56 | |||
| 57 | =item --imgbase I<url> | ||
| 58 | |||
| 59 | When creating URLs for the stylesheet or external images, use I<url> | ||
| 60 | as the base URL. | ||
| 61 | |||
| 62 | =item --pngs | ||
| 63 | |||
| 64 | Normally, rem2html uses inline "data:" URLs for the moon phase images, | ||
| 65 | yielding a standalone HTML file. The C<--pngs> option makes it use | ||
| 66 | external images named firstquarter.png, fullmoon.png, lastquarter.png | ||
| 67 | and newmoon.png, which are expected to live in C<--imgbase>. | ||
| 68 | |||
| 69 | =item --stylesheet I<url.css> | ||
| 70 | |||
| 71 | Use I<url.css> as the stylesheet. If this option is used, | ||
| 72 | I<url.css> is interpreted relative to B<imgbase> I<unless> it starts | ||
| 73 | with a "/". | ||
| 74 | |||
| 75 | =item --nostyle | ||
| 76 | |||
| 77 | Produce basic HTML that does not use a CSS stylesheet. | ||
| 78 | |||
| 79 | =item --tableonly | ||
| 80 | |||
| 81 | Output results as a E<lt>tableE<gt> ... E<lt>/tableE<gt> sequence only | ||
| 82 | without any E<lt>htmlE<gt> or E<lt>bodyE<gt> tags. | ||
| 83 | |||
| 84 | =item --title I<title> | ||
| 85 | |||
| 86 | Use I<title> as the content between E<lt>titleE<gt> and E<lt>/titleE<gt> | ||
| 87 | tags. | ||
| 88 | |||
| 89 | |||
| 90 | =item --prologue I<html_text> | ||
| 91 | |||
| 92 | Insert I<html_text> right after the E<lt>bodyE<gt> tag. | ||
| 93 | |||
| 94 | =item --epilogue I<html_text> | ||
| 95 | |||
| 96 | Insert I<html_text> right before the E<lt>/bodyE<gt> tag. | ||
| 97 | |||
| 98 | =back | ||
| 99 | |||
| 100 | =head1 SPECIALS SUPPORTED | ||
| 101 | |||
| 102 | The rem2html back-end supports the following SPECIAL reminders: | ||
| 103 | |||
| 104 | =over | ||
| 105 | |||
| 106 | =item HTML | ||
| 107 | |||
| 108 | Add an HTML reminder to the calendar. All HTML tags are available. | ||
| 109 | |||
| 110 | =item HTMLCLASS | ||
| 111 | |||
| 112 | Add a CSS class to the box representing the trigger date. See | ||
| 113 | "HIGHLIGHTING TODAY" for an example | ||
| 114 | |||
| 115 | =item WEEK, MOON, SHARE, COLOR | ||
| 116 | |||
| 117 | The standard SPECIALs supported by all back-ends | ||
| 118 | |||
| 119 | =back | ||
| 120 | |||
| 121 | =head1 HIGHLIGHTING TODAY | ||
| 122 | |||
| 123 | Older versions of rem2html used to highlight today's date with a red outline. | ||
| 124 | The current version does not do that by default. If you wish to highlight | ||
| 125 | today's date, add the following reminder to your reminders file: | ||
| 126 | |||
| 127 | REM [realtoday()] SPECIAL HTMLCLASS rem-today | ||
| 128 | |||
| 129 | =head1 AUTHOR | ||
| 130 | |||
| 131 | rem2html was written by Dianne Skoll with much inspiration from an | ||
| 132 | earlier version by Don Schwarz. | ||
| 133 | |||
| 134 | =head1 HOME PAGE | ||
| 135 | |||
| 136 | L<https://dianne.skoll.ca/projects/remind/> | ||
| 137 | |||
| 138 | =head1 SEE ALSO | ||
| 139 | |||
| 140 | B<remind>, B<rem2ps>, B<rem2pdf>, B<tkremind> | ||
| 141 | =cut | ||
| 142 | |||
| 143 | sub usage | ||
| 144 | { | ||
| 145 | my ($exit_status) = @_; | ||
| 146 | if (!defined($exit_status)) { | ||
| 147 | $exit_status = 1; | ||
| 148 | } | ||
| 149 | print STDERR <<"EOM"; | ||
| 150 | $TIDY_PROGNAME: Produce an HTML calendar from the output of "remind -pp" | ||
| 151 | |||
| 152 | Usage: remind -pp ... | rem2html [options] | ||
| 153 | |||
| 154 | Options: | ||
| 155 | |||
| 156 | --help, -h Print usage information | ||
| 157 | --man Show man page (requires "perldoc") | ||
| 158 | --version Print version | ||
| 159 | --backurl url Make the title on the previous month's small calendar | ||
| 160 | entry a link to <url> | ||
| 161 | --forwurl url Same as --backurl, but for the next month's small calendar | ||
| 162 | --imgbase url Base URL of images and default stylesheet file | ||
| 163 | --pngs Use external .PNG images for moon phases rater than | ||
| 164 | inline data: URLs | ||
| 165 | --stylesheet url.css URL of CSS stylesheet. If specified, imgbase is NOT | ||
| 166 | prepended to url.css | ||
| 167 | --nostyle Produce basic HTML that does not use a CSS stylesheet | ||
| 168 | --tableonly Output results as a <table> only, no <html>, <body>, etc. | ||
| 169 | --title string What to put in <title>...</title> tags | ||
| 170 | --prologue html_text Text to insert at the top of the body | ||
| 171 | --epilogue html_text Text to insert at the end of the body | ||
| 172 | EOM | ||
| 173 | exit($exit_status); | ||
| 174 | } | ||
| 175 | |||
| 176 | sub smoosh | ||
| 177 | { | ||
| 178 | my ($first, $second) = @_; | ||
| 179 | return $second unless defined ($first); | ||
| 180 | return $second if $first eq ''; | ||
| 181 | return $second if ($second =~ m|^/|); # Absolute path given for second | ||
| 182 | |||
| 183 | # Squash multiple slashes | ||
| 184 | $first =~ s|/+|/|g; | ||
| 185 | |||
| 186 | # Special case | ||
| 187 | return "/$second" if ($first eq '/'); | ||
| 188 | |||
| 189 | # Delete trailing slash | ||
| 190 | $first =~ s|/$||; | ||
| 191 | |||
| 192 | return "$first/$second"; | ||
| 193 | } | ||
| 194 | |||
| 195 | sub parse_options | ||
| 196 | { | ||
| 197 | local $SIG{__WARN__} = sub { print STDERR "$TIDY_PROGNAME: $_[0]\n"; }; | ||
| 198 | if (!GetOptions(\%Options, "help|h", | ||
| 199 | "man", | ||
| 200 | "pngs", | ||
| 201 | "version", | ||
| 202 | "stylesheet=s", | ||
| 203 | "nostyle", | ||
| 204 | "backurl=s", | ||
| 205 | "forwurl=s", | ||
| 206 | "title=s", | ||
| 207 | "prologue=s", | ||
| 208 | "epilogue=s", | ||
| 209 | "imgbase=s", | ||
| 210 | "tableonly")) { | ||
| 211 | usage(1); | ||
| 212 | } | ||
| 213 | $Options{title} ||= 'HTML Calendar'; | ||
| 214 | |||
| 215 | my $stylesheet = $Options{stylesheet}; | ||
| 216 | if ($stylesheet) { | ||
| 217 | $Options{stylesheet} = smoosh($Options{imgbase}, $stylesheet); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | sub start_output | ||
| 222 | { | ||
| 223 | return if ($Options{tableonly}); | ||
| 224 | |||
| 225 | print("<!doctype html>\n"); | ||
| 226 | print("<html>\n<head>\n<title>" . $Options{title} . "</title>\n"); | ||
| 227 | print('<meta charset="utf-8">' . "\n"); | ||
| 228 | print('<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">' . "\n"); | ||
| 229 | if (!$Options{nostyle}) { | ||
| 230 | if ($Options{stylesheet}) { | ||
| 231 | print('<link rel="stylesheet" type="text/css" href="' . | ||
| 232 | $Options{stylesheet} . '">' . "\n"); | ||
| 233 | } else { | ||
| 234 | print("<style>\n"); | ||
| 235 | print default_stylesheet(); | ||
| 236 | print("</style>\n"); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | print("</head>\n<body>\n"); | ||
| 240 | if ($Options{prologue}) { | ||
| 241 | print $Options{prologue} . "\n"; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | sub end_output | ||
| 246 | { | ||
| 247 | return if ($Options{tableonly}); | ||
| 248 | if ($Options{epilogue}) { | ||
| 249 | print $Options{epilogue} . "\n"; | ||
| 250 | } | ||
| 251 | print("</body>\n</html>\n"); | ||
| 252 | } | ||
| 253 | |||
| 254 | sub parse_input | ||
| 255 | { | ||
| 256 | undef $days; | ||
| 257 | undef $shades; | ||
| 258 | undef $moons; | ||
| 259 | undef $classes; | ||
| 260 | undef $weeks; | ||
| 261 | |||
| 262 | my $found_data = 0; | ||
| 263 | while(<STDIN>) { | ||
| 264 | chomp; | ||
| 265 | last if /^\# rem2ps2? begin$/; | ||
| 266 | } | ||
| 267 | |||
| 268 | my $line; | ||
| 269 | # Month Year numdays firstday monday_first_flag | ||
| 270 | $line = <STDIN>; | ||
| 271 | return 0 unless $line; | ||
| 272 | chomp($line); | ||
| 273 | ($Month, $Year, $Numdays, $Firstwkday, $Mondayfirst) = split(' ', $line); | ||
| 274 | |||
| 275 | $Month =~ s/_/ /g; | ||
| 276 | # Day names | ||
| 277 | $line = <STDIN>; | ||
| 278 | return 0 unless $line; | ||
| 279 | chomp($line); | ||
| 280 | @Daynames = split(' ', $line); | ||
| 281 | |||
| 282 | for (my $i=0; $i<7; $i++) { | ||
| 283 | $Daynames[$i] =~ s/_/ /g; | ||
| 284 | } | ||
| 285 | |||
| 286 | # Prevmon prevlen | ||
| 287 | $line = <STDIN>; | ||
| 288 | return 0 unless $line; | ||
| 289 | chomp($line); | ||
| 290 | ($Prevmon, $Prevlen) = split(' ', $line); | ||
| 291 | $Prevmon =~ s/_/ /g; | ||
| 292 | |||
| 293 | # Nextmon nextlen | ||
| 294 | $line = <STDIN>; | ||
| 295 | return 0 unless $line; | ||
| 296 | chomp($line); | ||
| 297 | ($Nextmon, $Nextlen) = split(' ', $line); | ||
| 298 | $Nextmon =~ s/_/ /g; | ||
| 299 | |||
| 300 | $found_data = 1; | ||
| 301 | my $class; | ||
| 302 | if ($Options{nostyle}) { | ||
| 303 | $class = ''; | ||
| 304 | } else { | ||
| 305 | $class = ' class="rem-entry"'; | ||
| 306 | } | ||
| 307 | while(<STDIN>) { | ||
| 308 | chomp; | ||
| 309 | last if /^\# rem2ps2? end$/; | ||
| 310 | next if /^\#/; | ||
| 311 | my ($y, $m, $d, $special, $tag, $duration, $time, $body); | ||
| 312 | if (m/^(\d*).(\d*).(\d*)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/) { | ||
| 313 | ($y, $m, $d, $special, $tag, $duration, $time, $body) = | ||
| 314 | ($1, $2, $3, $4, $5, $6, $7, $8); | ||
| 315 | } elsif (/\{/) { | ||
| 316 | my $obj = decode_json($_); | ||
| 317 | next unless ($obj->{date} =~ /^(\d+)-(\d+)-(\d+)$/); | ||
| 318 | $y = $1; | ||
| 319 | $m = $2; | ||
| 320 | $d = $3; | ||
| 321 | $special = $obj->{passthru} || '*'; | ||
| 322 | $tag = $obj->{tags} || '*'; | ||
| 323 | $duration = $obj->{duration} || '*'; | ||
| 324 | $time = $obj->{time} || '*'; | ||
| 325 | $body = $obj->{body}; | ||
| 326 | } else { | ||
| 327 | next; | ||
| 328 | } | ||
| 329 | my $d1 = $d; | ||
| 330 | $d1 =~ s/^0+//; | ||
| 331 | $special = uc($special); | ||
| 332 | if ($special eq 'HTML') { | ||
| 333 | push(@{$days->[$d]}, $body); | ||
| 334 | } elsif ($special eq 'HTMLCLASS') { | ||
| 335 | $classes->[$d] = $body; | ||
| 336 | } elsif ($special eq 'WEEK') { | ||
| 337 | $body =~ s/^\s+//; | ||
| 338 | $body =~ s/\s+$//; | ||
| 339 | $weeks->{$d1} = $body; | ||
| 340 | } elsif ($special eq 'MOON') { | ||
| 341 | if ($body =~ /(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) { | ||
| 342 | my ($phase, $moonsize, $fontsize, $msg) = ($1, $2, $3, $4); | ||
| 343 | $moons->[$d]->{'phase'} = $phase; | ||
| 344 | $moons->[$d]->{'msg'} = $msg; | ||
| 345 | } elsif ($body =~ /(\S+)/) { | ||
| 346 | $moons->[$d]->{'phase'} = $1; | ||
| 347 | $moons->[$d]->{'msg'} = ''; | ||
| 348 | } | ||
| 349 | } elsif ($special eq 'SHADE') { | ||
| 350 | if ($body =~ /(\d+)\s+(\d+)\s+(\d+)/) { | ||
| 351 | $shades->[$d] = sprintf("#%02X%02X%02X", | ||
| 352 | ($1 % 256), ($2 % 256), ($3 % 256)); | ||
| 353 | } elsif ($body =~ /(\d+)/) { | ||
| 354 | $shades->[$d] = sprintf("#%02X%02X%02X", | ||
| 355 | ($1 % 256), ($1 % 256), ($1 % 256)); | ||
| 356 | } | ||
| 357 | } elsif ($special eq 'COLOR' || $special eq 'COLOUR') { | ||
| 358 | if ($body =~ /(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/) { | ||
| 359 | my($r, $g, $b, $text) = ($1, $2, $3, $4); | ||
| 360 | my $color = sprintf("style=\"color: #%02X%02X%02X;\"", | ||
| 361 | $r % 256, $g % 256, $b % 256); | ||
| 362 | push(@{$days->[$d]}, "<p$class $color>" . escape_html($text) . '</p>'); | ||
| 363 | } | ||
| 364 | } elsif ($special eq '*') { | ||
| 365 | push(@{$days->[$d]}, "<p$class>" . escape_html($body) . '</p>'); | ||
| 366 | } | ||
| 367 | } | ||
| 368 | return $found_data; | ||
| 369 | } | ||
| 370 | |||
| 371 | sub small_calendar | ||
| 372 | { | ||
| 373 | my($month, $monlen, $url, $first_col) = @_; | ||
| 374 | if ($Mondayfirst) { | ||
| 375 | $first_col--; | ||
| 376 | if ($first_col < 0) { | ||
| 377 | $first_col = 6; | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | if ($Options{nostyle}) { | ||
| 382 | print "<td width=\"14%\">\n"; | ||
| 383 | print "<table border=\"0\">\n"; | ||
| 384 | print "<caption>"; | ||
| 385 | } else { | ||
| 386 | print "<td class=\"rem-small-calendar\">\n"; | ||
| 387 | print "<table class=\"rem-sc-table\">\n"; | ||
| 388 | print "<caption class=\"rem-sc-caption\">"; | ||
| 389 | } | ||
| 390 | print "<a href=\"$url\">" if ($url); | ||
| 391 | print $month; | ||
| 392 | print "</a>" if ($url); | ||
| 393 | print "</caption>\n"; | ||
| 394 | |||
| 395 | my $class; | ||
| 396 | if ($Options{nostyle}) { | ||
| 397 | print '<tr>'; | ||
| 398 | $class = ' align="right"'; | ||
| 399 | } else { | ||
| 400 | print '<tr class="rem-sc-hdr-row">'; | ||
| 401 | $class = ' class="rem-sc-hdr"'; | ||
| 402 | } | ||
| 403 | if (!$Mondayfirst) { | ||
| 404 | print "<th$class>" . substr($Daynames[0], 0, 1) . '</th>'; | ||
| 405 | } | ||
| 406 | for (my $i=1; $i<7; $i++) { | ||
| 407 | print "<th$class>" . substr($Daynames[$i], 0, 1) . '</th>'; | ||
| 408 | } | ||
| 409 | if ($Mondayfirst) { | ||
| 410 | print "<th$class>" . substr($Daynames[0], 0, 1) . '</th>'; | ||
| 411 | } | ||
| 412 | print("</tr>\n"); | ||
| 413 | my $col = 0; | ||
| 414 | for (; $col<$first_col; $col++) { | ||
| 415 | if ($col == 0) { | ||
| 416 | print("<tr>\n"); | ||
| 417 | } | ||
| 418 | if ($Options{nostyle}) { | ||
| 419 | print("<td align=\"right\" width=\"14%\"> </td>"); | ||
| 420 | } else { | ||
| 421 | print("<td class=\"rem-sc-empty-cell\"> </td>"); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | for (my $day=1; $day <= $monlen; $day++) { | ||
| 426 | if ($col == 0) { | ||
| 427 | print("<tr>\n"); | ||
| 428 | } | ||
| 429 | $col++; | ||
| 430 | if ($Options{nostyle}) { | ||
| 431 | print("<td align=\"right\" width=\"14%\">$day</td>"); | ||
| 432 | } else { | ||
| 433 | print("<td class=\"rem-sc-cell\">$day</td>"); | ||
| 434 | } | ||
| 435 | if ($col == 7) { | ||
| 436 | print("</tr>\n"); | ||
| 437 | $col = 0; | ||
| 438 | } | ||
| 439 | } | ||
| 440 | if ($col) { | ||
| 441 | while ($col < 7) { | ||
| 442 | if ($Options{nostyle}) { | ||
| 443 | print("<td align=\"right\" width=\"14%\"> </td>"); | ||
| 444 | } else { | ||
| 445 | print("<td class=\"rem-sc-empty-cell\"> </td>"); | ||
| 446 | } | ||
| 447 | $col++; | ||
| 448 | } | ||
| 449 | print("</tr>\n"); | ||
| 450 | } | ||
| 451 | print("</table>\n"); | ||
| 452 | print "</td>\n"; | ||
| 453 | } | ||
| 454 | |||
| 455 | sub output_calendar | ||
| 456 | { | ||
| 457 | # Which column is 1st of month in? | ||
| 458 | my $first_col = $Firstwkday; | ||
| 459 | if ($Mondayfirst) { | ||
| 460 | $first_col--; | ||
| 461 | if ($first_col < 0) { | ||
| 462 | $first_col = 6; | ||
| 463 | } | ||
| 464 | } | ||
| 465 | |||
| 466 | # Last column | ||
| 467 | my $last_col = ($first_col + $Numdays - 1) % 7; | ||
| 468 | |||
| 469 | # Figure out how many rows | ||
| 470 | my $number_of_rows = int(($first_col + $Numdays ) / 7 + 0.999); | ||
| 471 | |||
| 472 | # Add a row for small calendars if necessary | ||
| 473 | if ($first_col == 0 && $last_col == 6) { | ||
| 474 | $number_of_rows++; | ||
| 475 | } | ||
| 476 | |||
| 477 | # Start the table | ||
| 478 | my $class; | ||
| 479 | if ($Options{nostyle}) { | ||
| 480 | print '<table width="100%" border="1" cellspacing=\"0\"><caption>' . | ||
| 481 | $Month . ' ' . $Year . '</caption>' . "\n"; | ||
| 482 | print '<tr>'; | ||
| 483 | $class = ' width="14%"'; | ||
| 484 | } else { | ||
| 485 | print '<table class="rem-cal"><caption class="rem-cal-caption">' . | ||
| 486 | $Month . ' ' . $Year . '</caption>' . "\n"; | ||
| 487 | print '<tr class="rem-cal-hdr-row">'; | ||
| 488 | $class = ' class="rem-cal-hdr"'; | ||
| 489 | } | ||
| 490 | if (!$Mondayfirst) { | ||
| 491 | print "<th$class>" . $Daynames[0] . '</th>'; | ||
| 492 | } | ||
| 493 | for (my $i=1; $i<7; $i++) { | ||
| 494 | print "<th$class>" . $Daynames[$i] . '</th>'; | ||
| 495 | } | ||
| 496 | if ($Mondayfirst) { | ||
| 497 | print "<th$class>" . $Daynames[0] . '</th>'; | ||
| 498 | } | ||
| 499 | print "</tr>\n"; | ||
| 500 | |||
| 501 | # Start the calendar rows | ||
| 502 | my $col = 0; | ||
| 503 | if ($Options{nostyle}) { | ||
| 504 | print "<tr>\n"; | ||
| 505 | } else { | ||
| 506 | print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n"; | ||
| 507 | } | ||
| 508 | if ($first_col > 0) { | ||
| 509 | small_calendar($Prevmon, $Prevlen, $Options{backurl}, | ||
| 510 | ($Firstwkday - $Prevlen + 35) % 7); | ||
| 511 | $col++; | ||
| 512 | } | ||
| 513 | |||
| 514 | if ($last_col == 6 && $first_col > 0) { | ||
| 515 | small_calendar($Nextmon, $Nextlen, $Options{forwurl}, | ||
| 516 | ($Firstwkday + $Numdays) % 7); | ||
| 517 | $col++; | ||
| 518 | } | ||
| 519 | if ($Options{nostyle}) { | ||
| 520 | $class = ' width="14%"'; | ||
| 521 | } else { | ||
| 522 | $class = ' class="rem-empty rem-empty-$number_of_rows-rows"'; | ||
| 523 | } | ||
| 524 | while ($col < $first_col) { | ||
| 525 | print("<td$class> </td>\n"); | ||
| 526 | $col++; | ||
| 527 | } | ||
| 528 | |||
| 529 | for (my $day=1; $day<=$Numdays; $day++) { | ||
| 530 | draw_day_cell($day, $number_of_rows); | ||
| 531 | $col++; | ||
| 532 | if ($col == 7) { | ||
| 533 | $col = 0; | ||
| 534 | print "</tr>\n"; | ||
| 535 | if ($day < $Numdays) { | ||
| 536 | if ($Options{nostyle}) { | ||
| 537 | print "<tr>\n"; | ||
| 538 | } else { | ||
| 539 | print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n"; | ||
| 540 | } | ||
| 541 | } | ||
| 542 | } | ||
| 543 | } | ||
| 544 | |||
| 545 | if ($col) { | ||
| 546 | while ($col < 7) { | ||
| 547 | if ($col == 5) { | ||
| 548 | if ($first_col == 0) { | ||
| 549 | small_calendar($Prevmon, $Prevlen, $Options{backurl}, | ||
| 550 | ($Firstwkday - $Prevlen + 35) % 7); | ||
| 551 | } else { | ||
| 552 | print("<td$class> </td>\n"); | ||
| 553 | } | ||
| 554 | } elsif ($col == 6) { | ||
| 555 | small_calendar($Nextmon, $Nextlen, $Options{forwurl}, | ||
| 556 | ($Firstwkday + $Numdays) % 7); | ||
| 557 | } else { | ||
| 558 | print("<td$class> </td>\n"); | ||
| 559 | } | ||
| 560 | $col++; | ||
| 561 | } | ||
| 562 | print "</tr>\n"; | ||
| 563 | } | ||
| 564 | |||
| 565 | # Add a row for small calendars if they were not yet done! | ||
| 566 | if ($first_col == 0 && $last_col == 6) { | ||
| 567 | if ($Options{nostyle}) { | ||
| 568 | print "<tr>\n"; | ||
| 569 | } else { | ||
| 570 | print "<tr class=\"rem-cal-row rem-cal-row-$number_of_rows-rows\">\n"; | ||
| 571 | } | ||
| 572 | small_calendar($Prevmon, $Prevlen, $Options{backurl}, | ||
| 573 | ($Firstwkday - $Prevlen + 35) % 7); | ||
| 574 | for (my $i=0; $i<5; $i++) { | ||
| 575 | print("<td$class> </td>\n"); | ||
| 576 | } | ||
| 577 | small_calendar($Nextmon, $Nextlen, $Options{forwurl}, | ||
| 578 | ($Firstwkday + $Numdays) % 7); | ||
| 579 | print("</tr>\n"); | ||
| 580 | } | ||
| 581 | # End the table | ||
| 582 | print "</table>\n"; | ||
| 583 | } | ||
| 584 | |||
| 585 | sub draw_day_cell | ||
| 586 | { | ||
| 587 | my($day, $number_of_rows) = @_; | ||
| 588 | my $shade = $shades->[$day]; | ||
| 589 | my $week = ''; | ||
| 590 | if (exists($weeks->{$day})) { | ||
| 591 | $week = ' ' . $weeks->{$day}; | ||
| 592 | } | ||
| 593 | my $class; | ||
| 594 | if ($Options{nostyle}) { | ||
| 595 | $class = $classes->[$day] || ''; | ||
| 596 | } else { | ||
| 597 | $class = $classes->[$day] || "rem-cell rem-cell-$number_of_rows-rows"; | ||
| 598 | } | ||
| 599 | if ($shade) { | ||
| 600 | $shade = " style=\"background: $shade;\""; | ||
| 601 | } else { | ||
| 602 | $shade = ""; | ||
| 603 | } | ||
| 604 | if ($class ne '') { | ||
| 605 | print "<td class=\"$class\"$shade>\n"; | ||
| 606 | } else { | ||
| 607 | print "<td valign=\"top\" $shade>\n"; | ||
| 608 | } | ||
| 609 | if ($moons->[$day]) { | ||
| 610 | my $phase = $moons->[$day]->{'phase'}; | ||
| 611 | my $msg = $moons->[$day]->{'msg'}; | ||
| 612 | $msg ||= ''; | ||
| 613 | if ($msg ne '') { | ||
| 614 | $msg = ' ' . escape_html($msg); | ||
| 615 | } | ||
| 616 | my $img; | ||
| 617 | my $alt; | ||
| 618 | my $title; | ||
| 619 | if ($phase == 0) { | ||
| 620 | if ($Options{pngs}) { | ||
| 621 | $img = smoosh($Options{imgbase}, 'newmoon.png'); | ||
| 622 | } else { | ||
| 623 | $img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAC6SURBVDiNpdNNbsIwFATgL0HKolchHKBX6yFaBOEyoPYUabvOIVKJRaCL2JX5TRNGGvnJ8ozGz89cYoElPvET+BX2yivn/1Bggw5HHMKa1h2qcPZC/JEIhvh+brIZIY6sorhMYo9hh3KGFzzfa84NZNjDt9OG/ZcH1BlaPE1IAG0+URhxzNGESKPFaHJs9Q0Ziww7HnvGeXSrJhis0jiFfjwnj3I0WRv+TKtr4hQl3lDrZ6QN9Wt654hfWfGDmBpUwDkAAAAASUVORK5CYII='; | ||
| 624 | } | ||
| 625 | $title = 'New Moon'; | ||
| 626 | $alt = 'new'; | ||
| 627 | } elsif ($phase == 1) { | ||
| 628 | if ($Options{pngs}) { | ||
| 629 | $img = smoosh($Options{imgbase}, 'firstquarter.png'); | ||
| 630 | } else { | ||
| 631 | $img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADfSURBVDiNndM9TsNAFATgzy5yjZSAE85JBygETgENUPF3iBCitHAFQkcIhZ/Ryn9gRlrZmp2Z3ef3TBOHOMULPrDBMrhpi/4HI5xjix2+4nmJRbx/Yh7ahvkpRPVV4QDXwT3UQy46zGkAZDgK/iytefvHgCrkJsqZUH6cLnNbABSxd5Jhhf1IbkMXv8Qux7hH1Ic1xvk/jBWy6gavumvtwx7ectwZXkKh7MA95XgObeOtpI2U4zl0kGbpxgiPvwQUcXLrKFchc82f6Ur0PK49azOnmOI4TBu84zm4SV38DeIVYkrYJyNbAAAAAElFTkSuQmCC'; | ||
| 632 | } | ||
| 633 | $title = 'First Quarter'; | ||
| 634 | $alt = '1st'; | ||
| 635 | } elsif ($phase == 2) { | ||
| 636 | if ($Options{pngs}) { | ||
| 637 | $img = smoosh($Options{imgbase}, 'fullmoon.png'); | ||
| 638 | } else { | ||
| 639 | $img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADlSURBVDiNrdNBUsJAEAXQlyw4hq4hwWPqTixET6ELkZ16CcAq7oFLqXExjaYgQVNlV/Viev7/6XT/4TjGuME7PiLXUatb8N8xwB12SFjiIXIZtU/MAntEfgvQE4YtHxhiHpjXQ5H7uLhEcaLLAleBvd0Xx9Ha/BdyU+Q5OBV5OKmj7a4YBWdSyNPe4aKHAHkzqcQZNj3JgnNexqE8heyIAulffuFF3kTfIVbBVeu/xoXGGsn2TLJJ/mqkafNiINszySYZdbS90GHlvcgsWktY4TFy7ecxTdvIzahxHQLbyFXUqkPwF2ASRNYgB/PXAAAAAElFTkSuQmCC'; | ||
| 640 | } | ||
| 641 | $alt = 'full'; | ||
| 642 | $title = 'Full Moon'; | ||
| 643 | } else { | ||
| 644 | if ($Options{pngs}) { | ||
| 645 | $img = smoosh($Options{imgbase}, 'lastquarter.png'); | ||
| 646 | } else { | ||
| 647 | $img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAGQAAABkABchkaRQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADmSURBVDiNndMxTsNAEIXhzy5yCyQ6FAgcE7oQheQWUAAl5BIkREoZrgB0GFNkHBl7bURGsryaee/3jHeXdpxjghU+8InXyI0S+n0MMEeBEi+4jfV3vAvMQtsyL0J0j2GtViaeRRMyj8IlsgY8BSijE2Kur/hy09wHKMJrEolhwtwHKDHOsI4OLnoAXfl1jiNsOkR9keE4P8D4q4scbzg5xIxtjie709f1E7siC+9+Gx/8fxvPKtEsklcJSBdgWhcN8ByFR5z+AWgd5QpyE+OUWOJO+zJNU+Z6jHAdgHe7K73CuD5zFT9nCmRDIssCaAAAAABJRU5ErkJggg=='; | ||
| 648 | } | ||
| 649 | $alt = 'last'; | ||
| 650 | $title = 'Last Quarter'; | ||
| 651 | } | ||
| 652 | if ($Options{nostyle}) { | ||
| 653 | print("<div style=\"float: left\"><img border=\"0\" width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">$msg</div>"); | ||
| 654 | } else { | ||
| 655 | print("<div class=\"rem-moon\"><img width=\"16\" height=\"16\" alt=\"$alt\" title=\"$title\" src=\"$img\">$msg</div>"); | ||
| 656 | } | ||
| 657 | } | ||
| 658 | |||
| 659 | if ($Options{nostyle}) { | ||
| 660 | print "<div style=\"float: right\">$day$week</div>\n"; | ||
| 661 | print "<p> </p>\n"; | ||
| 662 | } else { | ||
| 663 | print "<div class=\"rem-daynumber\">$day$week</div>\n"; | ||
| 664 | } | ||
| 665 | if ($days->[$day]) { | ||
| 666 | print(join("\n", @{$days->[$day]})); | ||
| 667 | } | ||
| 668 | |||
| 669 | print "</td>\n"; | ||
| 670 | } | ||
| 671 | |||
| 672 | sub escape_html | ||
| 673 | { | ||
| 674 | my($in) = @_; | ||
| 675 | $in =~ s/\&/\&/g; | ||
| 676 | $in =~ s/\</\</g; | ||
| 677 | $in =~ s/\>/\>/g; | ||
| 678 | return $in; | ||
| 679 | } | ||
| 680 | |||
| 681 | parse_options(); | ||
| 682 | if ($Options{help}) { | ||
| 683 | usage(0); | ||
| 684 | exit(0); | ||
| 685 | } elsif ($Options{man}) { | ||
| 686 | system("perldoc $0"); | ||
| 687 | exit(0); | ||
| 688 | } elsif ($Options{version}) { | ||
| 689 | print "rem2html version $rem2html_version.\n"; | ||
| 690 | exit(0); | ||
| 691 | } | ||
| 692 | |||
| 693 | if (-t STDIN) { ## no critic | ||
| 694 | print STDERR "$TIDY_PROGNAME: Input should not come from a terminal.\n\n"; | ||
| 695 | usage(1); | ||
| 696 | } | ||
| 697 | |||
| 698 | my $found_something = 0; | ||
| 699 | while(1) { | ||
| 700 | last if (!parse_input()); | ||
| 701 | start_output() unless $found_something; | ||
| 702 | $found_something = 1; | ||
| 703 | output_calendar(); | ||
| 704 | } | ||
| 705 | if ($found_something) { | ||
| 706 | end_output(); | ||
| 707 | exit(0); | ||
| 708 | } else { | ||
| 709 | print STDERR "$TIDY_PROGNAME: Could not find any calendar data on STDIN.\n"; | ||
| 710 | exit(1); | ||
| 711 | } | ||
| 712 | |||
| 713 | sub default_stylesheet | ||
| 714 | { | ||
| 715 | return <<'EOF'; | ||
| 716 | table.rem-cal { | ||
| 717 | font-family: helvetica, arial, sans-serif; | ||
| 718 | font-size: 12pt; | ||
| 719 | } | ||
| 720 | |||
| 721 | table.rem-sc-table { | ||
| 722 | font-family: helvetica, arial, sans-serif; | ||
| 723 | font-size: 10pt; | ||
| 724 | width: 95%; | ||
| 725 | float: left; | ||
| 726 | } | ||
| 727 | |||
| 728 | caption.rem-cal-caption { | ||
| 729 | font-size: 14pt; | ||
| 730 | font-weight: bold; | ||
| 731 | } | ||
| 732 | |||
| 733 | th.rem-cal-hdr { | ||
| 734 | width: 14%; | ||
| 735 | border-style: solid; | ||
| 736 | border-width: 1px; | ||
| 737 | vertical-align: top; | ||
| 738 | } | ||
| 739 | td.rem-empty, td.rem-cell, td.rem-small-calendar { | ||
| 740 | width: 14%; | ||
| 741 | height: 7em; | ||
| 742 | border-style: solid; | ||
| 743 | border-width: 1px; | ||
| 744 | vertical-align: top; | ||
| 745 | } | ||
| 746 | td.rem-today { | ||
| 747 | width: 14%; | ||
| 748 | height: 7em; | ||
| 749 | border-style: solid; | ||
| 750 | border-width: 2px; | ||
| 751 | border-color: #EE3333; | ||
| 752 | vertical-align: top; | ||
| 753 | } | ||
| 754 | |||
| 755 | table.rem-cal { | ||
| 756 | width: 100%; | ||
| 757 | border-collapse: collapse; | ||
| 758 | } | ||
| 759 | |||
| 760 | div.rem-daynumber { | ||
| 761 | float: right; | ||
| 762 | text-align: right; | ||
| 763 | vertical-align: top; | ||
| 764 | font-size: 14pt; | ||
| 765 | } | ||
| 766 | |||
| 767 | p.rem-entry { | ||
| 768 | clear: both; | ||
| 769 | } | ||
| 770 | |||
| 771 | div.rem-moon { | ||
| 772 | float: left; | ||
| 773 | text-align: left; | ||
| 774 | vertical-align: top; | ||
| 775 | } | ||
| 776 | |||
| 777 | th.rem-sc-hdr { | ||
| 778 | text-align: right; | ||
| 779 | } | ||
| 780 | |||
| 781 | td.rem-sc-empty-cell, td.rem-sc-cell { | ||
| 782 | text-align: right; | ||
| 783 | width: 14%; | ||
| 784 | } | ||
| 785 | |||
| 786 | caption.rem-sc-caption { | ||
| 787 | font-size: 12pt; | ||
| 788 | } | ||
| 789 | EOF | ||
| 790 | } | ||
