ncurses 6.3
[ncurses.git] / misc / ncu2openbsd
1 #!/usr/bin/env perl
2 # $Id: ncu2openbsd,v 1.65 2021/10/03 18:52:22 tom Exp $
3 # -----------------------------------------------------------------------------
4 # Copyright 2021 by Thomas E. Dickey
5 #
6 #                         All Rights Reserved
7 #
8 # Permission is hereby granted, free of charge, to any person obtaining a
9 # copy of this software and associated documentation files (the
10 # "Software"), to deal in the Software without restriction, including
11 # without limitation the rights to use, copy, modify, merge, publish,
12 # distribute, sublicense, and/or sell copies of the Software, and to
13 # permit persons to whom the Software is furnished to do so, subject to
14 # the following conditions:
15 #
16 # The above copyright notice and this permission notice shall be included
17 # in all copies or substantial portions of the Software.
18 #
19 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 # IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 #
27 # Except as contained in this notice, the name(s) of the above copyright
28 # holders shall not be used in advertising or otherwise to promote the
29 # sale, use or other dealings in this Software without prior written
30 # authorization.
31 # -----------------------------------------------------------------------------
32 # https://invisible-island.net/ncurses/ncurses-openbsd.html
33 #
34 # Update the OpenBSD source-tree given an ncurses tarball or build-tree.
35
36 use strict;
37 use warnings;
38
39 use Getopt::Std;
40 use Cwd;
41 use Cwd 'abs_path';
42 use File::Path qw/ remove_tree /;
43 use File::Temp qw/ tempdir /;
44
45 $| = 1;
46
47 our ( $opt_d, $opt_n, $opt_r, $opt_t, $opt_v, $opt_x );
48 our $source_dir;
49 our $target_dir;
50 our $update_dir;
51 our $backup_dir;
52
53 our $tempdir = tempdir( CLEANUP => 1 );
54 my $current = getcwd;
55 my $working = $current;
56
57 our $generated_by = "generated by: ncu2openbsd";
58
59 our %setup_dir = qw(
60   lib/libcurses         ncurses
61   lib/libform           form
62   lib/libmenu           menu
63   lib/libpanel          panel
64   usr.bin/infocmp       progs
65   usr.bin/tabs          progs
66   usr.bin/tic           progs
67   usr.bin/toe           progs
68   usr.bin/tput          progs
69   usr.bin/tset          progs
70   share/termtypes       misc
71 );
72
73 our %generated = qw(
74   codes.c 1
75   comp_captab.c         1
76   comp_userdefs.c       1
77   expanded.c            1
78   fallback.c            1
79   init_keytry.h         1
80   keys.list             1
81   lib_gen.c             1
82   lib_keyname.c         1
83   make_hash             1
84   make_keys             1
85   names.c               1
86   termsort.c            1
87   unctrl.c              1
88 );
89
90 our %definitions = qw(
91   CAPTOINFO             captoinfo
92   DATADIR               /usr/share
93   INFOCMP               infocmp
94   INFOTOCAP             infotocap
95   NCURSES_MAJOR         5
96   NCURSES_MINOR         7
97   NCURSES_OSPEED        int
98   NCURSES_PATCH         20081102
99   TERMINFO              /usr/share/terminfo
100   TIC                   tic
101   TOE                   toe
102   TPUT                  tput
103   TSET                  tset
104 );
105
106 sub patchdate() {
107     return $definitions{"NCURSES_PATCH"};
108 }
109
110 sub failed($) {
111     chdir $current;
112     printf STDERR "? %s\n", $_[0];
113     exit;
114 }
115
116 sub verbose($) {
117     my $text = shift;
118     printf "%s\n", $text if ($opt_v);
119 }
120
121 sub read_file($) {
122     my $name = shift;
123     open( my $fp, $name ) || &failed("cannot open $name");
124     my (@input) = <$fp>;
125     chomp @input;
126     close($fp);
127     return @input;
128 }
129
130 sub read_dir($) {
131     my $path = shift;
132     my @result;
133     if ( opendir( my $dh, $path ) ) {
134         my @data = sort readdir($dh);
135         closedir $dh;
136         for my $d ( 0 .. $#data ) {
137             next if ( $data[$d] =~ /^\.(\.)?$/ );
138             next if ( -l $path . "/" . $data[$d] );
139             $result[ $#result + 1 ] = $data[$d];
140         }
141     }
142     return @result;
143 }
144
145 sub rename_dir($$) {
146     my $src = shift;
147     my $dst = shift;
148     printf "%% mv %s -> %s\n", $src, $dst if ($opt_v);
149     rename $src, $dst unless ($opt_n);
150 }
151
152 sub check_sourcedir($) {
153     my $path = shift;
154     &failed("not a directory: $path") unless ( -d $path );
155     my $full = abs_path($path);
156     chdir $full;
157     &failed("not an ncurses source-tree: $path")
158       unless ( -f "NEWS" and -f "dist.mk" );
159     $source_dir = $full;
160 }
161
162 sub unpack($) {
163     my $path    = shift;
164     my $full    = abs_path($path);
165     my $command = "";
166     if ( $path =~ /\.tgz$/ or $path =~ /\.tar\.gz$/ ) {
167         $command = "tar xzf %s";
168     }
169     elsif ( $path =~ /\.zip$/ ) {
170         $command = "unzip -q %s";
171     }
172     else {
173         &failed("not a gzip'd tarball or zip-file: $path");
174     }
175     chdir $tempdir;
176     system( sprintf( $command, $full ) );
177
178     # there should be exactly one subdirectory -- the source-tree
179     my @data = &read_dir(".");
180     &failed("found no subdirectories of $path") if ( $#data < 0 );
181     &failed( "too many subdirectories: " . $data[0] . " vs " . $data[1] )
182       if ( $#data > 0 );
183     &check_sourcedir( $data[0] );
184 }
185
186 sub remove_dir($) {
187     my $tree = shift;
188     if ( -d $tree ) {
189         printf "%% rm -rf %s\n", $tree if ($opt_v);
190         remove_tree( $tree, $opt_v ? 1 : 0, 1 ) unless ($opt_n);
191     }
192 }
193
194 sub copy_CVS($) {
195     my $leaf    = shift;
196     my $src     = $target_dir . $leaf . "/CVS";
197     my $dst     = $update_dir . $leaf . "/CVS";
198     my $verbose = $opt_v ? "v" : "";
199     if ( -d $src and !-d $dst ) {
200         my $mid = $update_dir . $leaf;
201         mkdir $mid unless ( -d $mid );
202         mkdir $dst unless ( -d $dst );
203         system("cp -a$verbose $src/* $dst/");
204     }
205 }
206
207 sub is_tic_code($) {
208     my $item   = shift;
209     my $result = 0;
210     $result = 1
211       if (
212         $item =~ /^(capconvert
213                    |tic
214                    |dump
215                    |progs
216                    |termsort
217                    |transform
218                    |MKtermsort)/x
219       );
220     return $result;
221 }
222
223 sub is_ident($$) {
224     my $name = shift;
225     my $text = shift;
226     my $code = 0;
227     $code = 1 if ( $text =~ /\$$name:.*\$/ );
228     return $code;
229 }
230
231 # We "could", filter out differences with ident's using the diff -I option,
232 # but in practice, that is cumbersome.
233 sub munge_ident($) {
234     my $target = shift;
235     my $source = $target;
236     $source =~ s/\.update\b//;
237     &failed("bug at $source") if ( $source eq $target );
238     return unless ( -f $source );
239     my @source = &read_file($source);
240     my @target = &read_file($target);
241     my $old_id = "";
242     my $gap_id = 0;
243     my $new_id = "";
244     my $skipit = -1;
245
246     for my $n ( 0 .. $#source ) {
247         if ( &is_ident( "OpenBSD", $source[$n] ) ) {
248             $old_id = $source[$n];
249             $skipit = $n + 1;
250         }
251         elsif ( &is_ident( "Id", $source[$n] ) ) {
252             $new_id = $source[$n];
253             last;
254         }
255         elsif ( $n == $skipit ) {
256             $source[$n] =~ s/\s+$//;
257             if ( $source[$n] eq "" ) {
258                 $gap_id = $source[$n];
259             }
260             elsif ( $source[$n] eq '.\"' ) {
261                 $gap_id = $source[$n];
262             }
263         }
264     }
265     if ( $old_id ne "" ) {
266         my @update;
267         my $tables = &uses_tables($target);
268         $update[ $#update + 1 ] = $target[0] if ($tables);
269         $update[ $#update + 1 ] = $old_id;
270         $update[ $#update + 1 ] = $gap_id unless ( $gap_id eq 0 );
271         for my $n ( $tables .. $#target ) {
272             if ( &is_ident( "Id", $target[$n] ) ) {
273                 $update[ $#update + 1 ] = $new_id;
274             }
275             else {
276                 $update[ $#update + 1 ] = $target[$n];
277             }
278         }
279         system("chmod u+w $target");
280         if ( open my $fp, ">", $target ) {
281             for my $n ( 0 .. $#update ) {
282                 printf $fp "%s\n", $update[$n];
283             }
284             close $fp;
285             system("chmod u-w $target");
286         }
287     }
288 }
289
290 # ncurses manual pages provide for renaming the utilities, normally as part of
291 # the scripts provided in its sources.  OpenBSD developers do not use those.
292 sub munge_docs($) {
293     my $path = shift;
294     my @data = &read_file($path);
295     my $done = 0;
296     for my $n ( 0 .. $#data ) {
297         my $text = $data[$n];
298         $text =~ s/\b1M\b/1/g;
299         $text =~ s/\b3X\b/3/g;
300         $text =~ s/\bcurs_(term(info|cap)\s*3\b)/$1/g;
301         $text =~ s/(\\fB)curs_(term(info|cap)\\f[RP]\(3\))/$1$2/g;
302         my $left = "";
303         while ( $text =~ /@[[:alnum:]_]+@/ ) {
304             my $next = index( $text, "@" );
305             last if ( $next < 0 );
306             $left .= substr( $text, 0, $next++ );
307             $text = substr( $text, $next );
308             $next = index( $text, "@" );
309             last if ( $next < 0 );
310             my $word = substr( $text, 0, $next );
311             if ( $word =~ /^[[:alnum:]_]+/ ) {
312
313                 if ( $definitions{$word} ) {
314                     $word = $definitions{$word};
315                 }
316                 else {
317                     $word = "?";
318                 }
319                 $left .= $word;
320                 $text = substr( $text, $next + 1 );
321             }
322             else {
323                 &failed("unexpected definition @$word@");
324             }
325         }
326         $text = $left . $text;
327         if ( $text ne $data[$n] ) {
328             $done++;
329             $data[$n] = $text;
330         }
331     }
332     if ($done) {
333         system("chmod u+w $path");
334         if ( open my $fp, ">", $path ) {
335             for my $n ( 0 .. $#data ) {
336                 printf $fp "%s\n", $data[$n];
337             }
338             close $fp;
339             system("chmod u-w $path");
340         }
341     }
342 }
343
344 sub copy_file($$) {
345     my $src     = shift;
346     my $dst     = shift;
347     my $verbose = $opt_v ? "v" : "";
348     if ( -d $dst ) {
349         my $leaf = $src;
350         $leaf =~ s,^.*/,,;
351         $dst .= "/" . $leaf;
352     }
353     system("chmod u+w $dst") if ( -f $dst );
354     system("cp -a$verbose $src $dst");
355     &munge_ident($dst);
356 }
357
358 sub copy_code($) {
359     my $src = shift;
360     my $dst = shift;
361     &copy_CVS( substr( $dst, length($update_dir) ) );
362     printf ".. copying files for $dst\n";
363     my @data = &read_dir($src);
364     printf ".. %d entries\n", $#data + 1;
365     my $verbose = $opt_v ? "v" : "";
366     for my $d ( 0 .. $#data ) {
367         my $item     = $data[$d];
368         my $src_item = $src . "/" . $item;
369         next if ( -d $src_item );
370         next if ( -l $src_item );
371         next if ( $item =~ /^\.(\.)?$/ );
372         next if ( $item =~ /\.(bak|in|log|status)$/ );
373         next if ( $item =~ /^llib-/ );
374         next if ( $item =~ /^modules/ );
375         next if ( $item =~ /^[fm]_trace\.c/ and not $opt_t );
376         next
377           if ( $item =~ /^Makefile/ and index( $update_dir, "/share/" ) < 0 );
378         next if ( $item =~ /^README/ );
379         next if ( $item eq "headers" );
380         next if ( $generated{$item} );
381         next if ( $item eq "link_test.c" );
382
383         if ( index( $dst, "/usr.bin/" ) >= 0 ) {
384             next if ( $item =~ /^(clear)/ );    # OpenBSD uses "tput clear"
385             my $prog = $dst;
386             $prog =~ s%^.*/%%;
387             $prog =~ s/(update|backup)//;
388             $prog .= "c";
389             if ( $dst =~ /infocmp/ ) {
390                 next if ( $item ne $prog );
391             }
392             elsif ( $dst =~ /tabs/ ) {
393                 next if ( $item ne $prog );
394             }
395             elsif ( $dst =~ /tic/ ) {
396                 next if ( &is_tic_code($item) == 0 );
397             }
398             elsif ( $dst =~ /toe/ ) {
399                 next if ( $item ne $prog );
400             }
401             elsif ( $dst =~ /tput/ ) {
402                 next if ( $item ne $prog );
403             }
404             elsif ( $dst =~ /tset/ ) {
405                 next if ( $item ne $prog );
406             }
407             else {
408                 next;
409             }
410         }
411         system( sprintf( "cp -a$verbose %s %s/%s", $src_item, $dst, $item ) );
412         &munge_ident("$dst/$item");
413     }
414 }
415
416 # Checking if nroff supports tables is a long-obsolete issue, and is not really
417 # necessary, except to match OpenBSD's source-tree.
418 sub uses_tables($) {
419     my $docs = shift;
420     my @docs = &read_file($docs);
421     my $code = 0;
422     for my $n ( 0 .. $#docs ) {
423         if ( $docs[$n] =~ /^[.']\\"\s+t\b.*/ ) {
424             $code = 1;
425             last;
426         }
427         elsif ( $docs[$n] =~ /^\./ ) {
428             last;
429         }
430     }
431     return $code;
432 }
433
434 sub copy_1doc($$) {
435     my $docs = shift;
436     my $src  = "$source_dir/man/$docs";
437     my $dst  = "$update_dir/$docs";
438     $src .= "m" if ( -f "${src}m" );
439     $dst =~ s/x$//;
440     if ( $dst =~ /\.3/ ) {
441         $dst =~ s/\bncurses/curses/ if ( $dst =~ /ncurses\./ );
442         $dst =~ s/\bcurs_//         if ( $dst =~ /_term(cap|info)\./ );
443     }
444     &copy_file( $src, $dst );
445     &munge_docs($dst);
446 }
447
448 sub copy_docs($) {
449     my $docs = shift;
450     if ( index( $update_dir, "/usr.bin/" ) >= 0 ) {
451         &copy_1doc( $docs . ".1" );
452         if ( $docs eq "tic" ) {
453             &copy_1doc("captoinfo.1");
454             &copy_1doc("infotocap.1");
455         }
456     }
457     else {
458         my @docs = &read_dir("$source_dir/man");
459         if ( $docs eq "curses" ) {
460             for my $n ( 0 .. $#docs ) {
461                 next if ( $docs[$n] eq "Makefile" );
462                 next if ( $docs[$n] eq "make_sed.sh" );
463                 next if ( $docs[$n] eq "man_db.renames" );
464                 next if ( $docs[$n] eq "manlinks.sed" );
465                 next if ( $docs[$n] =~ /\.(1|head|tail|in)/ );
466                 next if ( $docs[$n] =~ /^(form|menu|mitem|panel)/ );
467                 &copy_1doc( $docs[$n] );
468             }
469         }
470         elsif ( $docs eq "form" ) {
471             for my $n ( 0 .. $#docs ) {
472                 next unless ( $docs[$n] =~ /^form/ );
473                 &copy_1doc( $docs[$n] );
474             }
475         }
476         elsif ( $docs eq "menu" ) {
477             for my $n ( 0 .. $#docs ) {
478                 next unless ( $docs[$n] =~ /^(menu|mitem)/ );
479                 &copy_1doc( $docs[$n] );
480             }
481         }
482         elsif ( $docs eq "panel" ) {
483             for my $n ( 0 .. $#docs ) {
484                 next unless ( $docs[$n] =~ /^panel/ );
485                 &copy_1doc( $docs[$n] );
486             }
487         }
488     }
489 }
490
491 sub setup_dir($) {
492     my $dst = shift;
493     &failed("no definition for $dst")
494       unless ( defined $setup_dir{$dst} or $opt_r );
495     $target_dir = sprintf( "%s/%s", $opt_d, $dst );
496     $update_dir = $target_dir . ".update";
497     $backup_dir = $target_dir . ".backup";
498     my $result = 0;
499     if ($opt_r) {
500         &remove_dir($update_dir);
501         if ( $target_dir =~ /\/(tabs|toe)$/ ) {
502             &remove_dir($target_dir);
503         }
504         elsif ( -d $backup_dir ) {
505             &remove_dir($target_dir);
506             &rename_dir( $backup_dir, $target_dir );
507         }
508     }
509     else {
510         &remove_dir($update_dir);
511         mkdir $update_dir;
512
513         # reuse the shared-library version, assuming ABI=5 would involve at
514         # most a minor-version bump.
515         &copy_file( "$target_dir/shlib_version", $update_dir )
516           if ( $dst =~ /^lib\// );
517         &copy_code( $source_dir . "/" . $setup_dir{$dst}, $update_dir )
518           unless ( $setup_dir{$dst} eq "misc" );
519         $result = 1;
520     }
521     return $result;
522 }
523
524 sub do_build($) {
525     my $command = shift;
526     printf "%% %s\n", $command if ($opt_v);
527     system($command);
528 }
529
530 sub finish_dir() {
531     printf "** $target_dir\n";
532     system("diff -Naurb $target_dir $update_dir | diffstat -n 30")
533       if ( -d $target_dir );
534     if ($opt_n) {
535         &do_build("cd $update_dir && make -n") if ($opt_x);
536     }
537     else {
538         if ( -d $backup_dir ) {
539             printf STDERR "? backup directory exists: %s\n", $backup_dir;
540         }
541         else {
542             &rename_dir( $target_dir, $backup_dir );
543             &rename_dir( $update_dir, $target_dir );
544         }
545         &do_build("cd $target_dir && make") if ($opt_x);
546     }
547 }
548
549 ################################################################################
550
551 sub only_c_files($) {
552     my @data = @{ $_[0] };
553     my %data;
554     for my $n ( 0 .. $#data ) {
555         my $text = $data[$n];
556         $data{$text}++ if ( $text =~ /\.c$/ );
557     }
558     return sort keys %data;
559 }
560
561 sub makefile_list($$$) {
562     my @data = @{ $_[0] };
563     my $name = $_[1];
564     my $skip = $_[2];
565     my %data;
566     my $state = 0;
567     for my $n ( 0 .. $#data ) {
568         my $text = $data[$n];
569         $text =~ s/^\s+//;
570         next if ( index( $text, $skip ) == 0 );
571         $text =~ s/\s+=/=/;
572         $text =~ s/=\s+/=/;
573         $text =~ s/\s*\\//;
574         $state = 1 if ( $text =~ /^${name}=/ );
575         next unless ( $state == 1 );
576
577         if ( index( $text, "(trace)" ) >= 0 and not $opt_t ) {
578             next unless ( $text =~ /\b(lib_trace|visbuf)\.c$/ );
579         }
580         if ( not $opt_t ) {
581             next if ( $text =~ /\b[fm]_trace\.c$/ );
582         }
583         $text =~ s/^.*=//;
584         $text =~ s/\$o/.o/g;
585         $text =~ s/^.*\///;
586         next           if ( $text eq "link_test.c" );
587         next           if ( $text eq "mf_common.h" );
588         next           if ( $text eq "transform.h" );
589         $data{$text}++ if ( $text ne "" );
590         last           if ( $data[$n] !~ /\\$/ );
591     }
592     return sort keys %data;
593 }
594
595 sub manpage_list($) {
596     my $path = shift;
597     my @data = &read_dir($path);
598     my %data;
599     for my $n ( 0 .. $#data ) {
600         my $text = $data[$n];
601         $data{$text}++ if ( $text =~ /\.\d$/ );
602     }
603     return sort keys %data;
604 }
605
606 sub columns_of($) {
607     my $string = shift;
608     my $result = 0;
609     for my $n ( 0 .. length($string) - 1 ) {
610         my $c = substr( $string, $n, 1 );
611         if ( $c eq "\t" ) {
612             $result |= 7;
613             $result++;
614         }
615         elsif ( $c eq "\n" ) {
616             $result = 0;
617         }
618         else {
619             ++$result;
620         }
621     }
622     return $result;
623 }
624
625 sub format_list($$) {
626     my $name = $_[0];
627     my @data = @{ $_[1] };
628     my $keep = ( defined $_[2] ) ? 1 : 0;
629     my $base;
630     my $fill;
631     if ( length($name) >= 9 ) {
632         $fill = " ";
633         $base = length($name) + 1;
634     }
635     else {
636         $base = 9;
637         $fill = "\t";
638     }
639     my $result = sprintf( "%s%s", $name, $fill );
640     if ( $keep == 0 ) {
641         my %data;
642         for my $n ( 0 .. $#data ) {
643             $data{ $data[$n] } = 1 if ( defined $data[$n] );
644         }
645         @data = sort keys %data;
646     }
647     for my $n ( 0 .. $#data ) {
648         my $data = $data[$n];
649         my $col  = &columns_of($result);
650         my $add  = 1 + length($data);
651         if ( ( $col + $add ) > 76 ) {
652             $result .= " " if ( $col > $base );
653             $base = 9;
654             $fill = "\t";
655             $result .= "\\\n" . $fill . $data;
656         }
657         else {
658             $result .= " " if ( $col > $base );
659             $result .= $data;
660         }
661     }
662     return $result;
663 }
664
665 ################################################################################
666
667 sub compare_makefiles($) {
668     if ($opt_v) {
669         my $newfile = shift;
670         my $bakfile =
671           ( -d $backup_dir ? $backup_dir : $target_dir ) . "/Makefile";
672         system("diff -u $bakfile $newfile") if ( -f $bakfile );
673     }
674 }
675
676 # The curses makefile has to build build-time utilities and generate source.
677 sub gen_1st_makefile() {
678     my $libname = "curses";
679     my $oldfile = "$source_dir/n$libname/Makefile";
680     my @oldfile = &read_file($oldfile);
681
682     my $newfile = "$update_dir/Makefile";
683     open( my $fp, ">", $newfile ) || &failed("cannot open $newfile");
684     my @subdirs = (
685         '${.CURDIR}/base', '${.CURDIR}/tinfo',
686         '${.CURDIR}/tty',  '${.CURDIR}/widechar'
687     );
688     $subdirs[ $#subdirs + 1 ] = '${.CURDIR}/trace' if ($opt_t);
689     printf $fp <<EOF;
690 # $generated_by
691
692 LIB=    $libname
693
694 # Uncomment this to enable tracing in libcurses
695 #CURSESTRACE=-DTRACE
696
697 # This is used to compile terminal info directly into the library
698 FALLBACK_LIST=
699
700 # XXX - should be defined elsewhere
701 AWK?=   /usr/bin/awk
702
703 # Search in subdirs
704 EOF
705     printf $fp "%s\n", &format_list( ".PATH:", \@subdirs );
706
707     my @autosrc = &makefile_list( \@oldfile, "AUTO_SRC", "?" );
708     my @auto_cc = &only_c_files( \@autosrc );
709     printf $fp "%s\n", &format_list( "SRCS=", \@auto_cc );
710
711     my @sources = &makefile_list( \@oldfile, "C_SRC", "./" );
712     printf $fp "%s\n", &format_list( "SRCS+=", \@sources );
713
714     printf $fp <<EOF;
715
716 HOSTCFLAGS?=    \${CFLAGS}
717 HOSTLDFLAGS?=   \${LDFLAGS}
718 HOSTCFLAGS+=    -I. -I\${.CURDIR} \${CURSESTRACE}
719 CFLAGS+=        -I. -I\${.CURDIR} \${CURSESTRACE} -D_XOPEN_SOURCE_EXTENDED -DNDEBUG
720
721 EOF
722     my @manpages = &manpage_list($update_dir);
723     printf $fp "%s\n", &format_list( "MAN=", \@manpages );
724
725     $autosrc[ $#autosrc++ ] = "make_hash";
726     $autosrc[ $#autosrc++ ] = "make_keys";
727     printf $fp "%s\n", &format_list( "GENERATED=", \@autosrc );
728     printf $fp <<EOF;
729
730 CAPLIST = \${.CURDIR}/Caps
731 USE_BIG_STRINGS = 1
732
733 CLEANFILES+= \${GENERATED}
734
735 BUILDFIRST = \${GENERATED}
736
737 includes:
738         \@cmp -s \${DESTDIR}/usr/include/ncurses.h \${.CURDIR}/curses.h || \\
739           \${INSTALL} \${INSTALL_COPY} -m 444 -o \$(BINOWN) -g \$(BINGRP) \\
740           \${.CURDIR}/curses.h \${DESTDIR}/usr/include/ncurses.h
741         \@cd \${.CURDIR}; for i in ncurses_dll.h unctrl.h term.h termcap.h; do \\
742           cmp -s \$\$i \${DESTDIR}/usr/include/\$\$i || \\
743           \${INSTALL} \${INSTALL_COPY} -m 444 -o \$(BINOWN) -g \$(BINGRP) \$\$i \\
744           \${DESTDIR}/usr/include; done
745
746 keys.list: \${.CURDIR}/tinfo/MKkeys_list.sh
747         sh \${.CURDIR}/tinfo/MKkeys_list.sh \${.CURDIR}/Caps | sort > \${.TARGET}
748
749 fallback.c: \${.CURDIR}/tinfo/MKfallback.sh
750         sh \${.CURDIR}/tinfo/MKfallback.sh /usr/share/terminfo \${.CURDIR}/../../share/termtypes/termtypes.master \$(FALLBACK_LIST) > \${.TARGET}
751
752 lib_gen.c: \${.CURDIR}/base/MKlib_gen.sh
753         sh \${.CURDIR}/base/MKlib_gen.sh "\${CC} -E -P -I\${.CURDIR}" \\
754                 "\${AWK}" generated < \${.CURDIR}/curses.h > lib_gen.c
755
756 init_keytry.h: make_keys keys.list
757         ./make_keys keys.list > \${.TARGET}
758
759 make_keys: \${.CURDIR}/tinfo/make_keys.c \${.CURDIR}/curses.priv.h names.c
760         \${HOSTCC} \${LDSTATIC} \${HOSTCFLAGS} \${HOSTLDFLAGS} \\
761                 -o \${.TARGET} \${.CURDIR}/tinfo/make_keys.c \${LDADD}
762 EOF
763
764     if ( &patchdate >= 20090808 ) {
765         printf $fp <<EOF;
766 make_hash:      \${.CURDIR}/tinfo/make_hash.c \\
767                 \${.CURDIR}/curses.priv.h \\
768                 \${.CURDIR}/hashsize.h
769         \${HOSTCC} \${LDSTATIC} \${HOSTCFLAGS} -DMAIN_PROGRAM \${HOSTLDFLAGS} \\
770                 -o \${.TARGET} \${.CURDIR}/tinfo/make_hash.c \${LDADD}
771 EOF
772     }
773     else {
774         printf $fp <<EOF;
775 make_hash: \${.CURDIR}/tinfo/comp_hash.c \\
776                 \${.CURDIR}/curses.priv.h \\
777                 \${.CURDIR}/hashsize.h
778         \${HOSTCC} \${LDSTATIC} \${HOSTCFLAGS} -DMAIN_PROGRAM \${HOSTLDFLAGS} \\
779                 -o \${.TARGET} \${.CURDIR}/tinfo/comp_hash.c \${LDADD}
780 EOF
781     }
782
783     if ( &patchdate >= 20190309 ) {
784         printf $fp <<EOF;
785 CAPLIST += \${.CURDIR}/Caps-ncurses
786
787 comp_userdefs.c: make_hash \\
788                 \${.CURDIR}/hashsize.h \\
789                 \${.CURDIR}/tinfo/MKuserdefs.sh
790         sh \${.CURDIR}/tinfo/MKuserdefs.sh \${AWK} \${USE_BIG_STRINGS} \${CAPLIST} > \${.TARGET}
791 EOF
792     }
793     printf $fp <<EOF;
794
795 expanded.c: \${.CURDIR}/term.h \${.CURDIR}/curses.priv.h \\
796                 \${.CURDIR}/ncurses_cfg.h \${.CURDIR}/tty/MKexpanded.sh
797         sh \${.CURDIR}/tty/MKexpanded.sh "\${CC} -E -P" \${CPPFLAGS} > \${.TARGET}
798
799 comp_captab.c: make_hash
800         sh \${.CURDIR}/tinfo/MKcaptab.sh \${AWK} \${USE_BIG_STRINGS} \\
801                 \${.CURDIR}/tinfo/MKcaptab.awk \${CAPLIST} > \${.TARGET}
802
803 lib_keyname.c: keys.list \${.CURDIR}/base/MKkeyname.awk
804         \${AWK} -f \${.CURDIR}/base/MKkeyname.awk \\
805                 bigstrings=\${USE_BIG_STRINGS} \\
806                 keys.list > \${.TARGET}
807
808 names.c: \${.CURDIR}/tinfo/MKnames.awk
809         \${AWK} -f \${.CURDIR}/tinfo/MKnames.awk \\
810                 bigstrings=\${USE_BIG_STRINGS} \\
811                 \${CAPLIST} > \${.TARGET}
812 codes.c: \${.CURDIR}/tinfo/MKcodes.awk
813         \${AWK} -f \${.CURDIR}/tinfo/MKcodes.awk \\
814                 bigstrings=\${USE_BIG_STRINGS} \\
815                 \${CAPLIST} > \${.TARGET}
816
817 unctrl.c: \${.CURDIR}/base/MKunctrl.awk
818         echo | \${AWK} -f \${.CURDIR}/base/MKunctrl.awk bigstrings=1 > \${.TARGET}
819
820 .include <bsd.own.mk>
821
822 # Link libtermlib, libtermcap to libcurses so we don't break people's Makefiles
823 afterinstall:
824         -cd \${DESTDIR}\${LIBDIR}; \\
825         for i in \${_LIBS}; do \\
826             ln -f \$\$i `echo \$\$i | sed 's/curses/termlib/'`; \\
827             ln -f \$\$i `echo \$\$i | sed 's/curses/termcap/'`; \\
828             ln -f \$\$i `echo \$\$i | sed 's/curses/ncurses/'`; \\
829             ln -f \$\$i `echo \$\$i | sed 's/curses/ncursesw/'`; \\
830         done
831
832 .include <bsd.lib.mk>
833 EOF
834     close $fp;
835     &compare_makefiles($newfile);
836 }
837
838 sub gen_lib_makefile($) {
839     my $libname = shift;
840     my $oldfile = "$source_dir/$libname/Makefile";
841     my @oldfile = &read_file($oldfile);
842
843     # in ncurses, header-files are quasi-generated, because the original
844     # header file for form/menu/panel lives in the source-directory, but is
845     # copied to the include-directory with "make sources".
846     my @headers = &makefile_list( \@oldfile, "AUTO_SRC", "?" );
847
848     # The C source is more straightforward.
849     my @sources = &makefile_list( \@oldfile, "C_SRC", "?" );
850     my $newfile = "$update_dir/Makefile";
851     open( my $fp, ">", $newfile ) || &failed("cannot open $newfile");
852     printf $fp <<EOF;
853 # $generated_by
854
855 LIB=    $libname
856 EOF
857
858     printf $fp "%s\n", &format_list( "SRCS=", \@sources );
859     printf $fp "%s\n", &format_list( "HDRS=", \@headers );
860     my $includes = '-I${.CURDIR}/../libcurses';
861     $includes .= ' -I${.CURDIR}/../libmenu' if ( $libname eq "form" );
862     printf $fp <<EOF;
863 CFLAGS+=$includes -D_XOPEN_SOURCE_EXTENDED -DNDEBUG
864 EOF
865     my @manpages = &manpage_list($update_dir);
866     printf $fp "%s\n", &format_list( "MAN=", \@manpages );
867     printf $fp <<EOF;
868
869 includes:
870         \@cd \$\{.CURDIR}; for i in \$\{HDRS}; do \\
871           cmp -s \$\$i \${DESTDIR}/usr/include/\$\$i || \\
872           \${INSTALL} \${INSTALL_COPY} -m 444 -o \$(BINOWN) -g \$(BINGRP) \$\$i \\
873           \${DESTDIR}/usr/include; done
874
875 .include <bsd.own.mk>
876
877 afterinstall:
878         -cd \${DESTDIR}\${LIBDIR}; \\
879         for i in \${_LIBS}; do \\
880             ln -f \$\$i `echo \$\$i | sed 's/${libname}/${libname}w/'`; \\
881         done
882
883 .include <bsd.lib.mk>
884 EOF
885     close $fp;
886     &compare_makefiles($newfile);
887 }
888
889 sub gen_bin_makefile($) {
890     my $binname = shift;
891     my $oldfile = "$source_dir/progs/Makefile";
892     my @oldfile = &read_file($oldfile);
893     my $newfile = "$update_dir/Makefile";
894
895     open( my $fp, ">", $newfile ) || &failed("cannot open $newfile");
896     my @sources = ("$binname.c");
897     my @links   = ();
898     my @autosrc = &makefile_list( \@oldfile, "AUTO_SRC", "?" );
899
900     my $tput_ver       = 0;
901     my $use_dump_entry = 0;
902     my $use_termsort   = 0;
903     my $use_tparm_type = 0;
904     my $use_transform  = 0;
905
906     $use_dump_entry = 1 if ( $binname eq "infocmp" or $binname eq "tic" );
907     $use_termsort   = 1 if ( $use_dump_entry       or $binname eq "tput" );
908
909     if ( &patchdate >= 20090314 ) {
910         $use_transform = 1 if ( $binname =~ /^(tic|tput|tset)/ );
911     }
912     if ( &patchdate >= 20140521 ) {
913         $use_tparm_type = 1 if ( $binname =~ /^(tic|tput)$/ );
914     }
915     if ( &patchdate >= 20160806 ) {
916         $tput_ver = &patchdate;
917     }
918
919     $sources[ ++$#sources ] = "dump_entry.c" if ($use_dump_entry);
920     $sources[ ++$#sources ] = "tparm_type.c" if ($use_tparm_type);
921     $sources[ ++$#sources ] = "transform.c"  if ($use_transform);
922
923     $autosrc[ ++$#autosrc ] = "termsort.c" if ($use_termsort);
924
925     # transform.h also is generated, but OpenBSD checked-in a copy
926
927     if ( $binname eq "tic" ) {
928         $links[ ++$#links ] = "captoinfo";
929         $links[ ++$#links ] = "infotocap";
930     }
931     elsif ( $binname eq "tabs" ) {
932         $sources[ ++$#sources ] = "tty_settings.c" if ( $tput_ver >= 20161224 );
933     }
934     elsif ( $binname eq "tput" ) {
935         $sources[ ++$#sources ] = "clear_cmd.c"    if ( $tput_ver >= 20161022 );
936         $sources[ ++$#sources ] = "reset_cmd.c"    if ( $tput_ver >= 20160806 );
937         $sources[ ++$#sources ] = "tty_settings.c" if ( $tput_ver >= 20161224 );
938         $links[ ++$#links ]     = "clear";
939     }
940     elsif ( $binname eq "tset" ) {
941         $sources[ ++$#sources ] = "reset_cmd.c"    if ( $tput_ver >= 20160806 );
942         $sources[ ++$#sources ] = "tty_settings.c" if ( $tput_ver >= 20161224 );
943         $links[ ++$#links ]     = "reset";
944     }
945
946     printf $fp <<EOF;
947 # $generated_by
948
949 PROG=   $binname
950 EOF
951     printf $fp "%s\n", &format_list( "SRCS=", \@sources );
952     printf $fp <<EOF;
953 CURSES= \${.CURDIR}/../../lib/libcurses
954 DPADD=  \${LIBCURSES}
955 LDADD=  -L\${CURSES} -lcurses\t# in-tree link to add _nc_strict_bsd, etc
956 EOF
957     if ( $#links >= 0 ) {
958         my @bin_links;
959         for my $n ( 0 .. $#links ) {
960             $bin_links[ ++$#bin_links ] = '${BINDIR}/' . $binname;
961             $bin_links[ ++$#bin_links ] = '${BINDIR}/' . $links[$n];
962         }
963         printf $fp "%s\n", &format_list( "LINKS=", \@bin_links, 1 );
964     }
965     my $ticfix = '${.CURDIR}/';
966     if ( $binname eq "tic" ) {
967         printf $fp <<EOF;
968 CFLAGS+= -I\${CURSES} -I\${.CURDIR} -I.
969 EOF
970     }
971     else {
972         $ticfix = '${TIC}/';
973         printf $fp <<EOF;
974 TIC= \${.CURDIR}/../tic
975 CFLAGS+= -I\${CURSES} -I\${TIC} -I\${.CURDIR} -I.
976 .PATH:  \${TIC}
977 EOF
978     }
979     printf $fp "%s\n", &format_list( "CLEANFILES+=", \@autosrc );
980     if ($use_dump_entry) {
981         printf $fp <<EOF;
982
983 dump_entry.o: termsort.c
984 EOF
985     }
986     if ($use_termsort) {
987         printf $fp <<EOF;
988
989 termsort.c: ${ticfix}MKtermsort.sh
990         sh ${ticfix}MKtermsort.sh awk \${CURSES}/Caps > \${.TARGET}
991 EOF
992     }
993     printf $fp <<EOF;
994
995 .include <bsd.prog.mk>
996 EOF
997     close $fp;
998
999     &compare_makefiles($newfile);
1000 }
1001
1002 ################################################################################
1003
1004 sub setup_lib_libcurses() {
1005     if ( &setup_dir("lib/libcurses") ) {
1006         &copy_code( "$source_dir/ncurses/base",     "$update_dir/base" );
1007         &copy_code( "$source_dir/ncurses/tinfo",    "$update_dir/tinfo" );
1008         &copy_code( "$source_dir/ncurses/tty",      "$update_dir/tty" );
1009         &copy_code( "$source_dir/ncurses/widechar", "$update_dir/widechar" );
1010         &copy_file( "$source_dir/include/Caps",           $update_dir );
1011         &copy_file( "$source_dir/include/capdefaults.c",  $update_dir );
1012         &copy_file( "$source_dir/include/curses.h",       $update_dir );
1013         &copy_file( "$source_dir/include/hashed_db.h",    $update_dir );
1014         &copy_file( "$source_dir/include/hashsize.h",     $update_dir );
1015         &copy_file( "$source_dir/include/nc_alloc.h",     $update_dir );
1016         &copy_file( "$source_dir/include/nc_panel.h",     $update_dir );
1017         &copy_file( "$source_dir/include/nc_tparm.h",     $update_dir );
1018         &copy_file( "$source_dir/include/ncurses_cfg.h",  $update_dir );
1019         &copy_file( "$source_dir/include/ncurses_def.h",  $update_dir );
1020         &copy_file( "$source_dir/include/ncurses_dll.h",  $update_dir );
1021         &copy_file( "$source_dir/include/parametrized.h", $update_dir );
1022         &copy_file( "$source_dir/include/term.h",         $update_dir );
1023         &copy_file( "$source_dir/include/termcap.h",      $update_dir );
1024         &copy_file( "$source_dir/include/term_entry.h",   $update_dir );
1025         &copy_file( "$source_dir/include/tic.h",          $update_dir );
1026         &copy_file( "$source_dir/include/unctrl.h",       $update_dir );
1027         &copy_file( "$source_dir/man/terminfo.5",         $update_dir );
1028         &copy_docs("curses");
1029
1030         &verbose(".. work around a bug in /bin/sh in OpenBSD");
1031         system( "sed -i"
1032               . " -e 's,^shift,test \$# != 0 \\&\\& shift,'"
1033               . " $update_dir/tinfo/MKfallback.sh" );
1034
1035         # OpenBSD dropped support for sys/ttydev.h, without mentioning the
1036         # system version.  Just trim it.
1037         &verbose(".. work around mishandled sys/ttydef.h");
1038         system( "sed -i"
1039               . " -e '/__FreeBSD_version/s,|| defined(__OpenBSD__),,'"
1040               . " $update_dir/tinfo/lib_baudrate.c" );
1041
1042         if ($opt_t) {
1043             &copy_code( "$source_dir/ncurses/trace", "$update_dir/trace" );
1044         }
1045         else {
1046             &copy_file( "$source_dir/ncurses/trace/lib_trace.c", $update_dir );
1047             &copy_file( "$source_dir/ncurses/trace/visbuf.c",    $update_dir );
1048         }
1049         &copy_file( "$source_dir/include/nc_termios.h", $update_dir )
1050           if ( &patchdate >= 20110625 );
1051         &copy_file( "$source_dir/include/nc_string.h", $update_dir )
1052           if ( &patchdate >= 20120222 );
1053         &copy_file( "$source_dir/include/nc_access.h", $update_dir )
1054           if ( &patchdate >= 20210626 );
1055         &copy_file( "$source_dir/include/Caps-ncurses", $update_dir )
1056           if ( &patchdate >= 20190302 );
1057         &gen_1st_makefile;
1058         &finish_dir;
1059     }
1060 }
1061
1062 sub setup_lib_libform() {
1063     if ( &setup_dir("lib/libform") ) {
1064         &copy_docs("form");
1065         &gen_lib_makefile("form");
1066         &finish_dir;
1067     }
1068 }
1069
1070 sub setup_lib_libmenu() {
1071     if ( &setup_dir("lib/libmenu") ) {
1072         &copy_docs("menu");
1073         &gen_lib_makefile("menu");
1074         &finish_dir;
1075     }
1076 }
1077
1078 sub setup_lib_libpanel() {
1079     if ( &setup_dir("lib/libpanel") ) {
1080         &copy_docs("panel");
1081         &gen_lib_makefile("panel");
1082         &finish_dir;
1083     }
1084 }
1085
1086 sub setup_bin_infocmp() {
1087     if ( &setup_dir("usr.bin/infocmp") ) {
1088         &copy_docs("infocmp");
1089         &gen_bin_makefile("infocmp");
1090         &finish_dir;
1091     }
1092 }
1093
1094 sub setup_bin_tabs() {
1095     if ( &setup_dir("usr.bin/tabs") ) {
1096         &copy_docs("tabs");
1097         &gen_bin_makefile("tabs");
1098         &finish_dir;
1099     }
1100 }
1101
1102 sub setup_bin_tic() {
1103     if ( &setup_dir("usr.bin/tic") ) {
1104         if ( &patchdate >= 20140521 ) {
1105             &copy_file( "$source_dir/progs/tparm_type.c", $update_dir );
1106             &copy_file( "$source_dir/progs/tparm_type.h", $update_dir );
1107         }
1108
1109         # shared files for tput/tset
1110         if ( &patchdate >= 20160806 ) {
1111             &copy_file( "$source_dir/progs/reset_cmd.c", $update_dir );
1112             &copy_file( "$source_dir/progs/reset_cmd.h", $update_dir );
1113         }
1114         if ( &patchdate >= 20161022 ) {
1115             &copy_file( "$source_dir/progs/clear_cmd.c", $update_dir );
1116             &copy_file( "$source_dir/progs/clear_cmd.h", $update_dir );
1117         }
1118         if ( &patchdate >= 20161224 ) {
1119             &copy_file( "$source_dir/progs/tty_settings.c", $update_dir );
1120             &copy_file( "$source_dir/progs/tty_settings.h", $update_dir );
1121         }
1122         &copy_docs("tic");
1123         &gen_bin_makefile("tic");
1124         &finish_dir;
1125     }
1126 }
1127
1128 sub setup_bin_toe() {
1129     if ( &setup_dir("usr.bin/toe") ) {
1130         &copy_docs("toe");
1131         &gen_bin_makefile("toe");
1132         &finish_dir;
1133     }
1134 }
1135
1136 sub setup_bin_tput() {
1137     if ( &setup_dir("usr.bin/tput") ) {
1138         &copy_docs("tput");
1139         &gen_bin_makefile("tput");
1140         &finish_dir;
1141     }
1142 }
1143
1144 sub setup_bin_tset() {
1145     if ( &setup_dir("usr.bin/tset") ) {
1146         &copy_docs("tset");
1147         &gen_bin_makefile("tset");
1148         &finish_dir;
1149     }
1150 }
1151
1152 sub setup_terminfo() {
1153     if ( &setup_dir("share/termtypes") ) {
1154         &copy_code( $target_dir, $update_dir );
1155         &copy_file( "$source_dir/misc/terminfo.src",
1156             "$update_dir/termtypes.master" );
1157
1158         # build the terminfo database using the in-tree tic.
1159         # This is always best practice, but for ncurses 6.2 in particular is
1160         # required.
1161         my $prog = abs_path("$target_dir/../../usr.bin/tic");
1162         my $libs = abs_path("$target_dir/../../lib/libcurses");
1163         if ( defined $prog and defined $libs ) {
1164             $prog .= "/tic";
1165             &verbose(".. changing makefile to use in-tree tic");
1166             system( "sed -i -E "
1167                   . "-e 's,(TIC=).*,\\1\t$prog,' "
1168                   . "-e 's,(\\\${TIC}),LD_LIBRARY_PATH=$libs \\1,' "
1169                   . "$update_dir/Makefile" );
1170         }
1171         &finish_dir;
1172     }
1173 }
1174
1175 sub configure_tree() {
1176     return if ( -f "ncurses/Makefile" );
1177     my @search = ( "/usr/share/terminfo", "/usr/local/share/terminfo" );
1178     my @prefix = ("./configure");
1179     $prefix[ ++$#prefix ] = "--with-abi-version=5"
1180       if ( &patchdate >= 20150502 );
1181     my @options = (
1182         "--with-ospeed=int",    #
1183         "--with-shared",        #
1184         "--without-normal",     #
1185         "--without-debug",      #
1186         "--with-terminfo-dirs=" . join( ':', @search ),    #
1187         "--without-ada",                                   #
1188         "--disable-hard-tabs",                             #
1189         "--enable-const",                                  #
1190         "--enable-getcap",                                 #
1191         "--enable-bsdpad",                                 #
1192         "--enable-signed-char",                            #
1193         "--enable-termcap",                                #
1194         "--enable-widec"
1195     );
1196     $options[ ++$#options ] = "--with-trace" if ($opt_t);
1197     $options[ ++$#options ] = "--enable-string-hacks"
1198       if ( &patchdate >= 20120225 );
1199     system( join( ' ', @prefix ) . ' ' . join( ' ', @options ) );
1200     &failed("problem with configuring") unless ( -f "ncurses/Makefile" );
1201
1202     system("make sources");
1203
1204     # OpenBSD developers edit the generated file and do not regen it when
1205     # doing upgrades.  This script reflects those edits.
1206     system( "sed -i" . " -E"
1207           . " -e '/TYPEOF_CHTYPE/s,int,long,'"
1208           . " -e '/USE_TERMCAP/d'"
1209           . " -e '/HAVE_LIB(FORM|MENU|PANEL)/s,^(.*)\$,/* \\1 */,'"
1210           . " -e 's/TERMPATH.*/PURE_TERMINFO 0/'"
1211           . " -e '/SYSTEM_NAME/s,\[0-9.\]+,,'"
1212           . " include/ncurses_cfg.h" );
1213 }
1214
1215 sub get_definitions() {
1216     my @data = &read_file("dist.mk");
1217     for my $n ( 0 .. $#data ) {
1218         my $text = $data[$n];
1219         $text =~ s/^\s*//;
1220         next unless ( $text =~ /^NCURSES.*=/ );
1221         $text =~ s/\s*=\s+/=/;
1222         my $name = $text;
1223         $name =~ s/=.*//;
1224         my $value = $text;
1225         $value =~ s/^[^=]*=//;
1226         $value =~ s/\s.*//;
1227         $definitions{$name} = $value;
1228     }
1229 }
1230
1231 sub setup_all_dirs() {
1232     printf "** %s all build-directories\n", $opt_r ? "removing" : "setting up";
1233     &get_definitions;
1234     &configure_tree unless ($opt_r);
1235     &setup_lib_libcurses;
1236     &setup_lib_libmenu;
1237     &setup_lib_libform;    # build after libmenu, for mf_common.h
1238     &setup_lib_libpanel;
1239     &setup_bin_tic;        # do this first, for shared headers
1240     &setup_bin_infocmp;
1241     &setup_bin_tabs if ( -f "$source_dir/progs/tabs.c" );
1242     &setup_bin_toe;
1243     &setup_bin_tput;
1244     &setup_bin_tset;
1245     &setup_terminfo;
1246 }
1247
1248 sub usage() {
1249     print <<EOF;
1250 Usage: ncu2openbsd [options] [sourcetree]
1251
1252 Options:
1253   -d DST   specify destination (default: /usr/src)
1254   -n       no-op, do not update destination
1255   -r       remove update, restore sources from ".orig"
1256   -t       enable ncurses trace
1257   -v       verbose
1258   -x       build each directory after setting up
1259 EOF
1260     exit;
1261 }
1262
1263 $Getopt::Std::STANDARD_HELP_VERSION = 1;
1264 &getopts('d:nrtvx') || &usage();
1265 $opt_d = "/usr/src" unless ($opt_d);
1266 &usage() unless ( $#ARGV <= 0 );
1267
1268 if ( $#ARGV == 0 ) {
1269     if ( -f $ARGV[0] ) {
1270         printf "** unpacking sources: %s\n", $ARGV[0];
1271         &unpack( $ARGV[0] );
1272     }
1273     else {
1274         &check_sourcedir( $ARGV[0] );
1275     }
1276 }
1277 else {
1278     &check_sourcedir(".");
1279 }
1280
1281 &setup_all_dirs;
1282
1283 # move out of temp-directory to allow cleanup.
1284 chdir $current;
1285
1286 1;