diff options
Diffstat (limited to 'misc/ncu2openbsd')
-rwxr-xr-x | misc/ncu2openbsd | 1286 |
1 files changed, 1286 insertions, 0 deletions
diff --git a/misc/ncu2openbsd b/misc/ncu2openbsd new file mode 100755 index 0000000..b066a10 --- /dev/null +++ b/misc/ncu2openbsd @@ -0,0 +1,1286 @@ +#!/usr/bin/env perl +# $Id: ncu2openbsd,v 1.65 2021/10/03 18:52:22 tom Exp $ +# ----------------------------------------------------------------------------- +# Copyright 2021 by Thomas E. Dickey +# +# All Rights Reserved +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name(s) of the above copyright +# holders shall not be used in advertising or otherwise to promote the +# sale, use or other dealings in this Software without prior written +# authorization. +# ----------------------------------------------------------------------------- +# https://invisible-island.net/ncurses/ncurses-openbsd.html +# +# Update the OpenBSD source-tree given an ncurses tarball or build-tree. + +use strict; +use warnings; + +use Getopt::Std; +use Cwd; +use Cwd 'abs_path'; +use File::Path qw/ remove_tree /; +use File::Temp qw/ tempdir /; + +$| = 1; + +our ( $opt_d, $opt_n, $opt_r, $opt_t, $opt_v, $opt_x ); +our $source_dir; +our $target_dir; +our $update_dir; +our $backup_dir; + +our $tempdir = tempdir( CLEANUP => 1 ); +my $current = getcwd; +my $working = $current; + +our $generated_by = "generated by: ncu2openbsd"; + +our %setup_dir = qw( + lib/libcurses ncurses + lib/libform form + lib/libmenu menu + lib/libpanel panel + usr.bin/infocmp progs + usr.bin/tabs progs + usr.bin/tic progs + usr.bin/toe progs + usr.bin/tput progs + usr.bin/tset progs + share/termtypes misc +); + +our %generated = qw( + codes.c 1 + comp_captab.c 1 + comp_userdefs.c 1 + expanded.c 1 + fallback.c 1 + init_keytry.h 1 + keys.list 1 + lib_gen.c 1 + lib_keyname.c 1 + make_hash 1 + make_keys 1 + names.c 1 + termsort.c 1 + unctrl.c 1 +); + +our %definitions = qw( + CAPTOINFO captoinfo + DATADIR /usr/share + INFOCMP infocmp + INFOTOCAP infotocap + NCURSES_MAJOR 5 + NCURSES_MINOR 7 + NCURSES_OSPEED int + NCURSES_PATCH 20081102 + TERMINFO /usr/share/terminfo + TIC tic + TOE toe + TPUT tput + TSET tset +); + +sub patchdate() { + return $definitions{"NCURSES_PATCH"}; +} + +sub failed($) { + chdir $current; + printf STDERR "? %s\n", $_[0]; + exit; +} + +sub verbose($) { + my $text = shift; + printf "%s\n", $text if ($opt_v); +} + +sub read_file($) { + my $name = shift; + open( my $fp, $name ) || &failed("cannot open $name"); + my (@input) = <$fp>; + chomp @input; + close($fp); + return @input; +} + +sub read_dir($) { + my $path = shift; + my @result; + if ( opendir( my $dh, $path ) ) { + my @data = sort readdir($dh); + closedir $dh; + for my $d ( 0 .. $#data ) { + next if ( $data[$d] =~ /^\.(\.)?$/ ); + next if ( -l $path . "/" . $data[$d] ); + $result[ $#result + 1 ] = $data[$d]; + } + } + return @result; +} + +sub rename_dir($$) { + my $src = shift; + my $dst = shift; + printf "%% mv %s -> %s\n", $src, $dst if ($opt_v); + rename $src, $dst unless ($opt_n); +} + +sub check_sourcedir($) { + my $path = shift; + &failed("not a directory: $path") unless ( -d $path ); + my $full = abs_path($path); + chdir $full; + &failed("not an ncurses source-tree: $path") + unless ( -f "NEWS" and -f "dist.mk" ); + $source_dir = $full; +} + +sub unpack($) { + my $path = shift; + my $full = abs_path($path); + my $command = ""; + if ( $path =~ /\.tgz$/ or $path =~ /\.tar\.gz$/ ) { + $command = "tar xzf %s"; + } + elsif ( $path =~ /\.zip$/ ) { + $command = "unzip -q %s"; + } + else { + &failed("not a gzip'd tarball or zip-file: $path"); + } + chdir $tempdir; + system( sprintf( $command, $full ) ); + + # there should be exactly one subdirectory -- the source-tree + my @data = &read_dir("."); + &failed("found no subdirectories of $path") if ( $#data < 0 ); + &failed( "too many subdirectories: " . $data[0] . " vs " . $data[1] ) + if ( $#data > 0 ); + &check_sourcedir( $data[0] ); +} + +sub remove_dir($) { + my $tree = shift; + if ( -d $tree ) { + printf "%% rm -rf %s\n", $tree if ($opt_v); + remove_tree( $tree, $opt_v ? 1 : 0, 1 ) unless ($opt_n); + } +} + +sub copy_CVS($) { + my $leaf = shift; + my $src = $target_dir . $leaf . "/CVS"; + my $dst = $update_dir . $leaf . "/CVS"; + my $verbose = $opt_v ? "v" : ""; + if ( -d $src and !-d $dst ) { + my $mid = $update_dir . $leaf; + mkdir $mid unless ( -d $mid ); + mkdir $dst unless ( -d $dst ); + system("cp -a$verbose $src/* $dst/"); + } +} + +sub is_tic_code($) { + my $item = shift; + my $result = 0; + $result = 1 + if ( + $item =~ /^(capconvert + |tic + |dump + |progs + |termsort + |transform + |MKtermsort)/x + ); + return $result; +} + +sub is_ident($$) { + my $name = shift; + my $text = shift; + my $code = 0; + $code = 1 if ( $text =~ /\$$name:.*\$/ ); + return $code; +} + +# We "could", filter out differences with ident's using the diff -I option, +# but in practice, that is cumbersome. +sub munge_ident($) { + my $target = shift; + my $source = $target; + $source =~ s/\.update\b//; + &failed("bug at $source") if ( $source eq $target ); + return unless ( -f $source ); + my @source = &read_file($source); + my @target = &read_file($target); + my $old_id = ""; + my $gap_id = 0; + my $new_id = ""; + my $skipit = -1; + + for my $n ( 0 .. $#source ) { + if ( &is_ident( "OpenBSD", $source[$n] ) ) { + $old_id = $source[$n]; + $skipit = $n + 1; + } + elsif ( &is_ident( "Id", $source[$n] ) ) { + $new_id = $source[$n]; + last; + } + elsif ( $n == $skipit ) { + $source[$n] =~ s/\s+$//; + if ( $source[$n] eq "" ) { + $gap_id = $source[$n]; + } + elsif ( $source[$n] eq '.\"' ) { + $gap_id = $source[$n]; + } + } + } + if ( $old_id ne "" ) { + my @update; + my $tables = &uses_tables($target); + $update[ $#update + 1 ] = $target[0] if ($tables); + $update[ $#update + 1 ] = $old_id; + $update[ $#update + 1 ] = $gap_id unless ( $gap_id eq 0 ); + for my $n ( $tables .. $#target ) { + if ( &is_ident( "Id", $target[$n] ) ) { + $update[ $#update + 1 ] = $new_id; + } + else { + $update[ $#update + 1 ] = $target[$n]; + } + } + system("chmod u+w $target"); + if ( open my $fp, ">", $target ) { + for my $n ( 0 .. $#update ) { + printf $fp "%s\n", $update[$n]; + } + close $fp; + system("chmod u-w $target"); + } + } +} + +# ncurses manual pages provide for renaming the utilities, normally as part of +# the scripts provided in its sources. OpenBSD developers do not use those. +sub munge_docs($) { + my $path = shift; + my @data = &read_file($path); + my $done = 0; + for my $n ( 0 .. $#data ) { + my $text = $data[$n]; + $text =~ s/\b1M\b/1/g; + $text =~ s/\b3X\b/3/g; + $text =~ s/\bcurs_(term(info|cap)\s*3\b)/$1/g; + $text =~ s/(\\fB)curs_(term(info|cap)\\f[RP]\(3\))/$1$2/g; + my $left = ""; + while ( $text =~ /@[[:alnum:]_]+@/ ) { + my $next = index( $text, "@" ); + last if ( $next < 0 ); + $left .= substr( $text, 0, $next++ ); + $text = substr( $text, $next ); + $next = index( $text, "@" ); + last if ( $next < 0 ); + my $word = substr( $text, 0, $next ); + if ( $word =~ /^[[:alnum:]_]+/ ) { + + if ( $definitions{$word} ) { + $word = $definitions{$word}; + } + else { + $word = "?"; + } + $left .= $word; + $text = substr( $text, $next + 1 ); + } + else { + &failed("unexpected definition @$word@"); + } + } + $text = $left . $text; + if ( $text ne $data[$n] ) { + $done++; + $data[$n] = $text; + } + } + if ($done) { + system("chmod u+w $path"); + if ( open my $fp, ">", $path ) { + for my $n ( 0 .. $#data ) { + printf $fp "%s\n", $data[$n]; + } + close $fp; + system("chmod u-w $path"); + } + } +} + +sub copy_file($$) { + my $src = shift; + my $dst = shift; + my $verbose = $opt_v ? "v" : ""; + if ( -d $dst ) { + my $leaf = $src; + $leaf =~ s,^.*/,,; + $dst .= "/" . $leaf; + } + system("chmod u+w $dst") if ( -f $dst ); + system("cp -a$verbose $src $dst"); + &munge_ident($dst); +} + +sub copy_code($) { + my $src = shift; + my $dst = shift; + ©_CVS( substr( $dst, length($update_dir) ) ); + printf ".. copying files for $dst\n"; + my @data = &read_dir($src); + printf ".. %d entries\n", $#data + 1; + my $verbose = $opt_v ? "v" : ""; + for my $d ( 0 .. $#data ) { + my $item = $data[$d]; + my $src_item = $src . "/" . $item; + next if ( -d $src_item ); + next if ( -l $src_item ); + next if ( $item =~ /^\.(\.)?$/ ); + next if ( $item =~ /\.(bak|in|log|status)$/ ); + next if ( $item =~ /^llib-/ ); + next if ( $item =~ /^modules/ ); + next if ( $item =~ /^[fm]_trace\.c/ and not $opt_t ); + next + if ( $item =~ /^Makefile/ and index( $update_dir, "/share/" ) < 0 ); + next if ( $item =~ /^README/ ); + next if ( $item eq "headers" ); + next if ( $generated{$item} ); + next if ( $item eq "link_test.c" ); + + if ( index( $dst, "/usr.bin/" ) >= 0 ) { + next if ( $item =~ /^(clear)/ ); # OpenBSD uses "tput clear" + my $prog = $dst; + $prog =~ s%^.*/%%; + $prog =~ s/(update|backup)//; + $prog .= "c"; + if ( $dst =~ /infocmp/ ) { + next if ( $item ne $prog ); + } + elsif ( $dst =~ /tabs/ ) { + next if ( $item ne $prog ); + } + elsif ( $dst =~ /tic/ ) { + next if ( &is_tic_code($item) == 0 ); + } + elsif ( $dst =~ /toe/ ) { + next if ( $item ne $prog ); + } + elsif ( $dst =~ /tput/ ) { + next if ( $item ne $prog ); + } + elsif ( $dst =~ /tset/ ) { + next if ( $item ne $prog ); + } + else { + next; + } + } + system( sprintf( "cp -a$verbose %s %s/%s", $src_item, $dst, $item ) ); + &munge_ident("$dst/$item"); + } +} + +# Checking if nroff supports tables is a long-obsolete issue, and is not really +# necessary, except to match OpenBSD's source-tree. +sub uses_tables($) { + my $docs = shift; + my @docs = &read_file($docs); + my $code = 0; + for my $n ( 0 .. $#docs ) { + if ( $docs[$n] =~ /^[.']\\"\s+t\b.*/ ) { + $code = 1; + last; + } + elsif ( $docs[$n] =~ /^\./ ) { + last; + } + } + return $code; +} + +sub copy_1doc($$) { + my $docs = shift; + my $src = "$source_dir/man/$docs"; + my $dst = "$update_dir/$docs"; + $src .= "m" if ( -f "${src}m" ); + $dst =~ s/x$//; + if ( $dst =~ /\.3/ ) { + $dst =~ s/\bncurses/curses/ if ( $dst =~ /ncurses\./ ); + $dst =~ s/\bcurs_// if ( $dst =~ /_term(cap|info)\./ ); + } + ©_file( $src, $dst ); + &munge_docs($dst); +} + +sub copy_docs($) { + my $docs = shift; + if ( index( $update_dir, "/usr.bin/" ) >= 0 ) { + ©_1doc( $docs . ".1" ); + if ( $docs eq "tic" ) { + ©_1doc("captoinfo.1"); + ©_1doc("infotocap.1"); + } + } + else { + my @docs = &read_dir("$source_dir/man"); + if ( $docs eq "curses" ) { + for my $n ( 0 .. $#docs ) { + next if ( $docs[$n] eq "Makefile" ); + next if ( $docs[$n] eq "make_sed.sh" ); + next if ( $docs[$n] eq "man_db.renames" ); + next if ( $docs[$n] eq "manlinks.sed" ); + next if ( $docs[$n] =~ /\.(1|head|tail|in)/ ); + next if ( $docs[$n] =~ /^(form|menu|mitem|panel)/ ); + ©_1doc( $docs[$n] ); + } + } + elsif ( $docs eq "form" ) { + for my $n ( 0 .. $#docs ) { + next unless ( $docs[$n] =~ /^form/ ); + ©_1doc( $docs[$n] ); + } + } + elsif ( $docs eq "menu" ) { + for my $n ( 0 .. $#docs ) { + next unless ( $docs[$n] =~ /^(menu|mitem)/ ); + ©_1doc( $docs[$n] ); + } + } + elsif ( $docs eq "panel" ) { + for my $n ( 0 .. $#docs ) { + next unless ( $docs[$n] =~ /^panel/ ); + ©_1doc( $docs[$n] ); + } + } + } +} + +sub setup_dir($) { + my $dst = shift; + &failed("no definition for $dst") + unless ( defined $setup_dir{$dst} or $opt_r ); + $target_dir = sprintf( "%s/%s", $opt_d, $dst ); + $update_dir = $target_dir . ".update"; + $backup_dir = $target_dir . ".backup"; + my $result = 0; + if ($opt_r) { + &remove_dir($update_dir); + if ( $target_dir =~ /\/(tabs|toe)$/ ) { + &remove_dir($target_dir); + } + elsif ( -d $backup_dir ) { + &remove_dir($target_dir); + &rename_dir( $backup_dir, $target_dir ); + } + } + else { + &remove_dir($update_dir); + mkdir $update_dir; + + # reuse the shared-library version, assuming ABI=5 would involve at + # most a minor-version bump. + ©_file( "$target_dir/shlib_version", $update_dir ) + if ( $dst =~ /^lib\// ); + ©_code( $source_dir . "/" . $setup_dir{$dst}, $update_dir ) + unless ( $setup_dir{$dst} eq "misc" ); + $result = 1; + } + return $result; +} + +sub do_build($) { + my $command = shift; + printf "%% %s\n", $command if ($opt_v); + system($command); +} + +sub finish_dir() { + printf "** $target_dir\n"; + system("diff -Naurb $target_dir $update_dir | diffstat -n 30") + if ( -d $target_dir ); + if ($opt_n) { + &do_build("cd $update_dir && make -n") if ($opt_x); + } + else { + if ( -d $backup_dir ) { + printf STDERR "? backup directory exists: %s\n", $backup_dir; + } + else { + &rename_dir( $target_dir, $backup_dir ); + &rename_dir( $update_dir, $target_dir ); + } + &do_build("cd $target_dir && make") if ($opt_x); + } +} + +################################################################################ + +sub only_c_files($) { + my @data = @{ $_[0] }; + my %data; + for my $n ( 0 .. $#data ) { + my $text = $data[$n]; + $data{$text}++ if ( $text =~ /\.c$/ ); + } + return sort keys %data; +} + +sub makefile_list($$$) { + my @data = @{ $_[0] }; + my $name = $_[1]; + my $skip = $_[2]; + my %data; + my $state = 0; + for my $n ( 0 .. $#data ) { + my $text = $data[$n]; + $text =~ s/^\s+//; + next if ( index( $text, $skip ) == 0 ); + $text =~ s/\s+=/=/; + $text =~ s/=\s+/=/; + $text =~ s/\s*\\//; + $state = 1 if ( $text =~ /^${name}=/ ); + next unless ( $state == 1 ); + + if ( index( $text, "(trace)" ) >= 0 and not $opt_t ) { + next unless ( $text =~ /\b(lib_trace|visbuf)\.c$/ ); + } + if ( not $opt_t ) { + next if ( $text =~ /\b[fm]_trace\.c$/ ); + } + $text =~ s/^.*=//; + $text =~ s/\$o/.o/g; + $text =~ s/^.*\///; + next if ( $text eq "link_test.c" ); + next if ( $text eq "mf_common.h" ); + next if ( $text eq "transform.h" ); + $data{$text}++ if ( $text ne "" ); + last if ( $data[$n] !~ /\\$/ ); + } + return sort keys %data; +} + +sub manpage_list($) { + my $path = shift; + my @data = &read_dir($path); + my %data; + for my $n ( 0 .. $#data ) { + my $text = $data[$n]; + $data{$text}++ if ( $text =~ /\.\d$/ ); + } + return sort keys %data; +} + +sub columns_of($) { + my $string = shift; + my $result = 0; + for my $n ( 0 .. length($string) - 1 ) { + my $c = substr( $string, $n, 1 ); + if ( $c eq "\t" ) { + $result |= 7; + $result++; + } + elsif ( $c eq "\n" ) { + $result = 0; + } + else { + ++$result; + } + } + return $result; +} + +sub format_list($$) { + my $name = $_[0]; + my @data = @{ $_[1] }; + my $keep = ( defined $_[2] ) ? 1 : 0; + my $base; + my $fill; + if ( length($name) >= 9 ) { + $fill = " "; + $base = length($name) + 1; + } + else { + $base = 9; + $fill = "\t"; + } + my $result = sprintf( "%s%s", $name, $fill ); + if ( $keep == 0 ) { + my %data; + for my $n ( 0 .. $#data ) { + $data{ $data[$n] } = 1 if ( defined $data[$n] ); + } + @data = sort keys %data; + } + for my $n ( 0 .. $#data ) { + my $data = $data[$n]; + my $col = &columns_of($result); + my $add = 1 + length($data); + if ( ( $col + $add ) > 76 ) { + $result .= " " if ( $col > $base ); + $base = 9; + $fill = "\t"; + $result .= "\\\n" . $fill . $data; + } + else { + $result .= " " if ( $col > $base ); + $result .= $data; + } + } + return $result; +} + +################################################################################ + +sub compare_makefiles($) { + if ($opt_v) { + my $newfile = shift; + my $bakfile = + ( -d $backup_dir ? $backup_dir : $target_dir ) . "/Makefile"; + system("diff -u $bakfile $newfile") if ( -f $bakfile ); + } +} + +# The curses makefile has to build build-time utilities and generate source. +sub gen_1st_makefile() { + my $libname = "curses"; + my $oldfile = "$source_dir/n$libname/Makefile"; + my @oldfile = &read_file($oldfile); + + my $newfile = "$update_dir/Makefile"; + open( my $fp, ">", $newfile ) || &failed("cannot open $newfile"); + my @subdirs = ( + '${.CURDIR}/base', '${.CURDIR}/tinfo', + '${.CURDIR}/tty', '${.CURDIR}/widechar' + ); + $subdirs[ $#subdirs + 1 ] = '${.CURDIR}/trace' if ($opt_t); + printf $fp <<EOF; +# $generated_by + +LIB= $libname + +# Uncomment this to enable tracing in libcurses +#CURSESTRACE=-DTRACE + +# This is used to compile terminal info directly into the library +FALLBACK_LIST= + +# XXX - should be defined elsewhere +AWK?= /usr/bin/awk + +# Search in subdirs +EOF + printf $fp "%s\n", &format_list( ".PATH:", \@subdirs ); + + my @autosrc = &makefile_list( \@oldfile, "AUTO_SRC", "?" ); + my @auto_cc = &only_c_files( \@autosrc ); + printf $fp "%s\n", &format_list( "SRCS=", \@auto_cc ); + + my @sources = &makefile_list( \@oldfile, "C_SRC", "./" ); + printf $fp "%s\n", &format_list( "SRCS+=", \@sources ); + + printf $fp <<EOF; + +HOSTCFLAGS?= \${CFLAGS} +HOSTLDFLAGS?= \${LDFLAGS} +HOSTCFLAGS+= -I. -I\${.CURDIR} \${CURSESTRACE} +CFLAGS+= -I. -I\${.CURDIR} \${CURSESTRACE} -D_XOPEN_SOURCE_EXTENDED -DNDEBUG + +EOF + my @manpages = &manpage_list($update_dir); + printf $fp "%s\n", &format_list( "MAN=", \@manpages ); + + $autosrc[ $#autosrc++ ] = "make_hash"; + $autosrc[ $#autosrc++ ] = "make_keys"; + printf $fp "%s\n", &format_list( "GENERATED=", \@autosrc ); + printf $fp <<EOF; + +CAPLIST = \${.CURDIR}/Caps +USE_BIG_STRINGS = 1 + +CLEANFILES+= \${GENERATED} + +BUILDFIRST = \${GENERATED} + +includes: + \@cmp -s \${DESTDIR}/usr/include/ncurses.h \${.CURDIR}/curses.h || \\ + \${INSTALL} \${INSTALL_COPY} -m 444 -o \$(BINOWN) -g \$(BINGRP) \\ + \${.CURDIR}/curses.h \${DESTDIR}/usr/include/ncurses.h + \@cd \${.CURDIR}; for i in ncurses_dll.h unctrl.h term.h termcap.h; do \\ + cmp -s \$\$i \${DESTDIR}/usr/include/\$\$i || \\ + \${INSTALL} \${INSTALL_COPY} -m 444 -o \$(BINOWN) -g \$(BINGRP) \$\$i \\ + \${DESTDIR}/usr/include; done + +keys.list: \${.CURDIR}/tinfo/MKkeys_list.sh + sh \${.CURDIR}/tinfo/MKkeys_list.sh \${.CURDIR}/Caps | sort > \${.TARGET} + +fallback.c: \${.CURDIR}/tinfo/MKfallback.sh + sh \${.CURDIR}/tinfo/MKfallback.sh /usr/share/terminfo \${.CURDIR}/../../share/termtypes/termtypes.master \$(FALLBACK_LIST) > \${.TARGET} + +lib_gen.c: \${.CURDIR}/base/MKlib_gen.sh + sh \${.CURDIR}/base/MKlib_gen.sh "\${CC} -E -P -I\${.CURDIR}" \\ + "\${AWK}" generated < \${.CURDIR}/curses.h > lib_gen.c + +init_keytry.h: make_keys keys.list + ./make_keys keys.list > \${.TARGET} + +make_keys: \${.CURDIR}/tinfo/make_keys.c \${.CURDIR}/curses.priv.h names.c + \${HOSTCC} \${LDSTATIC} \${HOSTCFLAGS} \${HOSTLDFLAGS} \\ + -o \${.TARGET} \${.CURDIR}/tinfo/make_keys.c \${LDADD} +EOF + + if ( &patchdate >= 20090808 ) { + printf $fp <<EOF; +make_hash: \${.CURDIR}/tinfo/make_hash.c \\ + \${.CURDIR}/curses.priv.h \\ + \${.CURDIR}/hashsize.h + \${HOSTCC} \${LDSTATIC} \${HOSTCFLAGS} -DMAIN_PROGRAM \${HOSTLDFLAGS} \\ + -o \${.TARGET} \${.CURDIR}/tinfo/make_hash.c \${LDADD} +EOF + } + else { + printf $fp <<EOF; +make_hash: \${.CURDIR}/tinfo/comp_hash.c \\ + \${.CURDIR}/curses.priv.h \\ + \${.CURDIR}/hashsize.h + \${HOSTCC} \${LDSTATIC} \${HOSTCFLAGS} -DMAIN_PROGRAM \${HOSTLDFLAGS} \\ + -o \${.TARGET} \${.CURDIR}/tinfo/comp_hash.c \${LDADD} +EOF + } + + if ( &patchdate >= 20190309 ) { + printf $fp <<EOF; +CAPLIST += \${.CURDIR}/Caps-ncurses + +comp_userdefs.c: make_hash \\ + \${.CURDIR}/hashsize.h \\ + \${.CURDIR}/tinfo/MKuserdefs.sh + sh \${.CURDIR}/tinfo/MKuserdefs.sh \${AWK} \${USE_BIG_STRINGS} \${CAPLIST} > \${.TARGET} +EOF + } + printf $fp <<EOF; + +expanded.c: \${.CURDIR}/term.h \${.CURDIR}/curses.priv.h \\ + \${.CURDIR}/ncurses_cfg.h \${.CURDIR}/tty/MKexpanded.sh + sh \${.CURDIR}/tty/MKexpanded.sh "\${CC} -E -P" \${CPPFLAGS} > \${.TARGET} + +comp_captab.c: make_hash + sh \${.CURDIR}/tinfo/MKcaptab.sh \${AWK} \${USE_BIG_STRINGS} \\ + \${.CURDIR}/tinfo/MKcaptab.awk \${CAPLIST} > \${.TARGET} + +lib_keyname.c: keys.list \${.CURDIR}/base/MKkeyname.awk + \${AWK} -f \${.CURDIR}/base/MKkeyname.awk \\ + bigstrings=\${USE_BIG_STRINGS} \\ + keys.list > \${.TARGET} + +names.c: \${.CURDIR}/tinfo/MKnames.awk + \${AWK} -f \${.CURDIR}/tinfo/MKnames.awk \\ + bigstrings=\${USE_BIG_STRINGS} \\ + \${CAPLIST} > \${.TARGET} +codes.c: \${.CURDIR}/tinfo/MKcodes.awk + \${AWK} -f \${.CURDIR}/tinfo/MKcodes.awk \\ + bigstrings=\${USE_BIG_STRINGS} \\ + \${CAPLIST} > \${.TARGET} + +unctrl.c: \${.CURDIR}/base/MKunctrl.awk + echo | \${AWK} -f \${.CURDIR}/base/MKunctrl.awk bigstrings=1 > \${.TARGET} + +.include <bsd.own.mk> + +# Link libtermlib, libtermcap to libcurses so we don't break people's Makefiles +afterinstall: + -cd \${DESTDIR}\${LIBDIR}; \\ + for i in \${_LIBS}; do \\ + ln -f \$\$i `echo \$\$i | sed 's/curses/termlib/'`; \\ + ln -f \$\$i `echo \$\$i | sed 's/curses/termcap/'`; \\ + ln -f \$\$i `echo \$\$i | sed 's/curses/ncurses/'`; \\ + ln -f \$\$i `echo \$\$i | sed 's/curses/ncursesw/'`; \\ + done + +.include <bsd.lib.mk> +EOF + close $fp; + &compare_makefiles($newfile); +} + +sub gen_lib_makefile($) { + my $libname = shift; + my $oldfile = "$source_dir/$libname/Makefile"; + my @oldfile = &read_file($oldfile); + + # in ncurses, header-files are quasi-generated, because the original + # header file for form/menu/panel lives in the source-directory, but is + # copied to the include-directory with "make sources". + my @headers = &makefile_list( \@oldfile, "AUTO_SRC", "?" ); + + # The C source is more straightforward. + my @sources = &makefile_list( \@oldfile, "C_SRC", "?" ); + my $newfile = "$update_dir/Makefile"; + open( my $fp, ">", $newfile ) || &failed("cannot open $newfile"); + printf $fp <<EOF; +# $generated_by + +LIB= $libname +EOF + + printf $fp "%s\n", &format_list( "SRCS=", \@sources ); + printf $fp "%s\n", &format_list( "HDRS=", \@headers ); + my $includes = '-I${.CURDIR}/../libcurses'; + $includes .= ' -I${.CURDIR}/../libmenu' if ( $libname eq "form" ); + printf $fp <<EOF; +CFLAGS+=$includes -D_XOPEN_SOURCE_EXTENDED -DNDEBUG +EOF + my @manpages = &manpage_list($update_dir); + printf $fp "%s\n", &format_list( "MAN=", \@manpages ); + printf $fp <<EOF; + +includes: + \@cd \$\{.CURDIR}; for i in \$\{HDRS}; do \\ + cmp -s \$\$i \${DESTDIR}/usr/include/\$\$i || \\ + \${INSTALL} \${INSTALL_COPY} -m 444 -o \$(BINOWN) -g \$(BINGRP) \$\$i \\ + \${DESTDIR}/usr/include; done + +.include <bsd.own.mk> + +afterinstall: + -cd \${DESTDIR}\${LIBDIR}; \\ + for i in \${_LIBS}; do \\ + ln -f \$\$i `echo \$\$i | sed 's/${libname}/${libname}w/'`; \\ + done + +.include <bsd.lib.mk> +EOF + close $fp; + &compare_makefiles($newfile); +} + +sub gen_bin_makefile($) { + my $binname = shift; + my $oldfile = "$source_dir/progs/Makefile"; + my @oldfile = &read_file($oldfile); + my $newfile = "$update_dir/Makefile"; + + open( my $fp, ">", $newfile ) || &failed("cannot open $newfile"); + my @sources = ("$binname.c"); + my @links = (); + my @autosrc = &makefile_list( \@oldfile, "AUTO_SRC", "?" ); + + my $tput_ver = 0; + my $use_dump_entry = 0; + my $use_termsort = 0; + my $use_tparm_type = 0; + my $use_transform = 0; + + $use_dump_entry = 1 if ( $binname eq "infocmp" or $binname eq "tic" ); + $use_termsort = 1 if ( $use_dump_entry or $binname eq "tput" ); + + if ( &patchdate >= 20090314 ) { + $use_transform = 1 if ( $binname =~ /^(tic|tput|tset)/ ); + } + if ( &patchdate >= 20140521 ) { + $use_tparm_type = 1 if ( $binname =~ /^(tic|tput)$/ ); + } + if ( &patchdate >= 20160806 ) { + $tput_ver = &patchdate; + } + + $sources[ ++$#sources ] = "dump_entry.c" if ($use_dump_entry); + $sources[ ++$#sources ] = "tparm_type.c" if ($use_tparm_type); + $sources[ ++$#sources ] = "transform.c" if ($use_transform); + + $autosrc[ ++$#autosrc ] = "termsort.c" if ($use_termsort); + + # transform.h also is generated, but OpenBSD checked-in a copy + + if ( $binname eq "tic" ) { + $links[ ++$#links ] = "captoinfo"; + $links[ ++$#links ] = "infotocap"; + } + elsif ( $binname eq "tabs" ) { + $sources[ ++$#sources ] = "tty_settings.c" if ( $tput_ver >= 20161224 ); + } + elsif ( $binname eq "tput" ) { + $sources[ ++$#sources ] = "clear_cmd.c" if ( $tput_ver >= 20161022 ); + $sources[ ++$#sources ] = "reset_cmd.c" if ( $tput_ver >= 20160806 ); + $sources[ ++$#sources ] = "tty_settings.c" if ( $tput_ver >= 20161224 ); + $links[ ++$#links ] = "clear"; + } + elsif ( $binname eq "tset" ) { + $sources[ ++$#sources ] = "reset_cmd.c" if ( $tput_ver >= 20160806 ); + $sources[ ++$#sources ] = "tty_settings.c" if ( $tput_ver >= 20161224 ); + $links[ ++$#links ] = "reset"; + } + + printf $fp <<EOF; +# $generated_by + +PROG= $binname +EOF + printf $fp "%s\n", &format_list( "SRCS=", \@sources ); + printf $fp <<EOF; +CURSES= \${.CURDIR}/../../lib/libcurses +DPADD= \${LIBCURSES} +LDADD= -L\${CURSES} -lcurses\t# in-tree link to add _nc_strict_bsd, etc +EOF + if ( $#links >= 0 ) { + my @bin_links; + for my $n ( 0 .. $#links ) { + $bin_links[ ++$#bin_links ] = '${BINDIR}/' . $binname; + $bin_links[ ++$#bin_links ] = '${BINDIR}/' . $links[$n]; + } + printf $fp "%s\n", &format_list( "LINKS=", \@bin_links, 1 ); + } + my $ticfix = '${.CURDIR}/'; + if ( $binname eq "tic" ) { + printf $fp <<EOF; +CFLAGS+= -I\${CURSES} -I\${.CURDIR} -I. +EOF + } + else { + $ticfix = '${TIC}/'; + printf $fp <<EOF; +TIC= \${.CURDIR}/../tic +CFLAGS+= -I\${CURSES} -I\${TIC} -I\${.CURDIR} -I. +.PATH: \${TIC} +EOF + } + printf $fp "%s\n", &format_list( "CLEANFILES+=", \@autosrc ); + if ($use_dump_entry) { + printf $fp <<EOF; + +dump_entry.o: termsort.c +EOF + } + if ($use_termsort) { + printf $fp <<EOF; + +termsort.c: ${ticfix}MKtermsort.sh + sh ${ticfix}MKtermsort.sh awk \${CURSES}/Caps > \${.TARGET} +EOF + } + printf $fp <<EOF; + +.include <bsd.prog.mk> +EOF + close $fp; + + &compare_makefiles($newfile); +} + +################################################################################ + +sub setup_lib_libcurses() { + if ( &setup_dir("lib/libcurses") ) { + ©_code( "$source_dir/ncurses/base", "$update_dir/base" ); + ©_code( "$source_dir/ncurses/tinfo", "$update_dir/tinfo" ); + ©_code( "$source_dir/ncurses/tty", "$update_dir/tty" ); + ©_code( "$source_dir/ncurses/widechar", "$update_dir/widechar" ); + ©_file( "$source_dir/include/Caps", $update_dir ); + ©_file( "$source_dir/include/capdefaults.c", $update_dir ); + ©_file( "$source_dir/include/curses.h", $update_dir ); + ©_file( "$source_dir/include/hashed_db.h", $update_dir ); + ©_file( "$source_dir/include/hashsize.h", $update_dir ); + ©_file( "$source_dir/include/nc_alloc.h", $update_dir ); + ©_file( "$source_dir/include/nc_panel.h", $update_dir ); + ©_file( "$source_dir/include/nc_tparm.h", $update_dir ); + ©_file( "$source_dir/include/ncurses_cfg.h", $update_dir ); + ©_file( "$source_dir/include/ncurses_def.h", $update_dir ); + ©_file( "$source_dir/include/ncurses_dll.h", $update_dir ); + ©_file( "$source_dir/include/parametrized.h", $update_dir ); + ©_file( "$source_dir/include/term.h", $update_dir ); + ©_file( "$source_dir/include/termcap.h", $update_dir ); + ©_file( "$source_dir/include/term_entry.h", $update_dir ); + ©_file( "$source_dir/include/tic.h", $update_dir ); + ©_file( "$source_dir/include/unctrl.h", $update_dir ); + ©_file( "$source_dir/man/terminfo.5", $update_dir ); + ©_docs("curses"); + + &verbose(".. work around a bug in /bin/sh in OpenBSD"); + system( "sed -i" + . " -e 's,^shift,test \$# != 0 \\&\\& shift,'" + . " $update_dir/tinfo/MKfallback.sh" ); + + # OpenBSD dropped support for sys/ttydev.h, without mentioning the + # system version. Just trim it. + &verbose(".. work around mishandled sys/ttydef.h"); + system( "sed -i" + . " -e '/__FreeBSD_version/s,|| defined(__OpenBSD__),,'" + . " $update_dir/tinfo/lib_baudrate.c" ); + + if ($opt_t) { + ©_code( "$source_dir/ncurses/trace", "$update_dir/trace" ); + } + else { + ©_file( "$source_dir/ncurses/trace/lib_trace.c", $update_dir ); + ©_file( "$source_dir/ncurses/trace/visbuf.c", $update_dir ); + } + ©_file( "$source_dir/include/nc_termios.h", $update_dir ) + if ( &patchdate >= 20110625 ); + ©_file( "$source_dir/include/nc_string.h", $update_dir ) + if ( &patchdate >= 20120222 ); + ©_file( "$source_dir/include/nc_access.h", $update_dir ) + if ( &patchdate >= 20210626 ); + ©_file( "$source_dir/include/Caps-ncurses", $update_dir ) + if ( &patchdate >= 20190302 ); + &gen_1st_makefile; + &finish_dir; + } +} + +sub setup_lib_libform() { + if ( &setup_dir("lib/libform") ) { + ©_docs("form"); + &gen_lib_makefile("form"); + &finish_dir; + } +} + +sub setup_lib_libmenu() { + if ( &setup_dir("lib/libmenu") ) { + ©_docs("menu"); + &gen_lib_makefile("menu"); + &finish_dir; + } +} + +sub setup_lib_libpanel() { + if ( &setup_dir("lib/libpanel") ) { + ©_docs("panel"); + &gen_lib_makefile("panel"); + &finish_dir; + } +} + +sub setup_bin_infocmp() { + if ( &setup_dir("usr.bin/infocmp") ) { + ©_docs("infocmp"); + &gen_bin_makefile("infocmp"); + &finish_dir; + } +} + +sub setup_bin_tabs() { + if ( &setup_dir("usr.bin/tabs") ) { + ©_docs("tabs"); + &gen_bin_makefile("tabs"); + &finish_dir; + } +} + +sub setup_bin_tic() { + if ( &setup_dir("usr.bin/tic") ) { + if ( &patchdate >= 20140521 ) { + ©_file( "$source_dir/progs/tparm_type.c", $update_dir ); + ©_file( "$source_dir/progs/tparm_type.h", $update_dir ); + } + + # shared files for tput/tset + if ( &patchdate >= 20160806 ) { + ©_file( "$source_dir/progs/reset_cmd.c", $update_dir ); + ©_file( "$source_dir/progs/reset_cmd.h", $update_dir ); + } + if ( &patchdate >= 20161022 ) { + ©_file( "$source_dir/progs/clear_cmd.c", $update_dir ); + ©_file( "$source_dir/progs/clear_cmd.h", $update_dir ); + } + if ( &patchdate >= 20161224 ) { + ©_file( "$source_dir/progs/tty_settings.c", $update_dir ); + ©_file( "$source_dir/progs/tty_settings.h", $update_dir ); + } + ©_docs("tic"); + &gen_bin_makefile("tic"); + &finish_dir; + } +} + +sub setup_bin_toe() { + if ( &setup_dir("usr.bin/toe") ) { + ©_docs("toe"); + &gen_bin_makefile("toe"); + &finish_dir; + } +} + +sub setup_bin_tput() { + if ( &setup_dir("usr.bin/tput") ) { + ©_docs("tput"); + &gen_bin_makefile("tput"); + &finish_dir; + } +} + +sub setup_bin_tset() { + if ( &setup_dir("usr.bin/tset") ) { + ©_docs("tset"); + &gen_bin_makefile("tset"); + &finish_dir; + } +} + +sub setup_terminfo() { + if ( &setup_dir("share/termtypes") ) { + ©_code( $target_dir, $update_dir ); + ©_file( "$source_dir/misc/terminfo.src", + "$update_dir/termtypes.master" ); + + # build the terminfo database using the in-tree tic. + # This is always best practice, but for ncurses 6.2 in particular is + # required. + my $prog = abs_path("$target_dir/../../usr.bin/tic"); + my $libs = abs_path("$target_dir/../../lib/libcurses"); + if ( defined $prog and defined $libs ) { + $prog .= "/tic"; + &verbose(".. changing makefile to use in-tree tic"); + system( "sed -i -E " + . "-e 's,(TIC=).*,\\1\t$prog,' " + . "-e 's,(\\\${TIC}),LD_LIBRARY_PATH=$libs \\1,' " + . "$update_dir/Makefile" ); + } + &finish_dir; + } +} + +sub configure_tree() { + return if ( -f "ncurses/Makefile" ); + my @search = ( "/usr/share/terminfo", "/usr/local/share/terminfo" ); + my @prefix = ("./configure"); + $prefix[ ++$#prefix ] = "--with-abi-version=5" + if ( &patchdate >= 20150502 ); + my @options = ( + "--with-ospeed=int", # + "--with-shared", # + "--without-normal", # + "--without-debug", # + "--with-terminfo-dirs=" . join( ':', @search ), # + "--without-ada", # + "--disable-hard-tabs", # + "--enable-const", # + "--enable-getcap", # + "--enable-bsdpad", # + "--enable-signed-char", # + "--enable-termcap", # + "--enable-widec" + ); + $options[ ++$#options ] = "--with-trace" if ($opt_t); + $options[ ++$#options ] = "--enable-string-hacks" + if ( &patchdate >= 20120225 ); + system( join( ' ', @prefix ) . ' ' . join( ' ', @options ) ); + &failed("problem with configuring") unless ( -f "ncurses/Makefile" ); + + system("make sources"); + + # OpenBSD developers edit the generated file and do not regen it when + # doing upgrades. This script reflects those edits. + system( "sed -i" . " -E" + . " -e '/TYPEOF_CHTYPE/s,int,long,'" + . " -e '/USE_TERMCAP/d'" + . " -e '/HAVE_LIB(FORM|MENU|PANEL)/s,^(.*)\$,/* \\1 */,'" + . " -e 's/TERMPATH.*/PURE_TERMINFO 0/'" + . " -e '/SYSTEM_NAME/s,\[0-9.\]+,,'" + . " include/ncurses_cfg.h" ); +} + +sub get_definitions() { + my @data = &read_file("dist.mk"); + for my $n ( 0 .. $#data ) { + my $text = $data[$n]; + $text =~ s/^\s*//; + next unless ( $text =~ /^NCURSES.*=/ ); + $text =~ s/\s*=\s+/=/; + my $name = $text; + $name =~ s/=.*//; + my $value = $text; + $value =~ s/^[^=]*=//; + $value =~ s/\s.*//; + $definitions{$name} = $value; + } +} + +sub setup_all_dirs() { + printf "** %s all build-directories\n", $opt_r ? "removing" : "setting up"; + &get_definitions; + &configure_tree unless ($opt_r); + &setup_lib_libcurses; + &setup_lib_libmenu; + &setup_lib_libform; # build after libmenu, for mf_common.h + &setup_lib_libpanel; + &setup_bin_tic; # do this first, for shared headers + &setup_bin_infocmp; + &setup_bin_tabs if ( -f "$source_dir/progs/tabs.c" ); + &setup_bin_toe; + &setup_bin_tput; + &setup_bin_tset; + &setup_terminfo; +} + +sub usage() { + print <<EOF; +Usage: ncu2openbsd [options] [sourcetree] + +Options: + -d DST specify destination (default: /usr/src) + -n no-op, do not update destination + -r remove update, restore sources from ".orig" + -t enable ncurses trace + -v verbose + -x build each directory after setting up +EOF + exit; +} + +$Getopt::Std::STANDARD_HELP_VERSION = 1; +&getopts('d:nrtvx') || &usage(); +$opt_d = "/usr/src" unless ($opt_d); +&usage() unless ( $#ARGV <= 0 ); + +if ( $#ARGV == 0 ) { + if ( -f $ARGV[0] ) { + printf "** unpacking sources: %s\n", $ARGV[0]; + &unpack( $ARGV[0] ); + } + else { + &check_sourcedir( $ARGV[0] ); + } +} +else { + &check_sourcedir("."); +} + +&setup_all_dirs; + +# move out of temp-directory to allow cleanup. +chdir $current; + +1; |