3 #==============================================================================
5 # File ID: c1080bc6-f742-11dd-acb1-000475e441b9
6 # Ny versjon av DBK-systemet.
9 # ©opyleft 1999– Øyvind A. Holm <sunny@sunbase.org>
10 # License: GNU General Public License version 2 or later, see end of file for
12 #==============================================================================
38 $progname =~ s/^.*\/(.*?)$/$1/;
39 our $VERSION = '0.2.0';
41 my $STD_DIR = "$ENV{HOME}/dbk";
42 my $STD_VIEWER = "lynx -assume_charset=UTF-8";
44 Getopt
::Long
::Configure
('bundling');
47 'batch|b' => \
$Opt{'batch'},
48 'force|f' => \
$Opt{'force'},
49 'help|h' => \
$Opt{'help'},
50 'insert-file|i=s' => \
$Opt{'insert-file'},
51 'now|t' => \
$Opt{'now'},
52 'quiet|q+' => \
$Opt{'quiet'},
53 'verbose|v+' => \
$Opt{'verbose'},
54 'version' => \
$Opt{'version'},
55 'zone|z' => \
$Opt{'zone'},
57 ) || die("$progname: Option error. Use -h for help.\n");
59 $Opt{'verbose'} -= $Opt{'quiet'};
60 $Opt{'help'} && usage
(0);
61 if ($Opt{'version'}) {
66 my $time_not_found = 0;
75 if (defined($ENV{'DBK_DIR'}) && length($ENV{'DBK_DIR'})) {
76 $dbk_dir = $ENV{'DBK_DIR'};
81 if (defined($ENV{'DBK_VIEWER'}) && length($ENV{'DBK_VIEWER'})) {
82 $Viewer = $ENV{'DBK_VIEWER'};
84 $Viewer = $STD_VIEWER;
86 my $dbk_ext = ".html";
87 my $dbk_lockext = ".lock";
91 my @day_name = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
93 msg
(3, "$0: \$Opt{'now'} = $Opt{'now'}");
95 my ($Sec, $Min, $Hour, $Day, $Mon, $Year, $Wday, $Yday, $is_dst)
96 = localtime($curr_time);
101 msg
(3, "\$curr_time: $Year-$Mon-$Day $Hour:$Min:$Sec,"
102 . " \$Wday = $Wday, \$Yday = $Yday, \$is_dst = $is_dst");
104 # Parameterparsing og initialisering av datovariabler
106 my $time_str = ""; # Strengen som det vil bli leita etter og som blir
110 /^\d\d:/ && (splice(@ARGV, $arg_count, 1),
116 $Year = $ARGV[2] if $#ARGV >= 2;
117 $Mon = sprintf("%02u", $ARGV[1]) if $#ARGV >= 1;
118 $Day = sprintf("%02u", $ARGV[0]) if $#ARGV >= 0;
120 # Når vi nærmer oss 2030 begynner dette å bli en fixme. :)
123 } elsif ($Year < 100) {
127 $Mon =~ s/^(\d)$/0$1/;
128 $Day =~ s/^(\d)$/0$1/;
129 $Hour =~ s/^(\d)$/0$1/;
130 $Min =~ s/^(\d)$/0$1/;
131 $Sec =~ s/^(\d)$/0$1/;
133 die("$0: $Day: Feil format på datoen\n") unless ($Day =~ /^\d\d$/);
134 die("$0: $Mon: Feil format på måneden\n") unless ($Mon =~ /^\d\d$/);
135 die("$0: $Year: Feil format på året\n") unless ($Year =~ /^\d\d\d\d$/);
137 my $time_utc = timegm
($Sec, $Min, $Hour, $Day, $Mon-1, $Year);
138 my $time_sec = timelocal
($Sec, $Min, $Hour, $Day, $Mon-1, $Year);
139 my @time_arr = localtime($time_sec);
140 my $week_day = $time_arr[6];
141 my $utc_diff = ($time_utc-$time_sec)/3600;
143 msg
(3, "Etter ARGV: $Year-$Mon-$Day");
144 msg
(3, "\$dbk_dir = $dbk_dir");
145 msg
(3, "\$Opt{'insert-file'} = \"$Opt{'insert-file'}\"");
147 # Sjekk at alle katalogene er på plass
148 my $year_dir = "$dbk_dir/$Year";
149 my $dbk_file = "$year_dir/${Year}${Mon}${Day}${dbk_ext}";
150 my $lock_dir = "$year_dir/${Year}${Mon}${Day}${dbk_lockext}";
153 unless (-d
$dbk_dir) {
154 mkdir($dbk_dir, $dir_mode)
155 || die("$0: $dbk_dir: Kan ikke lage directoryen: $!\n");
157 unless (-d
$year_dir) {
158 mkdir($year_dir, $dir_mode)
159 || die("$0: $year_dir: Kan ikke lage directoryen: $!\n");
162 msg
(3, "\$dbk_file = $dbk_file");
165 rmdir($lock_dir) || warn("$0: $lock_dir:"
166 . " Kan ikke fjerne gammel lockdir"
167 . " med makt: $!\n");
170 create_lock
($lock_dir);
172 open(CheckFP
, ">$year_dir/.check")
173 || die("$0: $year_dir/.check: Klarte ikke å lage fila: $!\n");
175 unlink("$year_dir/.check")
176 || die("$0: $year_dir/.check: Cannot delete file, aborting");
178 unless (-f
$dbk_file) {
179 open(FP
, ">$dbk_file")
180 || die("$0: $dbk_file: Kan ikke åpne fila for skriving: $!\n");
181 print(FP
"<h1>$day_name[$week_day] $Year-$Mon-$Day</h1>\n")
182 || die("$0: $dbk_file: Kan ikke skrive header til fila: $!\n");
186 my $min_size = 0; # Minimum size of file to prevent deletion
189 # Legg til klokkeslettet akkurat nå i fila og gå inn i editoren
190 my $utc_str = sprintf("%s%02u00",
191 $utc_diff < 0 ?
"-" : "+", $utc_diff);
192 $utc_str = "" unless $Opt{'zone'};
193 if (length($time_str)) {
194 $time_str .= $utc_str;
196 $time_str = "$Hour:$Min:$Sec$utc_str";
198 open(dbkFP
, "+<$dbk_file")
199 || die("$0: $dbk_file:"
200 . " Kan ikke åpne fila for lesing+skriving+flock:"
202 flock(dbkFP
, LOCK_EX
)
203 || die("$0: $dbk_file: Klarte ikke flock(): $!\n");
204 my $which_line = find_line
($dbk_file, $time_str);
205 if ($time_not_found) {
207 || die("$0: $dbk_file: Klarte ikke å seeke"
208 . " til slutten for å legge til LF: $!\n");
210 || warn("$0: $dbk_file: Feil under skriving til fila:"
214 length($Opt{'insert-file'})
215 ? insert_file
($dbk_file, $Opt{'insert-file'},
216 $which_line, $time_str)
217 : insert_time
($dbk_file, $time_str, $which_line);
220 system("$Editor +$which_line $dbk_file") unless
221 (length($Opt{'insert-file'}) || length($Opt{'batch'}));
227 unless ($Opt{'batch'}) {
228 system("$Viewer $dbk_file");
231 my @stat_info = stat($dbk_file);
232 my $file_size = $stat_info[7];
233 if ($file_size < $min_size) {
234 print("Ingenting ble skrevet, så jeg sletter driten.\n");
236 || warn("$0: $dbk_file: Klarte ikke å slette fila: $!\n");
240 remove_lock
($lock_dir);
248 my $lock_dir = shift;
251 until (mkdir($lock_dir, 0777)) {
252 $print_ok || print(STDERR
"Venter på at lockdir $lock_dir"
253 . " skal forsvinne ($!)..");
258 $print_ok && print("OK\n");
264 my $lock_dir = shift;
267 || die("$0: $lock_dir: Klarte ikke å slette lockdir: $!\n");
273 my ($dbk_file, $srch_time) = @_;
277 || die("$dbk_file: Klarte ikke å gå til begynnelsen av fila: $!\n");
279 if (/^(?:<p>)?<b>(\d\d:\d\d:\d\d)/i
280 || /^(?:<p>)?<b>(\d\d:\d\d)/i) {
282 return($.) if ($srch_time lt $found_time);
290 my ($dbk_file, $time_str, $line_num) = @_;
292 || die("$dbk_file: Klarte ikke å gå"
293 . " til begynnelsen av fila i insert_time(): $!\n");
294 my @Linjer = <dbkFP
>;
299 sprintf("<b>$time_str</b> -\n%s", $time_not_found ?
"" : "\n")
302 || die("$0: $dbk_file: Klarte ikke å seeke til starten"
303 . " i insert_time(): $!\n");
305 || die("$0: $dbk_file: Klarte ikke å trunce fila til 0: $!\n");
308 || warn("$0: $dbk_file: Å neiiii, katastrofe!"
309 . " Feil under skriving til fila: $!\n");
314 # Sjekker om en tekst inneholder ulovlige UTF-8-sekvenser og returnerer
318 # Henta fra "find_inv_utf8,v 1.1 2001/09/07 08:54:31 sunny" og
319 # modifisert litt. FIXME: Klager ikke på overlange sekvenser og tegn i
320 # UTF-16-surrogatområdet
321 $Str =~ s
/([\xFC-\xFD][\x80-\xBF][\x80-\xBF]
322 [\x80-\xBF][\x80-\xBF][\x80-\xBF])//gx;
323 $Str =~ s/([\xF8-\xFB][\x80-\xBF][\x80-\xBF][\x80-\xBF][\x80-\xBF])//g;
324 $Str =~ s/([\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF])//g;
325 $Str =~ s/([\xE0-\xEF][\x80-\xBF][\x80-\xBF])//g;
326 $Str =~ s/([\xC0-\xDF][\x80-\xBF])//g;
327 $Retval = 0 if ($Str =~ /[\x80-\xFD]/);
328 msg
(3, "is_utf8() returnerer $Retval.");
333 my ($dbk_file, $file_name, $line_num, $time_str) = @_;
336 || die("$0: $dbk_file: Klarte ikke å gå til begynnelsen av fila"
337 . " i insert_file(): $!\n");
338 my @Linjer = <dbkFP
>;
339 my @InsLinj = "<b>$time_str</b> -\n";
340 open(LocFP
, "<$file_name")
341 || die("$0: $file_name: Kan ikke åpne fila for lesing: $!\n");
342 push(@InsLinj, <LocFP
>);
343 push(@InsLinj, "\n") unless $time_not_found; # Denne likte jeg egentlig
344 # fantastisk dårlig, men
345 # hvem bruker vel å ha to
346 # LF’er på slutten av
349 msg
(3, "\$_ = \"$_\"");
351 warn("$0: Ugyldig UTF-8 funnet,"
352 . " behandler teksten som ISO-8859-1.\n");
354 for my $Curr (@InsLinj) {
355 msg
(3, "FØR : \$Curr = \"$Curr\"");
356 $Curr =~ s/([\x80-\xFF])/widechar(ord($1))/ge;
357 msg
(3, "ETTER: \$Curr = \"$Curr\"");
364 splice(@Linjer, $line_num-1, 0, @InsLinj);
367 || die("$0: $dbk_file: Klarte ikke å seeke til starten"
368 . " i insert_file(): $!\n");
370 || die("$0: $dbk_file: Klarte ikke å trunce fila til 0: $!\n");
371 msg
(3, "scalar(\@Linjer): \"" . scalar(@Linjer) . "\".");
372 foreach my $Curr (@Linjer) {
373 $Curr =~ s/&#(\d{1,10});/widechar($1)/ge;
374 $Curr =~ s/&#x([0-9a-f]{1,8});/widechar(hex($1))/gei;
376 || warn("$0: $dbk_file: Knallkrise."
377 . " Feil under skriving til fila: $!\n");
382 # Print program version
383 print("$progname $VERSION\n");
388 # Send the help message to stdout
391 if ($Opt{'verbose'}) {
397 Syntax: $progname [valg] [dag [måned [år]]] [HH:MM]
402 Batch mode, ikke start editor eller viewer.
404 Force, start dbk selv om lockdir eksisterer.
407 -i x, --insert-file x
408 Sett inn filen x istedenfor å bruke tastatur. Forventer -t eller
411 Be more quiet. Can be repeated to increase silence.
413 Legg til klokkeslettet akkurat nå i fila og gå inn i editoren
415 Increase level of verbosity. Can be repeated.
417 Print version information.
419 Legg til tidssone til klokkeslett
421 Klokkeslettet kan spesifiseres hvor som helst, men må starte med
422 formatet "HH:" der HH er to siffer.
424 Environment variables:
427 Path to directory where files will be stored.
430 Specify HTML browser to use when viewing files.
431 Default: "$STD_VIEWER"
438 # Print a status message to stderr based on verbosity level
439 my ($verbose_level, $Txt) = @_;
441 if ($Opt{'verbose'} >= $verbose_level) {
442 print(STDERR
"$progname: $Txt\n");
448 # Konverterer en tegnverdi til UTF-8
449 # Henta fra "h2u,v 1.5 2002/11/20 00:09:40 sunny".
451 my $allow_invalid = 0;
454 return sprintf("%c", $Val);
455 } elsif ($Val < 0x800) {
456 return sprintf("%c%c", 0xC0 | ($Val >> 6),
457 0x80 | ($Val & 0x3F));
458 } elsif ($Val < 0x10000) {
459 unless ($allow_invalid) {
460 if (($Val >= 0xD800 && $Val <= 0xDFFF)
462 || ($Val eq 0xFFFF)) {
466 return sprintf("%c%c%c", 0xE0 | ($Val >> 12),
467 0x80 | (($Val >> 6) & 0x3F),
468 0x80 | ($Val & 0x3F));
469 } elsif ($Val < 0x200000) {
470 return sprintf("%c%c%c%c", 0xF0 | ($Val >> 18),
471 0x80 | (($Val >> 12) & 0x3F),
472 0x80 | (($Val >> 6) & 0x3F),
473 0x80 | ($Val & 0x3F));
474 } elsif ($Val < 0x4000000) {
475 return sprintf("%c%c%c%c%c", 0xF8 | ($Val >> 24),
476 0x80 | (($Val >> 18) & 0x3F),
477 0x80 | (($Val >> 12) & 0x3F),
478 0x80 | (($Val >> 6) & 0x3F),
479 0x80 | ( $Val & 0x3F));
480 } elsif ($Val < 0x80000000) {
481 return sprintf("%c%c%c%c%c%c", 0xFC | ($Val >> 30),
482 0x80 | (($Val >> 24) & 0x3F),
483 0x80 | (($Val >> 18) & 0x3F),
484 0x80 | (($Val >> 12) & 0x3F),
485 0x80 | (($Val >> 6) & 0x3F),
486 0x80 | ( $Val & 0x3F));
488 return widechar
(0xFFFD);
494 # This program is free software; you can redistribute it and/or modify it under
495 # the terms of the GNU General Public License as published by the Free Software
496 # Foundation; either version 2 of the License, or (at your option) any later
499 # This program is distributed in the hope that it will be useful, but WITHOUT
500 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
501 # FOR A PARTICULAR PURPOSE.
502 # See the GNU General Public License for more details.
504 # You should have received a copy of the GNU General Public License along with
506 # If not, see L<http://www.gnu.org/licenses/>.
508 # vim: set ts=8 sw=8 sts=8 noet fo+=w tw=79 fenc=UTF-8 :