diff options
Diffstat (limited to 'scripts')
95 files changed, 25243 insertions, 0 deletions
diff --git a/scripts/Makefile.am b/scripts/Makefile.am new file mode 100644 index 00000000..3cea8486 --- /dev/null +++ b/scripts/Makefile.am @@ -0,0 +1,57 @@ +# sorted by function +bin_SCRIPTS = \ + create_makefile create_makefiles adddebug \ + cheatmake makeobj kde-build build-progress.sh pruneemptydirs \ + cvsbackport cvsversion cvscheck cvslastchange cvslastlog cvsrevertlast \ + noncvslist cvs-clean cvs2dist cvsblame cvsforwardport create_cvsignore \ + colorsvn create_svnignore nonsvnlist svn2dist svnaddcurrentdir svnbackport svnforwardport \ + svn-clean svngettags svnlastchange svnlastlog svnrevertlast svnversions \ + svnchangesince findmissingcrystal kdesvn-build \ + kdedoc qtdoc extractrc extractattr zonetab2pot.py \ + licensecheck fixkdeincludes fixuifiles includemocs \ + cxxmetric extend_dmalloc kdekillall kdelnk2desktop.py \ + package_crystalsvg png2mng.pl kdemangen.pl + +# Install syntax highlighting file for KWrite/Kate. +kdesvn_build_syntaxdir = $(kde_datadir)/katepart/syntax +kdesvn_build_syntax_DATA = kdesvn-buildrc.xml + +# sorted by bin_SCRIPTS reference +man_MANS = \ + kde-build.1 \ + kdesvn-build.1 \ + cvsversion.1 cvscheck.1 \ + noncvslist.1 \ + cvsblame.1 \ + includemocs.1 + +CLEANFILES = $(man_MANS) + +# sorted alphabetically +noinst_SCRIPTS = \ + add_trace.pl alldcop.rb authors2xml.pl check_licenses colorcvs \ + cvsaddcurrentdir fixheaders kDebug2kdDebug.sh + +EXTRA_DIST = completions kde-emacs \ + colorcvsrc-sample gettext.patch kde-buildrc \ + kde-devel-emacs.el kde-devel-gdb kde-devel-vim.vim \ + kde.supp kdesvn-buildrc-sample + +# it'd be too good if this worked everywhere ... +#%.1: % +# pod2man $< $@ + +kde-build.1: kde-build + pod2man $(srcdir)/kde-build > $@ +kdesvn-build.1: kdesvn-build + pod2man $(srcdir)/kdesvn-build > $@ +cvsversion.1: cvsversion + pod2man $(srcdir)/cvsversion > $@ +cvscheck.1: cvscheck + pod2man $(srcdir)/cvscheck > $@ +noncvslist.1: noncvslist + pod2man $(srcdir)/noncvslist > $@ +cvsblame.1: cvsblame + pod2man $(srcdir)/cvsblame > $@ +includemocs.1: includemocs + pod2man $(srcdir)/includemocs > $@ diff --git a/scripts/README b/scripts/README new file mode 100644 index 00000000..ca3811e5 --- /dev/null +++ b/scripts/README @@ -0,0 +1,186 @@ + +Stuff in this directory: + +=== DEBUGGING SUPPORT + +adddebug Modifies the Makefile to add debug info (-g) + +add_trace.pl Modifies a source file to add a trace as the first line + of every method, using kdDebug, and showing args values. + +kDebug2kdDebug.sh Script to convert old KDE debugging statements to their + modern equivalents. + +extend_dmalloc Script to run gdb on return-addresses + +kdekillall Kills the process "kdeinit: <process> with signal <signal> + +=== PROGRAMMING SUPPORT + +cheatmake Helper for saving time when recompiling, skipping files that + haven't changed in a meaningful way (e.g. if you only change + a comment...) + +check_licenses Old license checker for source files + (Use licensecheck instead) + +licensecheck Simple license checker for source files + +create_makefile Create the Makefile in a directory containing a Makefile.am + Saves time compared to re-running configure completely + +create_makefiles The recursive version of it - needs create_makefile. + +fixheaders Adds header files as it recognices make error output + +fixkdeincludes Tries to reduce the number of includes in KDE source files + +fixuifiles Fixes up Qt Designer .ui files (version, accels, generated names) + To use before any commit of a .ui file. + +fixfsfaddr.sed Script for sed to fix old FSF addresses + +includemocs Adds missing "#include foobar.moc" lines + +kdedoc Open a kde help page in kfm/konqueror + +qtdoc Open a qt help page in kfm/konqueror + +kde-spellcheck.pl A script to check source code for misspelings and optionally + correct them. + +=== MODERNIZATION SCRIPTS + +rc2kcfgxt.pl Reads an existing KConfig rc file and creates a best-guess + version of a KConfigXT XML file. + +kdelnk2desktop.py Converts old-style .kdelnk files to their modern .desktop + equivalents. + +=== USEFUL DATA FOR EXTERNAL PROGRAMS + +kde-devel-emacs.el An emacs file that contains many helpful functions and keybindings + A must for anyone using [X]Emacs to develop KDE/Qt/C++ applications. + +kde-devel-gdb A gdb macro definition file, to e.g. print QStrings from gdb. + +kde-devel-vim.vim A vim script that contains many helpful functions and keybindings + for vim-using KDE developers. + +kde.supp Some valgrind suppressions handy for ignoring stuff we don't + care about when valgrinding kde applications + +completions/ Contains useful scripts to enhance the auto-complete feature of some shells. + +=== INFORMATION EXTRACTION + +alldcop.rb Shows an pseudo-XML representation of the DCOP interfaces for + currently-running KDE applications. Does not require + Korundum. + +authors2xml.pl Extract author information from C++ files and print it out + in DocBook format as a list + +makeobj Script around make which basicly checks if it's in srcdir + or in builddir and changes to the right directory for + calling /usr/bin/make + +extractrc Extract text tags from designer's UI files and XML GUI-RC files + +extractattr Same as extractrc, but for use by Scripty. + +findmissingcrystal Looks at Crystal icons to find ones which are still + unchanged from kdeclassic. + +zonetab2pot.py Reads timezone list as its first argument or from + /usr/share/zoneinfo/zone.tab, and converts it to a PO file + template. + +kdemangen.pl Script to use the output from a KDE application's --author and + --help-all output to automatically generate a man page for the + application. + +png2mng.pl Script to convert a series of numbered .png files into a .mng + animation. + +package_crystalsvg Script to package all svg files recursively from the current + directory. + +=== SOURCE CONTROL UTILITIES (CVS and Subversion) +=== All CVS utilities have a corresponding svn version. + +colorcvs Colorizes cvs commands. + +create_cvsignore Create a .cvsignore file (using the contents of Makefile.am) + +cvs-clean Recursively wipes out everything not registered in the CVS + server, starting from the current directory. + +cvs2dist Create a standalone source distribution tarball for an app + in a KDE CVS module. + +cvsaddcurrentdir Add all files in and below the current dir to cvs. + *.c, *.h, *.C, *.cpp, *.cc are added automatically, + *~, *.o, *.so, *.lo, *.la, .libs/, .deps/, .#* are ignored. + You will be asked for the remaining files. + +cvsblame Bonsai-like cvs annotate + +cvscheck Offline check for status of files in a checked-out module. + +cvsgettags List the available CVS tags for a given set of files, or + recursively for all files and directories. No equivalent for + svn. + +noncvslist List all files in a checked out CVS module that are unknown to + to the CVS server. + +cvsversion Display CVS version of a file without connecting to the server. + +cxxmetric Counts lines of code, comments and blank space in C and C++ + source files. + +cvslastchange launches "cvs diff -u" to display the last applied changes for a + given file. HEAD branch only. + +cvslastlog Shows the log associated with the last change on a given file. + +cvsremovealltags Remove all tags from a CVS file. Use with care, and for instance + after copying a file on the server. + +cvsrevertlast Reverts all the files given on the command by one version, then + you can commit them. + +cvsbackport Backport the last commit in HEAD, to a branch. + +cvsforwardport Forwardport the last commit in a branch to HEAD + +pruneemptydirs Detects stale source dirs in a CVS tree + +cvslastreferenced Goes through the whole history of a file to find all modifications + referencing a specific string. It's useful if you want to know + when a function has been removed/modified/added to a file if a + recent cvs annotate doesn't reference it anymore. + +=== KDE BUILD SCRIPTS + +kde-build Updates and recompiles a local CVS or Subversion tree + +build-progress.sh Displays the progress of kde-build, times needed to complete each + step. And sets the titlebar of the terminal to the directory that + make is processing + +kdesvn-build Updates and recompiles a local Subversion tree. + +=== OTHERS + +gettext.patch Patch for gettext-0.10.35 to give xgettext the functionality to + extract scoped messages + +---------------- +Looking to add a script? + +Just add it to this README. For easy man pages see the perlpod manpage; the +man page for many of these tools is in the script itself. + +$Id$ diff --git a/scripts/add_trace.pl b/scripts/add_trace.pl new file mode 100644 index 00000000..bad152c3 --- /dev/null +++ b/scripts/add_trace.pl @@ -0,0 +1,124 @@ +## add_trace.pl +## Script to add a kdDebug() call as the first line of each method +## including as many parameters as possible (i.e. those supported by kdDebug) +## Very useful for tracing. +## +## Usage: perl -i add_trace.pl myfile.cpp +## +## Generates all statement with kdDebug(0) so that it is very easy +## to remove them afterwards : +## perl -pi -e 'if (/kdDebug\(0\)/) { $_ = ""; }' myfile.cpp +## perl -pi -e 'if (/#include <kdebug.h> \/\/ inserted by add_trace/) { $_ = ""; }' myfile.cpp +## +## needs perl 5.8+ for the Tie::File module +## +## Written by David Faure <faure@kde.org>, licensed under pizzaware. +## 18/03/2000 + +use Tie::File; + +sub insert_kdebug() +{ +# inserts a line "include <kdebug.h>" at the beginning of each file + for ($i=0;$i<$#ARGV;$i++) + { + tie @LOG, 'Tie::File', $ARGV[$i]; + unshift @LOG, '#include <kdebug.h> // inserted by add_trace'; + } +} + +insert_kdebug(); +$insignature=0; +while (<>) +{ + if ( $insignature ) + { + $statement .= $_; + chop; + $oneline .= $_; + } + elsif ( /^[^\s]+\s*[^\s]+::[^\s]+/ && !/typedef\s/ && !/^\s*class\s/ && !/^[^\s]+\s*[^\s]+::[^\s]+.*;/ && !/ *\/\// ) + # A function declaration starts. A function is not a typedef, not a class, not a command and not a comment. + { + $insignature = 1; + $statement = $_; + chop; + $oneline = $_; + } + elsif ( /^\/\/.*/) + { + # comment + # do nothing + $insignature = 0; + } + # [^\s]+ means, one ore more characters that are no spaces + elsif ( /^[^\s]+\s*[^\s]+::[^\s]+.*\}/ && !/typedef\s/ && !/^\s*class\s/ ) + { + # declaration and implementation in one line + # do nothing + $insignature = 0; + } + if ( $insignature ) + { + if ( /\{/ ) # End of signature + { + $insignature = 0; + $_ = $oneline; + #print STDERR "Signature : $_\n"; + print $statement; + $line = " kdDebug(0)"; + if ( m/([^\*\s]+::[^\s]+)\(/ ) + { + $line = $line . " << \"$1\""; + } + ## Ok now extract args + s/\/\*.*\*\///; + s/\s*\/\/.*//; # remove comments + s/^.*\([\s]*//; # Remove everything before first '(' + s/\s*\)\s*:\s+.*$/,/; # Remove any ") : blah", replace with a ',' + s/\s*\).*\{\s*$/,/; # Remove anything after ')', replace with a ',' + s/ const[&] / /g; + #print STDERR "Args list : $_\n"; + @args = split( ",", $_ ); + foreach (@args) + { + s/^\s*//; + s/\s*$//; + #print STDERR "Argument: $_\n"; + ## Pointer ? + if ( m/[a-zA-Z0-9_\s]+\*\s*([a-zA-Z0-9_]+)/ ) { + $line = $line . " << \" $1=\" << " . $1; + } + ## int, long ? + elsif ( m/^int\s+([a-zA-Z0-9_]+)/ || m/^long\s*([a-zA-Z0-9_]+)/ ) { + $line = $line . " << \" $1=\" << " . $1; + } + ## bool + elsif ( m/^bool\s+([a-zA-Z0-9_]+)/ ) { + $line = $line . " << \" $1=\" << (" . $1 . " ? \"true\" : \"false\" )"; + } + ## QString and friends + elsif ( m/QString[\&\s]+([a-zA-Z0-9_]+)/ || m/QCString[\&\s]*([a-zA-Z0-9_]+)/ ) { + $line = $line . " << \" $1=\" << " . $1; + } + ## KURL + elsif ( m/KURL[\&\s]+([a-zA-Z0-9_]+)/ ) { + $line = $line . " << \" $1=\" << " . $1 . ".url()"; + } + } + $line = $line . " << endl;\n"; + if ( !m/\}/ ) {print $line;} + #print STDERR "Debug call added : $line\n"; + } + } + else + { + # Normal line + print; + } +} +if ( $insignature ) +{ + print STDERR "Warning, unterminated method signature !! Check the file !\n"; + print $statement; +} diff --git a/scripts/adddebug b/scripts/adddebug new file mode 100755 index 00000000..8968e89c --- /dev/null +++ b/scripts/adddebug @@ -0,0 +1,63 @@ +#!/bin/sh +# Modifies the Makefile in the current directory (and optionally its subdirs), +# - to add debug info (-g3) +# - optionally (default) remove optimizations (-O[1-9]?) +# - optionally remove -DNDEBUG and -DNO_DEBUG + +mxdp="-maxdepth 1" +for i in $*; do + case $i in + -k) keep=1;; + -r) mxdp=;; + -n) ndebug=1;; + *) echo -e "Usage: adddebug [-k] [-r] [-n]\n -k: keep optimizations (removed by default)\n -r: recursive (process all subdirectories)\n -n: compile without NDEBUG and NO_DEBUG being defined (makes kdDebug calls work)"; exit 1;; + esac +done + +xpr='s/^((C|CXX|LD)FLAGS[ \t]*=.*)$/\1 -g3/' +if test -z $keep; then + xpr="$xpr;"'s/[\t ]-O[1-9]?\b//g' + xpr="$xpr;"'s/[\t ]-march=\S+\b//g' +fi +if test -z $ndebug; then + xpr="$xpr;"'s/[\t ]-DNDEBUG\b//g' + xpr="$xpr;"'s/[\t ]-DNO_DEBUG\b//g' +fi +find . $mxdp -name Makefile -exec perl -pi -e "$xpr" {} \; + +using_unsermake= +if head -n 1 Makefile | grep unsermake >/dev/null; then + using_unsermake=new +fi +if head -n 1 Makefile | grep automake >/dev/null; then + using_unsermake=old +fi + +top_builddir=`grep '^top_builddir' Makefile | sed -e 's/^.*= *//'` + +if test "$using_unsermake" = "new"; then + # the idea: grab the cxxflags from MakeVars, modify them, and write them down + # in every Makefile after the line that says .FORWARDS + toplevelMakefile=$top_builddir/Makefile + if [ -f $toplevelMakefile ]; then + # warning this uses sed, so the '?' in the perl regexp above doesn't work here + cxxflags=`grep ^CXXFLAGS $toplevelMakefile | sed -e 's/[\t ]-O[1-9]\b//g;s/[\t ]-march=\S+\b//g;s/[\t ]-DNDEBUG\b//g;s/[\t ]-DNO_DEBUG\b//g'` + xpr="s/^CXXFLAGS\s*=.*//; if ( /^\.FORWARDS:/) { "'$_'" .= \"\n$cxxflags -g3\"; }" + find . $mxdp -name Makefile -exec perl -pi -e "$xpr" {} \; + else + echo "ERROR: top_builddir is $top_builddir but $makevars not found" + fi + +elif test "$using_unsermake" = "old"; then + # the idea: grab the cxxflags from MakeVars, modify them, and write them down + # in every Makefile after the line that includes MakeVars + makevars=$top_builddir/MakeVars + if [ -f $makevars ]; then + # warning this uses sed, so the '?' in the perl regexp above doesn't work here + cxxflags=`grep ^CXXFLAGS $makevars | sed -e 's/[\t ]-O[1-9]\b//g;s/[\t ]-march=\S+\b//g;s/[\t ]-DNDEBUG\b//g;s/[\t ]-DNO_DEBUG\b//g'` + xpr="s/^CXXFLAGS\s*=.*//; if ( /^include .*MakeVars$/) { "'$_'" .= \"\n$cxxflags -g3\"; }" + find . $mxdp -name Makefile -exec perl -pi -e "$xpr" {} \; + else + echo "ERROR: top_builddir is $top_builddir but $makevars not found" + fi +fi diff --git a/scripts/alldcop.rb b/scripts/alldcop.rb new file mode 100755 index 00000000..b15a1fdd --- /dev/null +++ b/scripts/alldcop.rb @@ -0,0 +1,91 @@ +#!/usr/bin/env ruby + +module DCOP + + def dump_all_apps + + `dcop`.split(/\n/).each do + + |app| + + DCOP.dump_app(app) + + end + + end + + def dump_app(app) + + print "<app name=\"#{app}\">\n" + + `dcop #{app}`.split(/\n/).each do + + |object| + + DCOP.dump_object(app, object) + + end + + print "</app>\n" + + end + + def dump_object(app, object) + + object.gsub!(/\(default\)/, '') + object.strip! + + print " <object name=\"#{object}\">\n" unless object == "(default)" + + `dcop #{app} #{object}`.split(/\n/).each do + + |method| + + DCOP.dump_method(app, object, method) + + end + + print " </object>\n" + + end + + def dump_method(app, object, method) + + return_type, method_name, arg_str = method.split(/[ \(]/, 3) + + arg_str.gsub!(/\)$/, '') + + arg_list = arg_str.split(',') + + print " <method name=\"#{method_name}\" return-type=\"#{return_type}\"" + + if arg_list.empty? + + print "/>\n" + return + + else + + print ">\n" + + arg_list.each do + + |arg| + + type, name = arg.split + + print " <parameter name=\"#{name}\" type=\"#{type}\"/>\n" + + end + + print " </method>\n" + + end + + end + + module_function :dump_all_apps, :dump_app, :dump_object, :dump_method + +end + +DCOP.dump_all_apps if __FILE__ == $0 diff --git a/scripts/authors2xml.pl b/scripts/authors2xml.pl new file mode 100755 index 00000000..c2e34438 --- /dev/null +++ b/scripts/authors2xml.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w +# Extract author information from C++ files +# and print it out in DocBook format as a list +# Daniel Naber <daniel.naber@t-online.de> +# $Id$ + +my $file = $ARGV[0]; +if( ! $file ) { + print "Usage: $0 <file.cpp>\n"; + exit; +} + +open(IN, $file) || die "Cannot open '$file': $!\n"; +undef $/; +my $str = (<IN>); +close(IN); + +print "<itemizedlist>\n"; +while( $str =~ m/addAuthor\s*\(\s*"(.*?)",\s*.*?,\s*"(.*?)"/gs ) { + my ($name, $email) = ($1, $2); + print "<listitem><para>$name <email>$email</email></para></listitem>\n"; + #print "$name, $email\n"; +} +print "</itemizedlist>\n"; + +print STDERR "Warning: maybe you need to fix umlauts manually...\n"; +exit; diff --git a/scripts/build-progress.sh b/scripts/build-progress.sh new file mode 100644 index 00000000..05a9dfd7 --- /dev/null +++ b/scripts/build-progress.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# This method gives some kind of status message in the title bar of Konsole, +# xterm, etc.. Thanks have to go to Malte Starostik +# <malte@kde.org> for the code :-) +set_title() { +if ([ "$TERM" = "xterm" ] || [ "$TERM" = "xterm-color" ] || [ "$TERM" = "screen" ]) && tty -s; then + echo -ne "\033]0;$1\007" +fi +} +. ./kde-buildrc +set_title "Progress of kde-build script..." + +cd $KDELOGDIR +while true; do + dir=`ls -t | head -n 1 | xargs grep "Entering directory" | tail -n 1 | awk "{print \\$4}" | sed "s'$KDESRCDIR/''g"` + set_title "Building $dir" + clear + grep --no-filename -i "time needed" *build* | \ + sed "s/\:T/ T/g" + sleep 5 +done; diff --git a/scripts/cheatmake b/scripts/cheatmake new file mode 100755 index 00000000..9659a6cc --- /dev/null +++ b/scripts/cheatmake @@ -0,0 +1,80 @@ +#!/bin/sh +# Helper for saving time when recompiling, skipping files that haven't +# changed in a meaningful way (e.g. if you only change a comment...) +# +# LGPL v2, David Faure <david@mandrakesoft.com> + +usage() +{ + echo "Usage:" + echo " $0 hidechange file Hides the fact that file was changed (use with care!)" + echo " $0 show Lists what make currently has to rebuild" + echo " $0 why file Explains why make must rebuild file" + exit 1; +} + +if [ $# -eq 0 ]; then usage; fi +CDPATH= +builddir=$PWD + +# 'srcdir != builddir' stuff +if test ! -f Makefile && test -n "$OBJ_SUBDIR"; then + builddir=$OBJ_SUBDIR +else + if test ! -f Makefile && test -n "$OBJ_REPLACEMENT"; then + builddir=`pwd | sed -e "$OBJ_REPLACEMENT"` + fi +fi + +if test ! -f Makefile && test -n "$OBJ_SUBDIR"; then + builddir=$OBJ_SUBDIR +fi +cd $builddir +srcdir=`egrep '^srcdir *=' Makefile | sed -e "s#srcdir *= *##"` +UNSERMAKE=`type -p unsermake` +using_unsermake= +if head -n 1 Makefile | grep unsermake >/dev/null; then + using_unsermake=new +fi +if head -n 1 Makefile | grep automake >/dev/null; then + using_unsermake=old +fi + + +case $1 in + hidechange ) + if [ $# -ne 2 ]; then usage; fi + ## TODO: unsermake support (or support in unsermake itself) + deps=`make SUBDIRS='' -n | grep '\-o' | sed -e 's/.*-o \([^ ]*\).*/\1/'`; + if [ -n "$deps" ]; then + oldestdep=`ls -t $deps 2>/dev/null | tail -1` + thefile=$2 + if [ -f $srcdir/$thefile ]; then + thefile=$srcdir/$thefile + fi + echo + echo "Setting date of $thefile back in time with:" + echo "touch -r $oldestdep $thefile" ; touch -r $oldestdep $thefile + fi + ;; + show ) + if [ $# -ne 1 ]; then usage; fi + if test "$using_unsermake" != "new"; then + # Look at the commands that make will issue, and extract "-o output". + # The only trouble, with libtool, is that this gives us .libs/foo.o instead of foo.lo + make SUBDIRS='' -n | grep '\-o' | sed -e 's/.*-o \([^ ]*\).*/\1/' + else + # Solve the above problem (when using new-unsermake) by watching the "echo" lines for creating .lo files + # separately from the rest of the "-o target" lines (for libs and binaries) + # (For libs and bins another way would be to grep for "linking") + # The "ls" is for sorting by date + $UNSERMAKE -n | perl -e 'while(<>) { if (/by libtool/) { s/.*> //; print; } if (m/-o ([^ ]*)/ && $1!~/\.o$/) { print "$1\n"; } }' | xargs --no-run-if-empty ls -t -1 + fi + ;; + why ) + if [ $# -ne 2 ]; then usage; fi + ## TODO: unsermake support (or support in unsermake itself) + make SUBDIRS='' -n -d $2 | egrep -e "(newer than target \`$2'|Must)" + ;; + * ) usage ;; +esac diff --git a/scripts/check_licenses b/scripts/check_licenses new file mode 100755 index 00000000..6accd259 --- /dev/null +++ b/scripts/check_licenses @@ -0,0 +1,88 @@ +#!/usr/bin/perl -w + +unless (scalar(@ARGV) == 1) +{ + die "Usage: check_licenses directory"; +} + +my $gpl = 'General Public License'; +my $gp2 = 'This is free software; it comes under the GNU'; +my $gp3 = 'License: GPL with the following explicit clarification'; +my $x11 = 'TORT OR OTHERWISE'; +my $bsd = 'INCLUDING NEGLIGENCE OR OTHERWISE'; +my $gen = 'generated'; + +sub nameok() +{ + my $f = shift; + + if ($f =~ /\.C$/ or $f =~ /\.cpp$/ or $f =~ /\.c$/ or $f =~ /\.h$/) + { + if ($f =~ /\.cpp$/) + { + if + ( + $f !~ /meta_unload\.cpp$/ + and $f !~ /_stub\.cpp/ + and $f !~ /_skel.cpp/ + and $f !~ /_closure\.cpp/ + and $f !~ /moc\.cpp/ + ) + { + return 1; + } + else + { + return 0; + } + } + else + { + return 1; + } + } + else + { + return 0; + } +} + +sub recursive_check() +{ + my $dir = shift; + + opendir (DIR, $dir) or die "Can't open $dir"; + + my @filenames = grep { /^[^\.]/ } readdir(DIR); + + for my $f (@filenames) + { + my $filename = "$dir/$f"; + + if (-d $filename) + { + &recursive_check($filename); + } + elsif (-f $filename and &nameok($filename)) + { + open (IN, "<$filename") or die "Can't open $filename"; + + my $license = "!"; + + while (<IN>) + { + if (/$gpl/) { $license = "G"; last; } + if (/$gp2/) { $license = "G"; last; } + if (/$gp3/) { $license = "G"; last; } + if (/$x11/) { $license = "X"; last; } + if (/$bsd/) { $license = "B"; last; } + if (/$gen/) { $license = "g"; last; } + } + + print "$license $filename\n"; + } + } +} + +&recursive_check($ARGV[0]); + diff --git a/scripts/colorcvs b/scripts/colorcvs new file mode 100755 index 00000000..41c7716d --- /dev/null +++ b/scripts/colorcvs @@ -0,0 +1,175 @@ +#! /usr/bin/env perl + +# colorcvs +# +# based on colorgcc +# +# Requires the ANSIColor module from CPAN. +# +# Usage: +# +# In a directory that occurs in your PATH _before_ the directory +# where cvs lives, create a softlink to colorcvs: +# +# cvs -> colorcvs +# +# That's it. When "cvs" is invoked, colorcvs is run instead. +# +# The default settings can be overridden with ~/.colorcvsrc. +# See the colorcvsrc-sample for more information. +# +# Note: +# +# colorcvs will only emit color codes if: +# +# (1) tts STDOUT is a tty. +# (2) the value of $TERM is not listed in the "nocolor" option. +# (3) the cvs command is not a commit or import (as the text editor +# opened by cvs will often be hampered by colorcvs). +# +# If colorcvs colorizes the output, cvs's STDERR will be +# combined with STDOUT. Otherwise, colorcvs just passes the output from +# cvs through without modification. +# +# Copyright 2002 Neil Stevens <neil@qualityassistant.com> +# +# Copyright 1999 Jamie Moyers <jmoyers@geeks.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +use Term::ANSIColor; +use IPC::Open3; + +sub initDefaults +{ + $cvsPath = "/usr/bin/cvs"; + + $nocolor{"dumb"} = "true"; + + $colors{"P"} = color("reset"); + $colors{"U"} = color("reset"); + $colors{"C"} = color("bold red"); + $colors{"M"} = color("bold yellow"); + $colors{"A"} = color("cyan"); + $colors{"R"} = color("cyan"); + $colors{"?"} = color("bold"); + $colors{"server"} = color("bold green"); + $colors{"warning"} = color("bold cyan"); +} + +sub loadPreferences +{ +# Usage: loadPreferences("filename"); + + my($filename) = @_; + + open(PREFS, "<$filename") || return; + + while(<PREFS>) + { + next if (m/^\#.*/); # It's a comment. + next if (!m/(.*):\s*(.*)/); # It's not of the form "foo: bar". + + $option = $1; + $value = $2; + + if ($option =~ /cvs/) + { + $cvsPath = $value; + } + elsif ($option eq "nocolor") + { + # The nocolor option lists terminal types, separated by + # spaces, not to do color on. + foreach $termtype (split(/\s+/, $value)) + { + $nocolor{$termtype} = "true"; + } + } + else + { + $colors{$option} = color($value); + } + } + close(PREFS); +} + +# +# Main program +# + +# Set up default values for colors and cvs path. +initDefaults(); + +# Read the configuration file, if there is one. +$configFile = $ENV{"HOME"} . "/.colorcvsrc"; +if (-f $configFile) +{ + loadPreferences($configFile); +} + +# Get the terminal type. +$terminal = $ENV{"TERM"} || "dumb"; + +$commit = 0; +foreach (@ARGV) +{ + if(/^ci$/ || /^commit$/ || /^import$/) + { + $commit = 1; + } +} + +# If it's in the list of terminal types not to color, or if +# we're writing to something that's not a tty, don't do color. +if (! -t STDOUT || $commit == 1 || $nocolor{$terminal}) +{ + exec $cvsPath, @ARGV + or die("Couldn't exec"); +} + +# Keep the pid of the cvs process so we can get its return +# code and use that as our return code. +$cvs_pid = open3('<&STDIN', \*CVSOUT, \*CVSOUT, $cvsPath, @ARGV); +$cvsName = $cvsPath; +$cvsName =~ s,.*/(.*)$,\1,; + +# Colorize the output from the cvs program. +while(<CVSOUT>) +{ + chomp; + if (m/^(.) .+/) # S filename + { + print($colors{$1}, $_, color("reset")); + } + elsif (m/warning:/) # warning + { + print($colors{"warning"}, $_, color("reset")); + } + elsif (m/^$cvsName[^:]*: / || m/^cvs server: /) # server message + { + print($colors{"server"}, $_, color("reset")); + } + else # Anything else + { + # Print normally. + print(color("reset"), $_); + } + print "\n"; +} + +# Get the return code of the cvs program and exit with that. +waitpid($cvs_pid, 0); +exit ($? >> 8); diff --git a/scripts/colorcvsrc-sample b/scripts/colorcvsrc-sample new file mode 100644 index 00000000..3b8eeef9 --- /dev/null +++ b/scripts/colorcvsrc-sample @@ -0,0 +1,36 @@ +# Sample .colorcvsrc +# These are the defaults + +# path to the cvs binary +cvs: /usr/bin/cvs + +# Don't do color if our terminal type ($TERM) is one of these. +# (List all terminal types on one line, seperated by whitespace.) +nocolor: dumb + +# The following groups of attributes may be combined for a given color: +# +# clear black on_black +# reset red on_red +# bold green on_green +# underline yellow on_yellow +# underscore blue on_blue +# blink magenta on_magenta +# reverse cyan on_cyan +# concealed white on_whit + +# colors for different types of status messages + +P: reset +U: reset +C: bold red +M: bold yellow +A: cyan +R: cyan +?: bold + +# this is for server messages +server: bold green + +# this is for warnings +warning: bold cyan diff --git a/scripts/colorsvn b/scripts/colorsvn new file mode 100755 index 00000000..f89e1c2f --- /dev/null +++ b/scripts/colorsvn @@ -0,0 +1,201 @@ +#! /usr/bin/env perl + +# colorsvn +# +# based on colorgcc +# +# Requires the ANSIColor module from CPAN. +# +# Usage: +# +# In a directory that occurs in your PATH _before_ the directory +# where svn lives, create a softlink to colorsvn: +# +# svn -> colorsvn +# +# That's it. When "svn" is invoked, colorsvn is run instead. +# +# The default settings can be overridden with ~/.colorcvsrc. +# See the colorcvsrc-sample for more information. +# +# Note: +# +# colorsvn will only emit color codes if: +# +# (1) tts STDOUT is a tty. +# (2) the value of $TERM is not listed in the "nocolor" option. +# (3) the svn command is not a commit or import (as the text editor +# opened by svn will often be hampered by colorsvn). +# +# If colorsvn colorizes the output, svn's STDERR will be +# combined with STDOUT. Otherwise, colorsvn just passes the output from +# svn through without modification. +# +# Copyright 2002 Neil Stevens <neil@qualityassistant.com> +# +# Copyright 1999 Jamie Moyers <jmoyers@geeks.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +use Term::ANSIColor; +use IPC::Open3; + +sub initDefaults +{ + $svnPath = "/usr/bin/svn"; + + $nocolor{"dumb"} = "true"; + + $colors{"P"} = color("reset"); + $colors{"U"} = color("reset"); + $colors{" "} = color("reset"); + $colors{"C"} = color("bold red"); + $colors{"M"} = color("bold yellow"); + $colors{'G'} = color("bold yellow"); + $colors{"A"} = color("cyan"); + $colors{"R"} = color("cyan"); + $colors{"D"} = color("red"); + $colors{"I"} = color("bold"); + $colors{"?"} = color("bold"); + $colors{"!"} = color("bold"); + $colors{"~"} = color("bold red"); + $colors{"server"} = color("bold green"); + $colors{"warning"} = color("bold cyan"); + + # Applies when only the properties changed + $propcolors{"C"} = color("bold red"); + $propcolors{"M"} = color("yellow"); +} + +sub loadPreferences +{ +# Usage: loadPreferences("filename"); + + my($filename) = @_; + + open(PREFS, "<$filename") || return; + + while(<PREFS>) + { + next if (m/^\#.*/); # It's a comment. + next if (!m/(.*):\s*(.*)/); # It's not of the form "foo: bar". + + $option = $1; + $value = $2; + + if ($option =~ /svn/) + { + $svnPath = $value; + } + elsif ($option eq "nocolor") + { + # The nocolor option lists terminal types, separated by + # spaces, not to do color on. + foreach $termtype (split(/\s+/, $value)) + { + $nocolor{$termtype} = "true"; + } + } + elsif ($option =~ /prop (.)/) + { + # Property color + $propcolors{$1} = color($value); + } + else + { + $colors{$option} = color($value); + } + } + close(PREFS); +} + +# +# Main program +# + +# Set up default values for colors and svn path. +initDefaults(); + +# Read the configuration file, if there is one. +$configFile = $ENV{"HOME"} . "/.colorcvsrc"; +if (-f $configFile) +{ + loadPreferences($configFile); +} + +# Get the terminal type. +$terminal = $ENV{"TERM"} || "dumb"; + +$commit = 0; +foreach (@ARGV) +{ + if(/^ci$/ || /^commit$/ || /^import$/ || /^prop/ || /^p[delsg]$/) + { + $commit = 1; + break; + } + elsif (! /^-/) + { + break; + } +} + +# If it's in the list of terminal types not to color, or if +# we're writing to something that's not a tty, don't do color. +if (! -t STDOUT || $commit == 1 || $nocolor{$terminal}) +{ + exec $svnPath, @ARGV + or die("Couldn't exec"); +} + +-f $svnPath or die ("$svnPath not found, add svn=/full/path/to/svn to ~/.colorcvsrc"); + +# Keep the pid of the svn process so we can get its return +# code and use that as our return code. +$svn_pid = open3('<&STDIN', \*SVNOUT, \*SVNOUT, $svnPath, @ARGV); +$svnName = $svnPath; +$svnName =~ s,.*/(.*)$,\1,; + +# Colorize the output from the svn program. +while(<SVNOUT>) +{ + chomp; + if (m/^ (.).+/) # Property changed only + { + print($propcolors{$1}, $_, color("reset")); + } + elsif (m/^(.).+/) # S filename + { + print($colors{$1}, $_, color("reset")); + } + elsif (m/warning:/) # warning + { + print($colors{"warning"}, $_, color("reset")); + } + elsif (m/^$svnName[^:]*: / || m/^svn server: /) # server message + { + print($colors{"server"}, $_, color("reset")); + } + else # Anything else + { + # Print normally. + print(color("reset"), $_); + } + print "\n"; +} + +# Get the return code of the svn program and exit with that. +waitpid($svn_pid, 0); +exit ($? >> 8); diff --git a/scripts/completions/bash/dcop b/scripts/completions/bash/dcop new file mode 100644 index 00000000..675bf6cf --- /dev/null +++ b/scripts/completions/bash/dcop @@ -0,0 +1,52 @@ +# dcop completion +# +# Inputs: +# $1 -- name of the command whose arguments are being completed +# $2 -- word being completed +# $3 -- ord preceding the word being completed +# $COMP_LINE -- current command line +# $COMP_PONT -- cursor position +# $COMP_WORDS -- array containing individual words in the current +# command line +# $COMP_CWORD -- index into ${COMP_WORDS} of the word containing the +# current cursor position +# Output: +# COMPREPLY array variable contains possible completions +# +# dcop syntax: +# dcop [ application [object [function [arg1] [arg2] [arg3] ... ] ] ] +# +_complete_dcop () +{ + local wordlist + + COMPREPLY=() + wordlist="" + + if (( $COMP_CWORD == 1 )); then + # + # Application. This one is easy, just return all names that dcop + # gives us. + # + wordlist=$(dcop) + elif (( $COMP_CWORD == 2 )); then + # + # Object. 'dcop <application>' returns all objects the application + # supports plus (default). The parenthesis in (default) should be + # omitted when using it as an argument so we need to remove them. + # + wordlist=$(dcop ${COMP_WORDS[1]} | sed -e "s,(default),default,") + elif (( $COMP_CWORD == 3 )); then + # + # Function. 'dcop <application> <object>' returns functions of the + # form 'type functionname(arguments)'. We need to return a list with + # the functionnames. + # + wordlist=$(dcop ${COMP_WORDS[1]} ${COMP_WORDS[2]} | sed -e "s,.* \(.*\)(.*,\1,") + fi + + COMPREPLY=( $(compgen -W "$wordlist" "$2") ) + return 0 +} + +complete -F _complete_dcop dcop diff --git a/scripts/completions/zsh/_dcop b/scripts/completions/zsh/_dcop new file mode 100644 index 00000000..c3fe6a50 --- /dev/null +++ b/scripts/completions/zsh/_dcop @@ -0,0 +1,11 @@ +#compdef dcop + +local tmp + +if [ CURRENT -eq 4 ]; then + tmp=(`$words[1,CURRENT-1] 2>/dev/null | sed -e "s,.* \(.*\)(.*,\1,"`) +else + tmp=(`$words[1,CURRENT-1] 2>/dev/null | sed -e "s,(default),default,"`) +fi + +compadd -a tmp diff --git a/scripts/completions/zsh/_kcmshell b/scripts/completions/zsh/_kcmshell new file mode 100644 index 00000000..57f9fc82 --- /dev/null +++ b/scripts/completions/zsh/_kcmshell @@ -0,0 +1,16 @@ +#compdef kcmshell=kcmshell appletproxy=appletproxy + +local i resource tmp dir flags +if [ "$service" = "kcmshell" ]; then + resource="apps"; + dir="/Settings"; + flags=":t:r"; +else + resource="data"; + dir="/kicker/applets"; + flags=":t" +fi +for i in `kde-config --path $resource| sed -e 's/:/ /g'`; do + tmp=($i/$dir/**/*.desktop($flags)) + compadd -a tmp +done diff --git a/scripts/completions/zsh/_kdeinit_wrapper b/scripts/completions/zsh/_kdeinit_wrapper new file mode 100644 index 00000000..a5fd75a0 --- /dev/null +++ b/scripts/completions/zsh/_kdeinit_wrapper @@ -0,0 +1,6 @@ +#compdef kdeinit_wrapper + +# Yes, this could be improved + +_arguments \ + '*::arguments: _normal' diff --git a/scripts/completions/zsh/_kdekillall b/scripts/completions/zsh/_kdekillall new file mode 100644 index 00000000..16ab40dc --- /dev/null +++ b/scripts/completions/zsh/_kdekillall @@ -0,0 +1,8 @@ +#compdef kdekillall + +local progs +progs=(`ps x | grep kdeinit: | grep -v Running | grep -v grep | sed 's,.*kdeinit: ,,' | sed 's, .*,,'`) + +_alternative \ + 'signals:: _signals -p' \ + 'compadd $progs' diff --git a/scripts/completions/zsh/_makeobj b/scripts/completions/zsh/_makeobj new file mode 100644 index 00000000..738a952c --- /dev/null +++ b/scripts/completions/zsh/_makeobj @@ -0,0 +1,30 @@ +#compdef makeobj + +local index olddir dir subdir + +olddir=$PWD +index="$words[(I)-[fCI]]" +if ! ((index)); then + if [ ! -f Makefile ]; then + if [ -n "$OBJ_SUBDIR" ]; then + dir=$PWD + subdir=. + while [ -n "$dir" -a $dir != '/' -a ! -f $dir/$OBJ_SUBDIR/$subdir/Makefile ]; do + dir=$dir(:h) + subdir=$dir(:t)/$subdir + done + if -f $dir/$OBJ_SUBDIR/$subdir/Makefile; then + cd $dir/$OBJ_SUBDIR/$subdir + fi + elif [ -n "$OBJ_REPLACEMENT" ]; then + dir=$(echo $PWD | sed -e "$OBJ_REPLACEMENT") + if [ -f $dir/Makefile ]; then + cd $dir + fi + fi + fi +fi + +_make + +cd $olddir diff --git a/scripts/create_cvsignore b/scripts/create_cvsignore new file mode 100755 index 00000000..2fb4c23e --- /dev/null +++ b/scripts/create_cvsignore @@ -0,0 +1,55 @@ +#!/bin/sh +# This script makes a preliminary .cvsignore in the current dir by +# adding some standard stuff according to Makefile.am. +# License: GPL + +addignore() { + test -f .cvsignore || \ + ( touch .cvsignore && echo "created new .cvsignore" && cvs add .cvsignore ) + grep -q "^$1\$" .cvsignore || \ + ( echo "$1" >> .cvsignore && echo "added $1 to .cvsignore" ) +} + +recurse=0 +if test $# -eq 1; then + if test "$1" = "-r"; then + recurse=1 + fi +fi + +handledir() { + ( + cd $1 + if test -f Makefile.am; then + if test $recurse -eq 1; then + echo "Entering $1" + fi + addignore Makefile + addignore Makefile.in + + bins=`perl -p -e 's/\\\s*\n/ /g' Makefile.am | grep _PROGRAMS | sed -e 's/.*=\s*//;s/#.*//;s/\$([^)]*)//'` + if test -n "$bins"; then + for prog in $bins; do + addignore "$prog" + done + fi + else + echo "Skipping $1" + fi + ) +} + + +if test -f Makefile.am; then + if test $recurse -eq 1; then + find . -type d | grep -v CVS | sed -e 's,/$,,' | \ + while read dir; do + handledir $dir + done + else + handledir . + fi +else + echo "No Makefile.am found!" +fi + diff --git a/scripts/create_makefile b/scripts/create_makefile new file mode 100755 index 00000000..e83b61d7 --- /dev/null +++ b/scripts/create_makefile @@ -0,0 +1,110 @@ +#!/usr/bin/env bash + +# Create Makefile.in and Makefile in a directory (containing a Makefile.am !) +# Saves time compared to re-running configure completely + +if [ $# -ne 1 ]; then + echo "$0 : creates a Makefile from a Makefile.am" + echo + echo "Usage : $0 relativepath/Makefile" + echo "So the argument is the file you want to create." + echo +else + if test -f config.status && test -f configure; then + : + else + if test ! -f Makefile && test -n "$OBJ_SUBDIR"; then + cd $OBJ_SUBDIR + else + if test ! -f Makefile && test -n "$OBJ_REPLACEMENT"; then + objdir=`pwd | sed -e "$OBJ_REPLACEMENT"` + cd $objdir + fi + fi + + if test ! -f Makefile && test -n "$OBJ_SUBDIR"; then + cd $OBJ_SUBDIR + fi + + if test ! -f Makefile; then + echo "$0: in the current directory there is no Makefile" + echo "you will have to run it from the top build dir." + echo "if you do not have a Makefile there - rerun configure" + exit + fi + + fi + + # Handle arg with missing "/Makefile" + relpath=$1 + if test -n "`echo $relpath | grep \/$`"; then + relpath=`echo $relpath | sed 's/\/$//'` + fi + if test -z "`echo $relpath | grep 'Makefile$'`"; then + relpath="$relpath/Makefile" + fi + + # Strip leading ./, otherwise config.status chokes + relpath=`echo "$relpath" | sed -e 's,^\./,,'` + + # Go up to toplevel dir + while test ! -f config.status; do + relpath="`basename $PWD`/$relpath" + cd .. + done + + # Find out top_srcdir. + top_srcdir=`egrep '^top_srcdir *=' Makefile | sed -e "s#top_srcdir *= *##"` + + ( + if cd $top_srcdir ; then + # Check if unsermake or automake was used to create the toplevel Makefile.in + # (the one in $relpath might not exist yet) + if test -n "`sed -n -e '1p' Makefile.in | grep unsermake`"; then + if test -n "`sed -n -e '1p' Makefile.in | grep automake`"; then # old unsermake + if test -z "$UNSERMAKE"; then + echo "unsermake was used to build this module, but \$UNSERMAKE isn't set!" + exit 1 + fi + $UNSERMAKE $relpath + exit 2 + else # new unsermake + UNSERMAKE=`type -p unsermake` + if test ! -x "$UNSERMAKE"; then + echo 'Makefile was created with unsermake, but there' + echo 'is no unsermake in $PATH' + exit 1 + fi + $UNSERMAKE -c $relpath + fi + else + # Suck in AUTOCONF/AUTOMAKE detection code + UNSERMAKE=no + eval `admin/detect-autoconf.pl` + /bin/sh admin/missing --run $AUTOMAKE $relpath || exit + if test -f admin/am_edit; then perl admin/am_edit $relpath.in ;\ + else + if test -f ../admin/am_edit; then perl ../admin/am_edit $relpath.in ; \ + fi + fi + fi + fi + ) + case $? in + 1) + exit 1 + ;; + 2) + createrulesfile="true" + ;; + *) + ;; + esac + if test -f `dirname $relpath`; then + rm `dirname $relpath` + fi + CONFIG_FILES=$relpath CONFIG_HEADERS= ./config.status + if test "$createrulesfile" = "true"; then + CONFIG_FILES="$relpath.rules $relpath.calls" CONFIG_HEADERS= ./config.status + fi +fi diff --git a/scripts/create_makefiles b/scripts/create_makefiles new file mode 100755 index 00000000..955edb90 --- /dev/null +++ b/scripts/create_makefiles @@ -0,0 +1,34 @@ +#!/bin/sh +# Usage : create_makefiles dir +# (to be run from toplevel directory) +# Will re-create all Makefiles in dir and its subdirs +# Needs create_makefile in the path. +# +# David Faure <faure@kde.org> + +if test ! -f Makefile && test -n "$OBJ_REPLACEMENT"; then + objdir=`pwd | sed -e "$OBJ_REPLACEMENT"` + cd $objdir +fi + +if test ! -f Makefile && test -n "$OBJ_SUBDIR"; then + cd $OBJ_SUBDIR +fi + +if test ! -f Makefile; then + echo "$0: in the current directory there is no Makefile" + echo "you will have to run it from the top build dir." + echo "if you do not have a Makefile there - rerun configure" + exit +fi + +srcdir=`egrep '^srcdir *=' Makefile | sed -e "s#srcdir *= *##"` + +( cd $srcdir ; find $1 -type d | sed -e 's,/$,,' ) | \ + while read a; do + if test -f "$srcdir/$a/Makefile.am"; then + test -d "$a" || mkdir -p "$a" + create_makefile "$a/Makefile" + fi + done + diff --git a/scripts/create_svnignore b/scripts/create_svnignore new file mode 100755 index 00000000..fed482fa --- /dev/null +++ b/scripts/create_svnignore @@ -0,0 +1,82 @@ +#!/bin/sh +# This script makes a preliminary svn:ignore in the current dir by +# adding some standard stuff according to Makefile.am. +# License: GPL + +addignore() { + if ! test -f svnignore.tmp; then + svn pg svn:ignore . | sed -e "s, *,," | grep -v '^$' > svnignore.tmp + addedsomething=0 + fi + if ! grep -q "^$1\$" svnignore.tmp; then + echo "$1" >> svnignore.tmp && echo "added $1 to svn:ignore" + sort -u -o svnignore.tmp svnignore.tmp + addedsomething=1 + fi +} + +recurse=0 +if test $# -eq 1; then + if test "$1" = "-r"; then + recurse=1 + fi +fi + +handledir() { + ( + cd $1 + trap "rm svnignore.tmp" 1 2 15 + if test -f Makefile.am; then + if test $recurse -eq 1; then + echo "Entering $1" + fi + addignore Makefile + addignore Makefile.in + + bins=`perl -p -e 's/\\\s*\n/ /g' Makefile.am | egrep '_PROGRAMS|_LTLIBRARIES|_LIBRARIES' | sed -e 's/.*=\s*//;s/#.*//;s/\$([^)]*)//'` + if test -n "$bins"; then + addignore ".libs" + addignore ".deps" + for prog in $bins; do + addignore "$prog" + done + fi + grep -q LIBRARIES Makefile.am && addignore ".libs" + grep -q METASOURCES Makefile.am && addignore "*.moc" + fgrep -q .skel Makefile.am && addignore "*.kidl" + fgrep -q .skel Makefile.am && addignore "*_skel.c*" + fgrep -q .stub Makefile.am && addignore "*_stub.cpp" + if fgrep -q .ui Makefile.am; then + uis=`ls -1 *.ui 2>/dev/null` + for ui in $uis; do + addignore ${ui/.ui/.h} + addignore ${ui/.ui/.cpp} + done + fi + + grep -q "^include.*/Doxyfile.am$" Makefile.am && addignore "Doxyfile" + + if test "$addedsomething" = 1; then + svn propset svn:ignore -F svnignore.tmp . + fi + rm svnignore.tmp + else + echo "Skipping $1" + fi + ) +} + + +if test -f Makefile.am; then + if test $recurse -eq 1; then + find . -type d | egrep -v 'CVS|.svn' | sed -e 's,/$,,' | \ + while read dir; do + handledir $dir + done + else + handledir . + fi +else + echo "No Makefile.am found!" +fi + diff --git a/scripts/cvs-clean b/scripts/cvs-clean new file mode 100755 index 00000000..f6ae254d --- /dev/null +++ b/scripts/cvs-clean @@ -0,0 +1,90 @@ +#! /usr/bin/env perl + +# +# This script recursively (beginning with the current directory) +# wipes out everything not registered in CVS. +# +# written by Oswald Buddenhagen <ossi@kde.org> +# inspired by the "old" cvs-clean target from Makefile.common +# +# This file is free software in terms of the modified BSD licence. +# See kdelibs/doc/common/bsd-license.html for the exact conditions. +# + +use File::Path; + +my $dry_run = 0; + +sub newfiles() +{ + my ($indir, $incvs) = @_; + for my $n (keys (%$incvs)) { delete $$indir{$n} } + return sort (keys (%$indir)); +} + +sub cvsclean() +{ + my $dir = shift; + my (%dirsdir, %filesdir, %dirscvs, %filescvs); + my $dnam = $dir ? $dir : "."; + if (!opendir (DIR, $dnam)) { + print STDERR "Cannot enter \"".$dnam."\".\n"; + return; + } + for my $fn (grep (!/^\.\.?$/, readdir (DIR))) { + if (-d $dir.$fn) { + $fn eq "CVS" or $dirsdir{$fn} = 1; + } else { + $filesdir{$fn} = 1; + } + } + closedir (DIR); + if (!open (FILE, "<".$dir."CVS/Entries")) { + print STDERR "No CVS information in \"".$dnam."\".\n"; + return; + } + while (<FILE>) { + m%^D/([^/]+)/.*$% and $dirscvs{$1} = 1; + m%^/([^/]+)/.*$% and $filescvs{$1} = 1; + } + close (FILE); + if (open (FILE, "<".$dir."CVS/Entries.Log")) { + while (<FILE>) { + m%^A D/([^/]+)/.*$% and $dirscvs{$1} = 1; + m%^A /([^/]+)/.*$% and $filescvs{$1} = 1; + m%^R D/([^/]+)/.*$% and delete $dirscvs{$1}; + m%^R /([^/]+)/.*$% and delete $filescvs{$1}; + } + close (FILE); + } + for my $fn (&newfiles (\%filesdir, \%filescvs)) { + print ("F ".$dir.$fn."\n"); + unlink($dir.$fn) unless $dry_run; + } + for my $fn (&newfiles (\%dirsdir, \%dirscvs)) { + print ("D ".$dir.$fn."\n"); + rmtree($dir.$fn, 0, 0) unless $dry_run; + } + for my $fn (sort (keys (%dirscvs))) { + &cvsclean ($dir.$fn."/"); + } +} + +my $usage = + "usage: cvs-clean [options]\n". + " --help | -h print usage information\n". + " --dry-run | -n print intended actions; don't change filesystem\n"; + +foreach my $arg (@ARGV) { + if ($arg eq '-h' || $arg eq '--help') { + print $usage; + exit (0); + } elsif ($arg eq '-n' || $arg eq '--dry-run') { + $dry_run = 1; + } else { + print STDERR "cvs-clean: unknown argument '".$arg."'\n\n".$usage; + exit (1); + } +} + +&cvsclean (""); diff --git a/scripts/cvs2dist b/scripts/cvs2dist new file mode 100755 index 00000000..dba8a4d9 --- /dev/null +++ b/scripts/cvs2dist @@ -0,0 +1,626 @@ +#! /usr/bin/env bash + +# This is cvs2dist +# Webpage: http://www.katzbrown.com/shiritsu/programming/cvs2dist/ +# Newest version is always available there! +# Please report bugs to <jason@katzbrown.com>. + +# Original author (of cvs2pack.sh) was Sebastian Stein <seb.stein@hpfsc.de> +# Heavy, heavy modifications by Jason Katz-Brown <jason@katzbrown.com> +# Some modifications for i18n inclusion by Dominique Devriese <devriese@kde.org> +# Added --no-i18n-lang and --replace-files by Michael Buesch <mbuesch@freenet.de> +# License: GPL (http://www.gnu.org/) +# Last modification: 2004/10/13 + +cmdline="$@" + +returndir=`pwd` +override="README ChangeLog INSTALL AUTHORS AUTHOR COPYING COPYING.LIB TODO" +remove="config.cache config.log config.status Makefile configure inst-apps CVS acinclude.m4 aclocal.m4 config.h config.h.bot config.h.in configure.files libtool stamp-h stamp-h.in stamp-h1 subdirs *.moc *.la .libs .deps .cvsignore autom4te.cache {arch} .arch-ids" +toplevelremove="configure.in.bot" +# whitespace seperated list of languages to never include. +always_skip_languages="xx" + + +exit_cleanup() +{ + echo -n "Cleaning up... " + if [ -d $temp_dir ]; then + test -z "$debug" && rm -Rf $temp_dir + fi + echo "done." +} + +trap "exit_cleanup; exit 1" SIGINT SIGTERM + +test -e ~/.cvs2distrc && extraoptions=`cat ~/.cvs2distrc` + +# getopt usage from the getopt bash example +# --log has optional argument +TEMP=`getopt \ +-o v:n:r:e:a:B:dhmbgol \ +--long log::,version:,name:,required-header:,required-header-error-message:,make-unpackaged,help,no-bz2,no-bzip2,no-gzip,only-directory,remove-hidden,admin-dir:,branch:,no-i18n,no-i18n-lang:,cvs-root:,debug,replace-files: \ +-n cvs2dist -- $extraoptions "$@"` + +if [ $? != 0 ]; then + echo "Aborted." >&2 + exit 1 +fi + +eval set -- "$TEMP" + +log="/dev/null" +calclog=0 +doi18n="yes" +noi18nlang="" +replace_files="" +cvsroot="" +debug="" + +while true; do + case "$1" in + -v|--version) version=$2; shift 2 ;; + -n|--name) name=$2; shift 2 ;; + -a|--admin-dir) admindir=$2; + if [ `echo $admindir | sed -e 's#^/##'` = $admindir ]; then + admindir="`pwd`/$admindir" + fi + shift 2 ;; + -B|--branch) branch="-r$2"; shift 2;; + --debug) debug="non-empty"; shift 1 ;; + --cvs-root) cvsroot="$2"; shift 2 ;; + -r|--required-header) requiredheader=$2; shift 2 ;; + --no-i18n) doi18n="no"; shift 1 ;; + --no-i18n-lang) noi18nlang="$2"; shift 2 ;; + -e|--required-header-error-message) requiredmsg=$2; shift 2 ;; + -m|--make-unpackaged) leavedir="non-empty"; shift 1 ;; + -h|--help) showhelp="non-empty"; shift 1 ;; + -b|--no-bz2|--no-bzip2) nobzip2="non-empty"; shift 1 ;; + -o|--only-directory) + nogzip="non-empty" + nobzip2="non-empty" + leavedir="non-empty" + shift 1 ;; + -g|--no-gzip) nogzip="non-empty"; shift 1 ;; + -d|--remove-hidden) removehidden="non-empty"; shift 1 ;; + -l) calclog=1; shift 1 ;; + --log) + case "$2" in + # no-argument case + "") calclog=1; shift 2 ;; + # something, should be a file + *) log=$2 + origlog=$log + if [ `echo $log | sed -e 's#^/##'` = $log ]; then + log="`pwd`/$log" + fi + + shift 2 ;; + esac ;; + --replace-files) replace_files="$2"; shift 2 ;; + --) shift + break ;; + *) echo "Aborted." + exit 1 ;; + esac +done + +count=0 +for arg do + test $count = 0 && module=$arg + test $count = 1 && directory=$arg + + if [ $count -ge 2 ]; then + modarg=$arg + if [ `echo $modarg | sed -e 's#^/##'` = $modarg ]; then + modarg="`pwd`/$modarg" + fi + addfiles="$addfiles $modarg" + fi + + let count count++ +done + +# test if a module and directory name was given +if [ ! -z $showhelp ] || [ -z $module ] || [ -z $directory ]; then + echo "Usage: cvs2dist module directory [options] [addfile1] [addfile2] ..." + echo "" + echo " -n --name <name>" + echo " -v --version <version>" + echo " --cvs-root <root> the value to use as cvs root" + echo " variable. It is not necessary if you use --no-i18n." + echo " if this is not given, it is taken from the CVSROOT " + echo " environment variable." + echo " --admin-dir <dir> admin/ location (default is module/admin)" + echo " (symbolic links are OK.)" + echo " -B --branch <branch> use branch for i18n checkouts." + echo " --no-i18n don't try to automatically checkout the translations from cvs." + echo " --no-i18n-lang <languages> exclude all languages in the given comma" + echo " seperated list. example:" + echo " --no-i18n-lang uk,de,en_GB" + echo " --log=<logfile> If logfile unspecified, default file is used." + echo " (The '=' is essential and may not be ommited" + echo " when specifying the logfile.)" + echo " -l Log to default logfile." + echo " -m --make-unpackaged Also makes an unpacked distribution" + echo " in the current directory." + echo " -g --no-gzip Do not create gzip package." + echo " -b --no-bz2 Do not create bzip2 package." + echo " --no-bzip2 Alias for the above." + echo " -o --only-directory Alias for -mbg (no packages, only a directory.)" + echo " -r --required-header <header> Errors if header is not installed." + echo " -e --required-header-error-message <message>" + echo " Error message for above." + echo " -d --remove-hidden Remove hidden files/directories from packages" + echo " --replace-files <file-pair-list>" + echo " <file-pair-list> is a comma separated list of file pairs" + echo " which should be replaced in the final distribution package." + echo " Each element of a pair is separated by an @" + echo -n " Example: --replace-files take_this_file@and_move_it_here," + echo "configure.in.bot.dist@configure.in.bot" + echo " The filenames are all relative to your package root." + echo " Please be careful! Try to avoid the usage of .. in the path. It" + echo " may break stuff! There can not be blank characters in the paths." + echo " -h --help Show this help" + echo "" + echo " Name defaults to the last part of the directory." + echo "By default, creates name[-version].tar.gz if gzip is installed" + echo "and/or name[-version].tar.bz2 if bzip2 is installed in the current" + echo "directory. Removes all temporary files it creates. Produces" + echo "tarballs that are standard distribution tarballs with a" + echo "configure script." + echo " Unless --no-i18n is given, it automatically tries to check out " + echo "strings and documentation translation from cvs." + echo " Arguments after the second are added to the toplevel directory" + echo "in the package. Short options can be combined, eg -dm to create" + echo "a directory and remove hidden files. ~/.cvs2distrc is added to" + echo "the beginning of command line arguments if it exists." + echo " '--' signifies the end of options." + echo "" + echo "Example: cvs2dist /sources/kdegames kolf/objects/picture \\" + echo " -n kolf-picture -v 0.9 -r \"kolf/game.h\" \\" + echo " --log ~/tmp/extra-file" + echo "" + echo " Creates packages of the kolf picture plugin, naming the" + echo " packages kolf-picture-0.9 and logging the process. For configure" + echo " to succeed, kolf/game.h must be installed or an error will occur." + echo " ~/tmp/extra-file is added to the packages." + echo "" + echo "Webpage: http://www.katzbrown.com/shiritsu/programming/cvs2dist/" + echo "Authors: Jason Katz-Brown <jason@katzbrown.com>," + echo " Sebastian Stein <seb.stein@hpfsc.de>," + echo " Dominique Devriese <devriese@kde.org>" + exit 1 +fi + +# expand module +module=`echo $module | sed -e 's#/$##'` +if [ `echo $module | sed -e 's#^/##'` = $module ]; then + module="`pwd`/$module" +fi + +# test if the given module is a directory +test -d $module +if [ $? -ne 0 ]; then + echo "$module is not a directory." + echo "Aborted." + exit 1 +fi + +# go to our module +cd $module + +directory=`echo $directory | sed -e 's#^/##'` + +if [ -z $name ]; then + name=$directory + # get rid of trailing slash + name=`echo $name | sed -e 's#/$##'` + # leading slash + name=`echo $name | sed -e 's#^/##'` + + if [ `echo $name | sed -e 's#/##'` != $name ]; then + name=`echo $name | sed -e 's#^.*/##'` + fi +fi + +test $calclog = 1 && log="$returndir/cvs2dist-$name.log" && origlog="cvs2dist-$name.log" + +# test if the given name is a sub-directory +if [ ! -d "$directory" ]; then + echo "$directory is not a sub-directory of $module." + echo "Aborted." + exit 1 +fi + +test $log != "/dev/null" && echo "Logging to $log." + +echo "cvs2dist log on "`date` > $log +echo "http://katzbrown.com/shiritsu/programming/cvs2dist/" >> $log +echo -n "Module: $module; Directory: $directory; Name: $name; " >> $log +if [ -z $version ]; then + echo "Version unspecified." >> $log +else + echo "Version $version." >> $log +fi +echo $cmdline >> $log +echo "--------" >> $log + +if [ -z $version ]; then + filename=$name +else + filename="$name-$version" +fi + +if [ -z $cvsroot ]; then + cvsroot="$CVSROOT"; +fi +if [ $doi18n = "yes" ]; then + # a little warning... + echo "Will try to fetch i18n files from KDE's CVS." + echo "If this doesn't work, use --no-i18n." + + if [ -z "$cvsroot" ]; then + echo "No cvs root specified, CVSROOT env var is empty, " >> $log + echo "and --no-i18n option is not given.." >> $log + echo "Using anonymous cvs.." >> $log + cvsroot=":pserver:anonymous@anoncvs.kde.org:/home/kde" + # append an entry to ~/.cvspass so the user will not be asked + # for a pwd. Thanks to coolo for the idea.. + if ! grep "anoncvs.kde.org" ~/.cvspass >/dev/null 2>&1; then + echo "/1 :pserver:anonymous@anoncvs.kde.org:2401/home/kde A" >> ~/.cvspass + fi + fi +fi + +# the temporary directory +temp_dir="$module/cvs2dist-tmp" +temp_dist="$temp_dir/$filename" + +echo "Temporary directory is $temp_dir." >> $log + +# make a temporary directory +test -d $temp_dir && rm -Rf $temp_dir + +mkdir -p $temp_dist + +# check if we were able to create temp_dir +test -d $temp_dist +if [ $? -ne 0 ]; then + echo "Could not create temporary directory $temp_dist." + echo "$temp_dist could not be created." >> $log + echo "Aborted." + exit 1 +fi + +test -z "$requiredmsg" && requiredmsg="Install development package needed first! $requiredheader, for one, is missing." + +### configure.in.in +if [ ! -z $requiredheader ]; then + naiyou="KDE_CHECK_HEADER( +$requiredheader, +[], +[AC_MSG_ERROR(\"$requiredmsg\")] +)" + echo $naiyou > $temp_dir/configure.in.in + echo "configure.in.in contents: " >> $log + echo "--------" >> $log + echo $naiyou >> $log + appaddfiles="$appaddfiles $temp_dir/configure.in.in" +fi + +# copy all files of the module to temp_dir/name +cp -RL $module/$directory $temp_dist/$name + +echo "cp -R $module/$directory $temp_dist/$name" >> $log + +modulename="$module" +# get rid of trailing slash +modulename=`echo $modulename | sed -e 's#/$##'` +# get the last part +modulename=`echo $modulename | sed -e 's#^.*/##'` + +remove="$remove $modulename.lsm" + +# we check out kde-i18n/subdirs in temp_dir/kde-i18n.. +if [ $doi18n = "yes" ]; then + pushd $temp_dir + echo "cvs co kde-i18n/subdirs" >> $log + cvs -z4 -q -d "$cvsroot" co $branch -P kde-i18n/subdirs > /dev/null 2>&1 + i18nlangs_tmp="$(cat kde-i18n/subdirs)" + skiplist="`echo $noi18nlang | sed -e 's/,/ /g'`" + skiplist="$skiplist $always_skip_languages" + for lang in $i18nlangs_tmp; do + must_skip="no" + for skip in $skiplist; do + if [ "$lang" = "$skip" ]; then + must_skip="yes" + fi + done + if [ "$must_skip" = "no" ]; then + i18nlangs="$i18nlangs $lang" + fi + done + echo "available languages: $i18nlangs" >> $log + popd +fi + +# if a handbook exists, we also copy it to the directory +if [ -d $module/doc/$name ]; then + mkdir -p $temp_dist/doc/$name + cp -Rf $module/doc/$name $temp_dist/doc + find $module/doc/ -maxdepth 1 ! -xtype d | xargs --replace={} cp {} $temp_dist/doc + + if [ $doi18n = "yes" ]; then + pushd $temp_dir + for lang in $i18nlangs; do + test -d $temp_dist/doc/$lang && rm -Rf $temp_dist/doc/$lang + docdirname="kde-i18n/$lang/docs/$modulename/$name" + echo "cvs co $docdirname" >> $log + cvs -z4 -q -d "$cvsroot" co $branch -P "$docdirname" > /dev/null 2>&1 + if [ ! -d "$docdirname" ]; then + echo "$lang's $name documentation does not exist." >> $log + continue + fi + echo -n "Copying $lang's $name documentation over... " + cp -R $docdirname $temp_dist/doc/$lang + # we don't want KDE_DOCS = AUTO, cause that makes the + # build system assume that the name of the app is the + # same as the name of the dir the Makefile.am is in. + # Instead, we explicitly pass the name.. + echo "KDE_LANG=$lang" > $temp_dist/doc/$lang/Makefile.am + echo "KDE_DOCS=$name" >> $temp_dist/doc/$lang/Makefile.am + echo "done." + echo "$lang documentation included." >> $log + done + popd + fi +fi + +# clean up doc directory +if [ -d $temp_dist/doc/$name ]; then + pushd $temp_dist/doc/$name + echo -n "make clean in $temp_dist/doc/$name/... " + echo >> $log + echo "make clean in $temp_dist/doc/$name/" >> $log + make clean >> $log + echo "--------" >> $log + echo "done." + popd +fi + +if [ $doi18n = "yes" ]; then + test -d $temp_dist/po && rm -Rf $temp_dist/po + mkdir $temp_dist/po + + pushd $temp_dir/ + for lang in $i18nlangs; do + pofilename="kde-i18n/$lang/messages/$modulename/$name.po"; + echo "cvs co $pofilename" >> $log + cvs -z4 -q -d "$cvsroot" co $branch -P "$pofilename" > /dev/null 2>&1 + if [ ! -f "$pofilename" ]; then + echo "$lang's $name.po does not exist." >> $log + continue + fi + + dest=$temp_dist/po/$lang + mkdir $dest + echo -n "Copying $lang's $name.po over... " + echo "$lang's $name.po file included." >> $log + cp $pofilename $dest + echo "done." + + echo "KDE_LANG = $lang +SUBDIRS = \$(AUTODIRS) +POFILES = AUTO" > $dest/Makefile.am + + subdirs="non_empty" + done + + if [ -z "$subdirs" ]; then + rm -Rf $temp_dist/po + else + echo "SUBDIRS = \$(AUTODIRS)" > $temp_dist/po/Makefile.am + fi +fi + +# copy the admin directory +if [ -z $admindir ]; then + cp -pRL $module/admin $temp_dist + echo "cp -pRL $module/admin $temp_dist" >> $log +else + cp -pRL $admindir $temp_dist + echo "cp -pRL $admindir $temp_dist" >> $log +fi + +# and all files from the base dir, except directories +echo "Copying over files from the module directory:" >> $log +find $module ! -xtype d -maxdepth 1 | xargs --verbose --replace={} cp {} $temp_dist 2>> $log +echo "--------" >> $log + +# we now enter the temp_dist and delete all unwanted files +# and add wanted files +cd $temp_dist + +# override top-level files +echo "Override files: " >> $log +for file in $override; do + test -e $temp_dist/$name/$file && mv $temp_dist/$name/$file . && echo "mv $temp_dist/$name/$file ." >> $log +done + +test ! -z "$addfiles" && echo "Addfiles: " >> $log +for file in $addfiles; do + test -e $file && cp -R $file $temp_dist && echo "cp -R $file $temp_dist" >> $log +done + +test ! -z "$appaddfiles" && echo "Application addfiles: " >> $log +for file in $appaddfiles; do + test -e $file && cp -R $file $temp_dist/$name/ && echo "cp -R $file $temp_dist/$name/" >> $log +done + +echo "--------" >> $log + +# replace all user requested files +if [ -n "$replace_files" ]; then + echo "Replace user requested files" >> $log + pair_list="`echo $replace_files | sed -e 's/,/ /g'`" + for pair in $pair_list; do + pair_tmp="`echo $pair | sed -e 's/@/ /g'`" + from="`echo $pair_tmp | awk '//{print $1}'`" + to="`echo $pair_tmp | awk '//{print $2}'`" + if [ -z "$from" ] || [ -z "$to" ]; then + echo "bogus pair \"$from@$to\"" >> $log + continue + fi + echo "Replacing \"$to\" by \"$from\"" >> $log + from_path="$temp_dist/$name/$from" + to_path="$temp_dist/$name/$to" + if [ ! -f "$from_path" ]; then + echo "$from_path does not exist!" >> $log + echo "" + echo "Warning: \"$from\" does not exist!" + echo -n "Please enter the path in --replace-files relative " + echo "to the package root of your project." + echo "Your package root is: \"$module/$directory\"" + echo "" + continue + fi + rm -f "$to_path" && \ + mv "$from_path" "$to_path" + if [ $? -ne 0 ]; then + echo -n "Moving \"$from_path\" failed! " >> $log + echo -n "This should not happen." >> $log + if [ -f "$to_path" ]; then + echo "" + else + echo " No \"$to\" will exist in the archive!" >> $log + fi + fi + done + echo "--------" >> $log +fi + +# version file, if it doesn't exist +test ! -z $version && test ! -e VERSION && echo "$name version $version" > VERSION + +cd $temp_dist/$name +echo "make clean in $temp_dist/$name/:" >> $log +echo "" >> $log +echo -n "make clean in $temp_dist/$name/... " +make clean >> $log +echo "--------" >> $log +echo "done." + +cd $temp_dist + +# remove files +echo "Remove files: " >> $log +for file in $remove; do + find . -name $file | xargs rm -Rf + echo "find . -name $file | xargs rm -Rf" >> $log +done + +# remove more files +echo "Remove toplevel files: " >> $log +for file in $toplevelremove; do + test -e $file && rm -Rf $file && echo "rm -Rf $file" >> $log +done +unset file + +# remove hidden files +test ! -z $removehidden && echo "Remove hidden files: " >> $log && find $temp_dist -name ".*" -and ! -name "." | xargs --verbose rm -Rf 2>> $log + +echo "--------" >> $log + +cd $temp_dist + +# create the configure script +# working directory is $temp_dist +echo "make -f Makefile.cvs in $temp_dist/:" >> $log +echo "" >> $log +echo -n "make -f Makefile.cvs in $temp_dist/... " +make -f Makefile.cvs >> $log 2>> $log +echo "rm Makefile.cvs" >> $log +rm -f Makefile.cvs +echo "rm autom4te.cache" >> $log +rm -Rf autom4te.cache +echo "--------" >> $log +echo "done." + +echo "Directory will be $filename." + +# play around with our tar file in temp_dir +cd $temp_dir + +if [ ! -z $leavedir ]; then + test -e $returndir/$filename && rm -Rf $returndir/$filename + cp -R $filename $returndir +fi + +# make a tar of temp_dist +if [ -z $nogzip ] || [ -z $nobzip2 ]; then + echo -n "Tarring... " + echo "tar cf $filename.tar $filename" >> $log + tar cf $filename.tar $filename >> $log + echo "done." +fi + +if [ -z $nogzip ] && [ ! -z `which gzip 2> /dev/null` ]; then + cp $filename.tar $filename.tar.tmp + echo -n "running gzip... " + echo "gzip $filename.tar" >> $log + gzip $filename.tar + echo "done." + mv $filename.tar.tmp $filename.tar + mv $filename.tar.gz $returndir + echo "mv $filename.tar.gz $returndir" >> $log +fi +if [ -z $nobzip2 ] && [ ! -z `which bzip2 2> /dev/null` ]; then + echo -n "running bzip2... " + echo "bzip2 $filename.tar" >> $log + bzip2 $filename.tar + echo "done." + mv $filename.tar.bz2 $returndir + echo "mv $filename.tar.bz2 $returndir" >> $log +fi + +test -e $filename.tar && rm -f $filename.tar + +# cleanup all tempoaries +exit_cleanup + +cd $returndir + +test -z $leavedir && test ! -z $nobzip2 && test ! -z $nogzip && echo "Finished - no created files." && exit 1 + +# cool, everything went ok! +if [ -z $leavedir ]; then + echo "Finished. Created packages:" +else + if [ -z $nogzip ] || [ -z $nobzip2 ]; then + echo "Finished. Created packages/directories:" + else + echo "Finished. Created directory:" + fi +fi + +echo "--------" >> $log +echo "Done: " >> $log +echo "Files are in `pwd`." >> $log + +if [ ! -z $leavedir ] && [ -d $filename ]; then + ls -ld $filename + ls -ld $filename >> $log +fi +if [ -z $nogzip ] && [ -e $filename.tar.gz ]; then + ls -l $filename.tar.gz + ls -l $filename.tar.gz >> $log +fi +if [ -z $nobzip2 ] && [ -e $filename.tar.bz2 ]; then + ls -l $filename.tar.bz2 + ls -l $filename.tar.bz2 >> $log +fi +if [ $log != "/dev/null" ]; then + echo "Created log:" + ls -l $origlog +fi diff --git a/scripts/cvsaddcurrentdir b/scripts/cvsaddcurrentdir new file mode 100755 index 00000000..56185f27 --- /dev/null +++ b/scripts/cvsaddcurrentdir @@ -0,0 +1,30 @@ +#!/bin/sh +#Alexander Neundorf <neundorf@kde.org> +#copyright 2002, GPL + +#call this script to add all files in and below the current dir to cvs +#it adds *.c, *.h, *.C, *.cpp, *.cc automatically +#*~, *.o, *.so, *.lo, *.la, .libs/, .deps/, .#* are ignored +#it asks for the remaining files + + +#ignore dirs "CVS", ".deps", ".libs" +#ignore files *.o, *.so, *.lo, *.la, *~, .#* +FOUND=`find |grep -v "^\.$"| grep -v CVS| grep -v "\.[ls]\?o$"|grep -v "~$"|grep -v "\.libs/"|grep -v "\.deps/" |grep -v "\.depend/"| grep -v "/\.#" |grep -v "\.la$"` +#echo $FOUND + +ask_for_adding() { +echo +read -p "Add file $file to cvs ? (y/n) " answer rest +#if [ "$answer" != "y" ]; then echo $file; fi +if [ "$answer" == "y" ]; then cvs add $file; fi +} + + +for file in $FOUND +do +#matches all *.h, *.c, *.cpp, *.C, *.cpp, *.cc (and some others too) + echo $file | grep "\.[cCh][cp]\?p\?$" && cvs add $file + echo $file | grep -v "\.[cCh][cp]\?p\?$" && ask_for_adding +done + diff --git a/scripts/cvsbackport b/scripts/cvsbackport new file mode 100755 index 00000000..085b27ae --- /dev/null +++ b/scripts/cvsbackport @@ -0,0 +1,32 @@ +#!/bin/sh +# Backport the last change in HEAD, to a branch. +# Usage: cvsbackport <files> +# WARNING: the branch tag is hardcoded into the script, make sure to check it! +# +# Initial author: Dirk Mueller +# Support for multiple command-line arguments: David Faure + +BRANCH=KDE_3_4_BRANCH +echo "Backporting to $BRANCH" +TMPFILE=`mktemp cvsbackport.XXXXXX` || exit 1 +files=$* +until test $# -eq 0; do + + echo "looking for last change to $1..." + CVSLASTCHANGE_KEEP_WHITESPACE=1 cvslastchange $1 > $TMPFILE + echo "browsing last change to $1..." + less $TMPFILE + cvs up -r$BRANCH $1 + patch < $TMPFILE + rm -f $TMPFILE + echo "showing diff for $1..." + cvs diff $1 | less + + shift +done + +echo "Press ENTER now to commit ($files) or Ctrl+C to abort" +read confirm + +cvs commit $files +cvs up -A $files diff --git a/scripts/cvsblame b/scripts/cvsblame new file mode 100755 index 00000000..bd3635ed --- /dev/null +++ b/scripts/cvsblame @@ -0,0 +1,252 @@ +#! /usr/bin/env perl + +# cvs blame inspired by Bonsai +# Author: Bernd Gehrmann <bernd@physik.hu-berlin.de> + +=head1 NAME + +cvsblame - Shows a blame-annotated representation of a CVS controlled file in Konqueror. + +=head1 SYNOPSIS + +cvsblame <filename> + +=head1 DESCRIPTION + +cvsblame opens Konqueror to display the output of cvs annotate of +a cvs controlled file. When the mouse is on a revision number shown +in the second column, a popup with the respective log message +appears. + +In the popup, a proper mailto: link to the author of a revision +can be created as follows: In your home directory, make a file +.cvsblame. In that file, enter for each repository you are working +with a line like + + accounts :pserver:gehrmab@cvs.kde.org:/home/kde /home/bernd/.kdeaccounts + +where the accounts file contains a simple list of cvs usernames in +the first column and the respective mail address in the second. + +=head1 BUGS + +=over 4 + +=item Does not really work for filenames which are not in the current directory + +=item Is a hack. Really. + +=back + +=head1 AUTHOR + +Bernd Gehrmann <bernd@physik.hu-berlin.de> + +=cut + +$file = $ARGV[0]; +$outputfile = `kde-config --path tmp` || './#'; # if we put the file in the cwd, then we keep a '#' at the beggining to help CVS ignore it +($outputfile) = split(/:/,$outputfile); +chomp $outputfile; +$outputfile .= "cvsblame.$$.html"; +$configfile = $ENV{HOME}. "/.cvsblame"; +$rootfile = "`pwd`/CVS/Root"; +$cvsroot = `cat "$rootfile"`; +chop $cvsroot; + +# +# Look for a username -> mail address mapping +# + +if (open(CONFIG, $configfile)) { + while (<CONFIG>) { + if (/accounts\s*([^\s]*)\s+([^\s]*)/) { + if ($1 eq $cvsroot) { + $accountfile = $2; + } + } + } + close CONFIG; +} +if ($accountfile) { + open(ACCOUNTS, $accountfile) || die "Account file not found: $accountfile"; + while (<ACCOUNTS>) { + if (/([^\s]*)\s+([^\s].*[^\s])\s+([^\s]+)/) { + $mail{$1} = "$2 <$3>"; + } + elsif (/([^\s]*)\s+([^\s]*)/) { + $mail{$1} = $2; + } + } +} + + +# +# The real work, first the html header +# + + +open(OUTPUT, ">$outputfile"); +print OUTPUT <<EOF; +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + <head> + <title>Blame annotation for $file</title> + </head> + <script type="text/javascript"> + function hidelog(event) { + var target = event.relatedTarget; + while (target && target.id != "popup") + target = target.offsetParent; + if (target) + return; + target = event.target; + while (target.id != "popup") + target = target.offsetParent; + target.style.visibility = "hidden"; + } + function init() { + document.getElementById("popup").addEventListener("mouseout", hidelog, false); + } + function poplog(target, rev) { + var popup = document.getElementById("popup"); + var x = 120, y = 0; + while (target && target != document) + { + x += target.offsetLeft; + y += target.offsetTop; + target = target.offsetParent; + } + popup.style.pixelLeft = x; + popup.style.pixelTop = y; + popup.innerHTML = rev; + popup.style.visibility = "visible"; + return true; + } +EOF + +# +# Translate information from cvs log in javascript stuff +# + +$revision = ""; +open (LOG, "cvs log \"$file\"|"); +while (<LOG>) { + chop; + $line = $_; + if ($line =~ /^revision (.*)/) { + $revision = $1; + $revstr = "log$revision"; + $revstr =~ s/\./_/g; + } elsif ($line =~ /date: ([^;]*);\s*author: ([^;]*);.*/) { + $date = $1; + $author = $2; + if ($mail{$author}) { + $author = "<a href=\\\"mailto:$mail{$author}\\\">$author</a>"; + } + $content = "<b>$revision</b> $author <b>$date<b>"; + } elsif ($line eq "----------------------------" && !($revision eq "")) { + print OUTPUT "var $revstr = \"$content\";\n"; + } elsif ($line eq "=============================================================================" && !($revision eq "")) { + print OUTPUT "var $revstr = \"$content\";\n"; + } else { + $line =~ s/\"/\\\"/g; + $line =~ s/&/&/g; + $line =~ s/</</g; + $line =~ s/>/>/g; + $content = "$content<br>$line"; + } +} +close LOG; + +print OUTPUT <<EOF; + </script> + <style type="text/css"> + body { + background: #eeeee0; + } + #popup { + position: absolute; + background: #ffcc99; + border: 1px solid #80664D; + padding: 2px; + } + a:link { + text-decoration: none; + } + a:hover { + text-decoration: underline; + } + </style> + <body text="#000000" onload="init()"> + <h1>$file</h1> + <table border=0 cellpadding=0 cellspacing=0 width="100%"> +EOF + +# +# Information from cvs annotate +# + +$color = 1; +$lineno = 1; +$oldrevision = ""; +$oldlineno = ""; +$oldrevstr = ""; +open (ANNOTATE, "cvs annotate \"$file\" 2>/dev/null|"); +while (<ANNOTATE>) { + chop; + $line = $_; + $revision = substr $line, 0, 13; + $revision =~ s/\s//g; + $author = substr $line, 14, 9; + $author =~ s/\s//g; + $date = substr $line, 23, 9; + $content = substr $line, 35; + $content =~ s/\&/&/g; + $content =~ s/\</</g; + $content =~ s/\>/>/g; + $revstr = "log$revision"; + $revstr =~ s/\./_/g; + if ($revision eq $oldrevision) { + if ($lineno == $oldlineno+20) { + $linkstr = "<span onmouseover=\"return poplog(this, $revstr)\"'>"; + $linkendstr = "</span>"; + $revauthor = "$author $revision"; + $oldlineno = $lineno; + } else { + $linkstr = ""; + $linkendstr = ""; + $revauthor = ""; + } + } else { + $color = ($color == 0)? 1 : 0; + $linkstr = "<span onmouseover=\"return poplog(this, $revstr)\"'>"; + $linkendstr = "</span>"; + $revauthor = "$author $revision"; + $oldlineno = $lineno; + $oldrevision = $revision; + } + print OUTPUT "<tr><td nowrap style=\"background: ", ($color==1)? "#EEEEE0" : "#FFFFCC", "\"><pre>"; + + print OUTPUT sprintf '%-5i%s%-14s%s%s', $lineno, $linkstr, $revauthor,$linkendstr, $content; + print OUTPUT "</pre></td></tr>\n"; + $lineno++; +} +close ANNOTATE; + +# +# Finally, the html footer +# + +print OUTPUT <<EOF; + </table> + <div id="popup" style="visibility: hidden"></div> + </body> +</html> +EOF + +close OUTPUT; + +system("kfmclient openProfile webbrowsing $outputfile"); + +exit 0; diff --git a/scripts/cvscheck b/scripts/cvscheck new file mode 100755 index 00000000..1e1da5a8 --- /dev/null +++ b/scripts/cvscheck @@ -0,0 +1,385 @@ +#! /usr/bin/env perl + +use POSIX qw(mktime ctime); +use Time::Local qw( timegm ); + +# Offline check for status of files in a checked-out +# CVS module. +# Artistic License, Dirk Mueller <mueller@kde.org> 2001-2003 + +# based on cvschanged by +# Sirtaj Singh Kang <taj@kde.org> Nov 1998. + +if ( defined $ARGV[0] && $ARGV[0] =~ /(?:-h|--help)/) { + print "cvscheck (c) 2001-2003 Dirk Mueller <mueller\@kde.org>\n\nUsage:\n"; + print " cvscheck [options] <dirs>\n\n"; + print "Prints information about the status of your local CVS checkout without\n"; + print "communicating with the server (therefore in speed only limited by your\n"; + print "hard-disk throughput, much unlike cvs -n up).\n\n"; + print "Every file is printed with a status character in front of its name:\n"; + print "? foobar.c file is not known to CVS - maybe you should add it?\n"; + print "M foobar.c file is for sure locally modified.\n"; + print "m foobar.c file *might* have local changes (needs a diff with the server).\n"; + print "C foobar.c file has a CVS conflict and therefore cannot be committed.\n"; + print "U foobar.c file is in CVS but its somehow missing in your local checkout.\n"; + print "T foobar.c file has an unusual sticky CVS tag.\n"; + print "A foobar.c you cvs add'ed this file but did not yet commit.\n"; + print "R foobar.c you cvs rm'ed this file but did not yet commit.\n"; + +print <<EOF; + + +Options: + +-u | --unknown Show only unknown (?) files +-m | --modified Show only modified (m/M) files +--missing Show only missing (U) files +-t | --tagged Show only tagged (T) files +-a | --added Show only added (A) files +-r | --removed Show only removed (R) files +-c | --conflicts Show only conflict (C) files + +If no option is given, it defaults to show all files and diagnostic messages. +EOF + exit; +} + +# default is HEAD +$standardtag = ""; +%defaulttag = (); +@dirqueue = (); +@merged = (); +@uncommitted = (); +@missing = (); +@tagged = (); +@removed = (); +@unknown = (); +@modified = (); +@conflicts = (); + +%months = ( 'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, + 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, + 'Nov' => 10, 'Dec' => 11); + +%showoptions = (); +$optionlocal = 0; + +sub printinfo($) +{ + print @_ if (defined($showoptions{"all"})); +} + +# convert text stamp to GMT +sub strToTime +{ + my( $timestr ) = @_; + + if( ! ($timestr =~ + /^(\w+)\s*(\w+)\s*(\d+)\s*(\d+):(\d+):(\d+)\s*(\d+)/) ) { + + return -1; + } + + # CVS timestamps are in GMT. + + my( $tm ) = timegm( $6, $5, $4, $3, $months{ $2 }, $7 - 1900); + + return $tm; +} + +sub processEntries +{ + my ( $dir ) = @_; + my %dirunknown = (); + + opendir (DIR, "$dir") || warn "Couldn't read '$dir'"; + # first assume all are unknown + while ( $e = readdir(DIR) ) { + next if ($e eq "."); + next if ($e eq ".."); + next if ($e eq "RCS"); + next if ($e eq "SCCS"); + next if ($e eq "CVS"); + next if ($e eq "CVS.adm"); + next if ($e eq "RCSLOG"); + next if ($e eq "tags"); + next if ($e eq "TAGS"); + next if ($e eq ".make.state"); + next if ($e eq ".nse_depinfo"); + next if ($e eq "core"); + next if ($e eq ".libs"); + next if ($e eq ".deps"); + next if ($e =~ /^.+~$/); + next if ($e =~ /^\#.+$/); + next if ($e =~ /^\.\#.+$/); + next if ($e =~ /^,.+$/); + next if ($e =~ /^_\$.+$/); + next if ($e =~ /^.+\$$/); + next if ($e =~ /^.+\.old$/); + next if ($e =~ /^.+\.bak$/); + next if ($e =~ /^.+\.BAK$/); + next if ($e =~ /^.+\.orig$/); + next if ($e =~ /^.+\.rej$/); + next if ($e =~ /^\.del-.+$/); + next if ($e =~ /^.+\.a$/); + next if ($e =~ /^.+\.olb$/); + next if ($e =~ /^.+\.o$/); + next if ($e =~ /^.*\.obj$/); + next if ($e =~ /^.+\.so$/); + next if ($e =~ /^.+\.Z$/); + next if ($e =~ /^.+\.elc$/); + next if ($e =~ /^.+\.ln$/); + next if ($e =~ /^cvslog\..*$/); + + # kde specific entries + # TODO read from CVSROOT/cvsignore - if it's been checked out! + next if ($e eq "config.cache"); + next if ($e eq "config.log"); + next if ($e eq "config.status"); + next if ($e eq "index.cache.bz2"); + next if ($e eq ".memdump"); + next if ($e eq "autom4te.cache"); + next if ($e eq "autom4te.cache"); + next if ($e eq "Makefile.rules"); + next if ($e eq "Makefile.calls"); + next if ($e eq "Makefile.rules.in"); + next if ($e eq "Makefile.calls.in"); + next if ($e =~ /^.*\.moc$/); + next if ($e =~ /^.+\.gmo$/); + next if ($e =~ /^.+\.moc\.[^\.]+$/); + next if ($e =~ /^.+\.lo$/); + next if ($e =~ /^.+\.la$/); + next if ($e =~ /^.+\.rpo$/); + next if ($e =~ /^.+\.closure$/); + next if ($e =~ /^.+\.all_cpp\.cpp$/); + next if ($e =~ /^.+\.all_C\.C$/); + next if ($e =~ /^.+\.all_cc\.cc$/); + next if ($e =~ /^.+_meta_unload\.[^\.]+$/); + next if ($e =~ /^.+\.kidl$/); + next if ($e =~ /^.+_skel\.[^\.]+$/); + + # Qt specific entries + next if ($e eq ".ui"); + next if ($e eq ".moc"); + next if ($e eq ".obj"); + + $dirunknown{$e} = 1; + } + closedir(DIR); + if( open(CVSIGNORE, $dir."/.cvsignore") ) { + while(<CVSIGNORE>) { + s/\s*$//; + my $line = $_; + foreach my $entry ( split(/ /,$line) ) { + if ($entry =~ /[\*\?]/) { + my $pattern = quotemeta $entry; + $pattern =~ s/\\\*/.*/g; + $pattern =~ s/\\\?/./g; + foreach $m (keys (%dirunknown)) { + $dirunknown{$m} = 0 if ($m =~ /^$pattern$/); + } + next; + } + $dirunknown{$entry} = 0; + } + } + close(CVSIGNORE); + } + + if ( !open( ENTRIES, $dir."/CVS/Entries" ) ) { + &printinfo("I CVS/Entries missing in $dir\n"); + return; + } + my $oldstandardtag = defined($defaulttag{$dir}) ? $defaulttag{$dir} : ""; + my $staginfo = ""; + if( open(CVSTAG, $dir."/CVS/Tag" ) ) { + my $line = <CVSTAG>; + if($line =~ /^[TDN](.+)$/) { + $standardtag = $1; + $staginfo = $1; + } + else { + # something with D - assume HEAD + $oldstandardtag = $standardtag = ""; # its HEAD + &printinfo("I $dir has unknown stickyness: $line"); + } + close(CVSTAG); + } + else { + $standardtag = ""; # its HEAD + $staginfo = "(HEAD)"; + } + &printinfo("I $dir has sticky tag $staginfo\n") if($standardtag ne $oldstandardtag); + while( <ENTRIES> ) { + if ( m#^\s*D/([^/]+)/# ) { + if (-d "$dir/$1" && !$optionlocal) { + push ( @dirqueue, "$dir/$1" ); + $defaulttag{"$dir/$1"} = $standardtag; + } + $dirunknown{$1} = 0; + next; + } + + next if !m#^\s*/([^/]+)/([-]*[\d\.]*)/([^/]+)/([^/]*)/(\S*)$#; + $fname = $1; + $ver = $2; + $stamp = $3; + $options = $4; + $tag = $5; + $tag = $1 if ($tag =~ /^[TD](.+)$/); + + $dirunknown{$fname} = 0; + + my $taginfo=""; + if(defined($showoptions{"all"})) { + if ( $tag ne $standardtag ) { + if ($tag eq "") { + $taginfo = " (HEAD)"; + } + else { + $taginfo = " ($tag)"; + } + } + if ($options =~ /^\-k(.)$/) { + $taginfo .= " (no RCS-tags)" if($1 eq "o"); + $taginfo .= " (RCS binary file)" if($1 eq "b"); + $taginfo .= " (RCS values only)" if($1 eq "v"); + $taginfo .= " (RCS keywords only)" if($1 eq "k"); + } + } + my $state = $stamp; + if( $stamp =~ m(^(.+)\+(.+)$) ) { + $state = $1; + $stamp = $2; + } + if ( $state =~ /merge/ ) { + # modified version merged with update from server + # check for a conflict + if ( open (F, "$dir/$fname") ) { + my @conflict = grep /^<<<<<<</, <F>; + close (F); + if( @conflict ) { + push @conflicts, "$dir/$fname$taginfo"; + next; + } + } + else { + push @missing, "$dir/$fname$taginfo"; + next; + } + } + if ( $ver =~ /^\-.*/ ) { + push @removed, "$dir/$fname$taginfo"; + next; + } + $mtm = strToTime( $stamp ); + if( $mtm < 0 ) { + if ( $ver eq "0" ) { + push @uncommitted, "$dir/$fname$taginfo"; + } + else { + push @merged, "$dir/$fname$taginfo"; + } + next; + } + @sparams = lstat( "$dir/$fname" ); + + if ( $#sparams < 0 ) { + push @missing, "$dir/$fname$taginfo"; + next; + } + if( $mtm < $sparams[ 9 ] ) { + push @modified, "$dir/$fname$taginfo"; + next; + } + if ( $tag ne $standardtag ) { + push @tagged, "$dir/$fname$taginfo"; + } + } + close( ENTRIES ); + + my @unknownlist = sort keys (%dirunknown); + foreach $entry (@unknownlist) { + next if ($dirunknown{$entry} == 0); + # ignore unusual files + next if (-l "$dir/$entry" ); + # its a CVS directory ? might be a different module + if (-d "$dir/$entry" and -d "$dir/$entry/CVS") { + $defaulttag{"$dir/$entry"} = $standardtag; + push ( @dirqueue, "$dir/$entry" ); + next; + } + push @unknown, "$dir/$entry"; + } +} + +sub printlist($$@) +{ + my ($status, $type, @flist) = @_; + + return if (not defined($showoptions{"all"}) and + not defined($showoptions{"$type"})); + + if(defined($showoptions{"all"})) { + foreach (@flist) { + s/\.\///; + print "$status $_\n"; + } + } + else { + foreach(@flist) { + print "$_\n"; + } + } +} + +foreach $f ( @unknown ) { + $f =~ s/^\.\///; + print "? $f\n"; +} +foreach (@ARGV) { + $showoptions{"unknown"}++ if(/^(?:-u|--unknown)$/); + $showoptions{"modified"}++ if(/^(?:-m|--modified)$/); + $showoptions{"missing"}++ if(/^(?:--missing)$/); + $showoptions{"tagged"}++ if(/^(?:-t|--tagged)$/); + $showoptions{"added"}++ if(/^(?:-a|--added)$/); + $showoptions{"removed"}++ if(/^(?:-r|--removed)$/); + $showoptions{"conflicts"}++ if(/^(?:-c|--conflicts)$/); + $optionlocal++ if(/^(?:-l|--local)$/); + + next if (/^-/); + push (@dirqueue, "./$_"); +} + +# if no special flags set, show all files +$showoptions{"all"}++ if(scalar(keys(%showoptions)) == 0); + +# Try current directory if none specified +push(@dirqueue, ".") if( $#dirqueue < 0 ); + +# process directory queue +while ($#dirqueue >= 0) { + processEntries( pop @dirqueue ); +} + +&printlist("?", "unknown", @unknown); +&printlist("M", "modified", @modified); +&printlist("m", "modified", @merged); +&printlist("U", "missing", @missing); +&printlist("T", "tagged", @tagged); +&printlist("A", "added", @uncommitted); +&printlist("R", "removed", @removed); +&printlist("C", "conflicts", @conflicts); + +=head1 NAME + +cvscheck -- Lists all files in checked out CVS modules that have been +edited or changed locally. No connection is required to the CVS server, +therefore being extremely fast. + +=head1 AUTHOR + +Dirk Mueller <mueller@kde.org> +based on cvschanged by Sirtaj Singh Kang <taj@kde.org> + +=cut diff --git a/scripts/cvsforwardport b/scripts/cvsforwardport new file mode 100755 index 00000000..10397845 --- /dev/null +++ b/scripts/cvsforwardport @@ -0,0 +1,32 @@ +#!/bin/sh +# Forwardport the last change in a branch to HEAD +# Usage: cvsforwardport <files> +# WARNING: the branch tag is hardcoded into the script, make sure to check it! +# +# Initial author: Dirk Mueller +# Support for multiple command-line arguments: David Faure + +BRANCH=KDE_3_4_BRANCH +echo "Forwardporting to HEAD" +TMPFILE=`mktemp cvsforwardport.XXXXXX` || exit 1 +files=$* +until test $# -eq 0; do + + echo "looking for last change to $1..." + CVSLASTCHANGE_KEEP_WHITESPACE=1 cvslastchange $1 > $TMPFILE + echo "browsing last change to $1..." + less $TMPFILE + cvs up -A $1 + patch < $TMPFILE + rm -f $TMPFILE + echo "showing diff for $1..." + cvs diff $1 | less + + shift +done + +echo "Press ENTER now to commit ($files) or Ctrl+C to abort" +read confirm + +cvs commit $files +cvs up -r $BRANCH $files diff --git a/scripts/cvsgettags b/scripts/cvsgettags new file mode 100755 index 00000000..9869eb06 --- /dev/null +++ b/scripts/cvsgettags @@ -0,0 +1,38 @@ +#!/bin/sh +# +# copyright (C) 2004 Roberto Teixeira <roberto@kde.org> +# +# This script is release under the GPL +# + +# +# This very simple script can be used to fetch available +# cvs tags for a group of files. +# +# Its usage is simple, simply type something like +# +# gettags myfile.cpp myfile.h +# +# to get the available cvs tags for myfile.cpp and myfile.h +# otherwise simply type +# +# gettags +# +# to fetch all available tags in the current directory and its +# subdirectories. +# + +usage() +{ + echo "Ex.:" + echo " $0 [file1] [file2] ..." +} + +if test -z "$1"; then + echo "Will test tags for all files and subdirectories under `pwd`. Hope it's right" + echo "but if it is not, please inform the files you want to fetch the tags from." + + usage +fi + +cvs log $@|tr "\n" "å"|sed 's/^.*symbolic names:å\(.*\)keyword subst.*$/\1/'|tr "å" "\n" diff --git a/scripts/cvslastchange b/scripts/cvslastchange new file mode 100755 index 00000000..9c4688be --- /dev/null +++ b/scripts/cvslastchange @@ -0,0 +1,55 @@ +#! /usr/bin/env perl + +use File::Basename; + +sub usage() +{ + print "Usage:\n"; + print " $0 [ <filename > | <filename> <rev> | \n" . + " M +<digits> -<digits> <filename <rev> ]\n"; + print "\n"; + + exit 5; +} + +my $filename; + +my $argc = scalar @ARGV; + +if ($argc > 0 and $argc < 3 ) { + $filename = $ARGV[0]; + $cvsversion= dirname($0) . "/cvsversion"; + $version=`$cvsversion $filename`; + chomp $version; + $version=$ARGV[1] if ($argc > 1 and $ARGV[1] =~ /^[\d\.]{3,}$/); +} elsif ($argc == 5) { + $filename=$ARGV[3] if (-f $ARGV[3]); + $version=$ARGV[4] if ($ARGV[4] =~ /^[\d\.]{3,}$/); +} else { + &usage(); +} + +die "$0: filename expected" if(!length($filename)); +die "$filename: $!\n" if (! -f $filename); + +my $vold = $version; +my $vnew = $version; + +if ($version=~/^.*\.1$/) { + $vold = $1 if ($version=~/^(\d+\.\d+(?:\.\d+\.\d+)*)\.\d+\.1$/); +} +else { + if ($version=~/^(.*)\.([^.]*)$/) { $v1 = $1; $v2 = $2 } + $v2old = ${v2}-1; + $vold = $v1 . '.' . $v2old; +} +my $base = basename($filename); +my $dir = dirname($filename); +my $cmd = "cd $dir; cvs -f log -N -r$vnew $base"; +print "$cmd\n"; +system("$cmd"); +my $whitespace = ""; +$whitespace = "-b" unless (defined $ENV{"CVSLASTCHANGE_KEEP_WHITESPACE"}); +$cmd = "cd $dir; cvs -f diff -kk $whitespace -p -u -r$vold -r$vnew $base"; +print "$cmd\n"; +system("$cmd"); diff --git a/scripts/cvslastlog b/scripts/cvslastlog new file mode 100755 index 00000000..d1b45812 --- /dev/null +++ b/scripts/cvslastlog @@ -0,0 +1,8 @@ +#!/bin/sh +# cvslastlog - prints log of last commit for a file +# Depends on the version of the local file, not the one on the server +# Requires cvsversion +# David Faure, faure@kde.org + +cvs log -N -r`cvsversion $1` $1 + diff --git a/scripts/cvslastreferenced b/scripts/cvslastreferenced new file mode 100755 index 00000000..666a5b6d --- /dev/null +++ b/scripts/cvslastreferenced @@ -0,0 +1,64 @@ +#!/usr/bin/perl -w +# Written by Zack Rusin <zack@kde.org> +# +# This file is free software, licensed under the BSD licence. +# That means that you can do anything you want with it except +# eating too much candy since that totally messes up your teeth +# and here in KDE land we care about your teeth. They're out +# greatest priority right next to scoring chicks of course... +# + +# This script goes through the whole history of a file to find +# all modifications referencing specific string. It's useful if +# you want to know when a function has been removed/modified/added +# to a file if a recent cvs annotate doesn't anymore reference it. + +our $file; +our $func; + +sub check_file +{ + my $rev1 = shift; + my $rev2 = shift; + + my $output = `cvs diff -r $rev1 -r $rev2 $file`; + + if ( $output =~ /(^[+-].+$func.+$)/m ) { + print "FOUND IN: cvs diff -r $rev1 -r $rev2 $file\n"; + $_ = $1; + s/^([-+])\s*(.+)/$1 $2/; + return $_; + } + return 0; +} + +sub get_revision +{ + my $output = `cvsversion $file`; + chomp $output; + return $output; +} + +my $argc = scalar @ARGV; + +die "$0 <function> <file>" if ( $argc != 2 ); +$func = $ARGV[0]; +$file = $ARGV[1]; + +my $current_revision = get_revision( $file ); + +$current_revision =~ /(\d+)\.(\d+)/; +$base = $1; +$working = $2; + +while ( $working > 1 ) { + my $older = $working - 1; + my $res = check_file( "$base.$older", "$base.$working"); + + if ( $res ) { + print "\t($res)\n"; + } + --$working; +} + +print "Didn't find a reference to that $func in $file\n"; diff --git a/scripts/cvsrevertlast b/scripts/cvsrevertlast new file mode 100755 index 00000000..96808514 --- /dev/null +++ b/scripts/cvsrevertlast @@ -0,0 +1,17 @@ +#!/bin/sh +# (C) 2001 Charles Samuels <charles@kde.org> +# +# This script reverts all the files given on the command +# by one version, then you can commit them. This +# is like a less polite version of cvsblame ;) +# + +for i in $@ ; +do + text=`cvs status "$i" | grep '[^s]Repository revision:.*$'` + current=`echo $text | awk '{print $3}'` + previous=`echo $current | awk -F . '{ ORS="."; OFS="\n"; for (i=1; i<NF; i++) print $i; ORS=""; $NF-=1; print $NF }'` + echo $i... "(reverting from $current to $previous)" + cvs up -j $current -j $previous $i +done + diff --git a/scripts/cvsversion b/scripts/cvsversion new file mode 100755 index 00000000..200c008a --- /dev/null +++ b/scripts/cvsversion @@ -0,0 +1,30 @@ +#!/bin/sh +exec awk -F / "{ if (\$2 == \"`basename $1`\") print \$3 }" < `dirname $1`/CVS/Entries + +=head1 NAME + +cvsversion -- Displays version of the file passed as argument. + +=head1 SYNOPSIS + + cvsversion <file> + +=head1 DESCRIPTION + +cvsversion displays the version in CVS of a file, as known by the local +checked out directory. No connection is required to the CVS server. +It can be used in other scripts, or simply to ask +for diffs using + +cvs diff -r <version> [-r <version>] <file> + +=head1 EXAMPLES + + cd baseline/kdelibs ; cvsversion configure.in + cvsversion baseline/kdelibs/configure.in + +=head1 AUTHOR + +David Faure <faure@kde.org> + +=cut diff --git a/scripts/cxxmetric b/scripts/cxxmetric new file mode 100755 index 00000000..0fae0a9b --- /dev/null +++ b/scripts/cxxmetric @@ -0,0 +1,223 @@ +#!/usr/bin/perl -w + +# Simple Source metrics for C++ +# Taj Sun Apr 26 03:31:00 EST 1998 +# $Id$ + +use strict; + +our $bigblank = 0; +our $bigcommt = 0; +our $bigstrcount = 0; +our $bigstrsize = 0; +our $bigtotal = 0; +our $numfiles = 0; + +our $blocklen = 0; +our $numblocks = 0; +our $blockdepth = 0; +our $blockstart = 0; +our $blockmin = -1; +our $blockmax = 0; +our @blenlist = (); +our @extensions = ( ".cpp", ".cc", ".C", ".c", ".h", ".tcc" ); + +sub processFile +{ + our ( $file ) = @_; + our $blank = 0; + our $comment = 0; + our $total = 0; + our $incomment = 0; + our $strcount = 0; + our $strsize = 0; + + open( SOURCE, "$file" ) || + die "cxxmetric.pl: Couldn't read from $file.\n"; + + while( <SOURCE> ) { + $total++; + + if ( /^\s*$/ ) { + $blank++; + next; + } + + if ( m#^\s*//# ) { + $comment++; + next; + } + + if ( /{/ ) { + # block start + $blockdepth += s/{/{/g; + + $blockstart = $. if $blockdepth == 1; + } + + if ( /}/ ) { + # block end + + $blockdepth -= s/}/}/g; + + if( $blockdepth == 0 ) { + my $thisblocklen = $. - $blockstart; + push @blenlist, $thisblocklen; + + $blocklen += $thisblocklen; + $numblocks++; + + if( $blockmax < $thisblocklen ) { + $blockmax = $thisblocklen; + } + + if ( $blockmin == -1 + || $blockmin > $thisblocklen ) { + $blockmin = $thisblocklen; + } + } + } + + my $start = 0; + my $stop = 0; + + if ( m#/\*# ) { + $start = 1; + } + + if( m#\*/# ) { + $stop = 1; + } + + if( $start ) { + $incomment = 1 unless $stop; + $comment++; + } + elsif ( $stop ) { + $comment++; + $incomment = 0; + } + elsif ( $incomment ) { + $comment++; + } + else { + my $line = $_; + countStrings( $line ); + } + } + + our $code = $total - ($comment + $blank ); + $bigtotal += $total; + $bigcommt += $comment; + $bigblank += $blank; + $bigstrcount += $strcount; + $bigstrsize += $strsize; + + our $stravglen = $strcount ? ($strsize / $strcount) : 0; + + write; +} + +sub buildFileList { + my ( $dir ) = @_; + my @fileList = glob( "$dir/*" ); + my @cxxList; + + foreach my $file (@fileList) { + + if( -d $file ) { + push @cxxList, buildFileList( $file ); + } + else { + foreach my $extension (@extensions) { + if( substr( $file, length( $file ) - length( $extension ) ) eq $extension ) { + push @cxxList, $file; + } + } + } + } + + return @cxxList; +} + +sub countStrings +{ + my $line = shift; + + foreach my $string ( split( /("[^"]*)\"/, $line ) ) { + next unless $string =~ /^\"/; + + our $strcount++; + our $strsize += length( $string ) - 1; + } +} + +sub pct +{ + my( $top, $bottom ) = @_; + + return 0 if $bottom == 0; + + return int(( $top * 100 ) / $bottom); +} + +our @files; + +if( @ARGV == 0 ) { + @files = buildFileList("."); +} +else { + @files = @ARGV; +} + +foreach my $file ( @files ) { + processFile( $file ); + ++$numfiles; +} + +our $total = $bigtotal; +our $comment = $bigcommt; +our $blank = $bigblank; +our $code = $bigtotal - ($bigcommt + $bigblank ); +our $file = "Total"; + +print "\n"; +write; + +print "\nPercentage Code:\t" , pct( $code, $total ),"%\n"; +print "Percentage Comment:\t" , pct( $comment, $total ),"%\n"; +print "Percentage Blank:\t" , pct( $blank, $total ),"%\n"; +print "Percentage Cmt/Code:\t" , pct( $comment, $code ),"%\n"; +print "Average Code/File:\t" , int($code/$numfiles)," lines\n" + unless $numfiles == 0; + +if ( $numblocks > 0 ) { + my $avg = int( $blocklen / $numblocks ); + @blenlist = sort @blenlist; + my $median = $blenlist[ int( $numblocks / 2 )]; +print<<EOF; + +Blocks:\t$numblocks +\tLengths (lines):\tmin: $blockmin\tmax: $blockmax\tmed: $median\taverage: $avg +EOF +} + +our $bigstravglen = $bigstrcount ? int($bigstrsize / $bigstrcount) : 0; + +print<<EOF; +Strings:\t$bigstrcount +\tSize (bytes):\ttotal: $bigstrsize\taverage: $bigstravglen +EOF + +exit; + +format STDOUT_TOP = + Lines Code Comment Blank Strs AvgLen File + ------ ------- -------- ------ ------ ------ ------ + +. + +format STDOUT = +@###### @###### @###### @###### @###### @###### @<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +$total, $code, $comment, $blank, our $strcount, our $stravglen, $file +. diff --git a/scripts/extend_dmalloc b/scripts/extend_dmalloc new file mode 100755 index 00000000..53bd7491 --- /dev/null +++ b/scripts/extend_dmalloc @@ -0,0 +1,159 @@ +#! /usr/bin/env perl +# +# script to run gdb on return-addresses +# Usage: $0 malloc-log-file binary +# +# Copyright 1995 by Gray Watson +# +# This file is part of the dmalloc package. +# +# Permission to use, copy, modify, and distribute this software for +# any purpose and without fee is hereby granted, provided that the +# above copyright notice and this permission notice appear in all +# copies, and that the name of Gray Watson not be used in advertising +# or publicity pertaining to distribution of the document or software +# without specific, written prior permission. +# +# Gray Watson makes no representations about the suitability of the +# software described herein for any purpose. It is provided "as is" +# without express or implied warranty. +# +# The author may be contacted at gray.watson@letters.com +# +# $Id$ +# + +# +# Use this Perl script to run gdb and get information on the return-address +# (ra) addresses from a dmalloc logfile output. This will search for +# any ra= lines and will examine them and try to get the line number. +# +# NOTE: you may want to direct the output from the script to a file +# else gdb seems to prompt for a return like you are on the end of a +# page. +# +# Be sure to send me mail if there is an easier way to do all this. +# + +############################################################################### +# usage message +# +if (@ARGV != 2 ) { + die "Usage: $0 dmalloc-log binary-that-generated-log\n"; +} + +$malloc = @ARGV[0]; +$command = @ARGV[1]; + +@addresses = (); + +open(malloc, $malloc); +while ( <malloc> ) { + if ($_ =~ m/ra=(0x[0-9a-fA-F]+)/) { + push(@addresses, $1); + } +} +close(malloc); +open(SORT, "|sort -u > $malloc.tmp"); + +foreach $address (@addresses) { + print SORT "$address\n"; +} +close(SORT); + +@addresses = (); + +open(SORT, "< $malloc.tmp"); +while ( <SORT> ) { + chomp $_; + push(@addresses, $_); +} +close(SORT); +unlink $malloc.tmp; + +open (gdb, "|gdb -nx -q $command > $malloc.tmp") || die "Could not run gdb: $!\n"; +$| = 1; + +# get rid of the (gdb) +printf (gdb "set prompt\n"); +printf (gdb "echo \\n\n"); + +# load in the shared libraries +printf (gdb "sharedlibrary\n"); + +# run the program to have _definitly_ the informations +# we need from the shared libraries. Unfortunatly gdb 4.18's +# version of sharedlibrary does nothing ;( +printf (gdb "b main\n"); +printf (gdb "run\n"); + +foreach $address (@addresses) { + + printf (gdb "echo -----------------------------------------------\\n\n"); + # printf (gdb "echo Address = '%s'\n", $address); + printf (gdb "x %s\n", $address); + printf (gdb "info line *(%s)\n", $address); +} +printf (gdb "quit\ny\n"); +# $| = 0; + +close(gdb); + +%lines = (); + +open(malloc, "< $malloc.tmp"); + +$count = 0; +$address = ""; +$line = ""; + +while ( <malloc> ) { + + # ignore our own input + if ($_ =~ m/^x 0x/ || $_ =~ m/^echo ------/ || $_ =~ m/^info line/) { + next; + } + + if ($_ =~ m/^--------/) { + if ($line) { + $lines{$address} = "$line"; + } + $count = 0; + $address = ""; + $line = ""; + } else { + $count = $count + 1; + } + + if ($count == 1 && $_ =~ m/(0x[0-9a-fA-F]+)\s*<(.*)>:\s*(\S+)/) { + $address = $1; + $line = "$2<$3>"; + } + + if ($count == 2 && $_ =~ m/Line ([0-9]+) of \"([^\"]*)\"/) { + $line = "$2:$1"; + } + +} + +if ($line) { + $lines{$address} = "$line"; +} + +close(malloc); + +open(malloc, $malloc); + +while ( <malloc> ) { + if ($_ =~ m/ra=(0x[0-9a-fA-F]+)/) { + $address = $1; + if (defined($lines{$address})) { + $_ =~ s/ra=$address/$lines{$address}/; + print STDOUT $_; + } else { + print STDOUT $_; + } + } else { + print STDOUT $_; + } +} diff --git a/scripts/extractattr b/scripts/extractattr new file mode 100755 index 00000000..324b1f56 --- /dev/null +++ b/scripts/extractattr @@ -0,0 +1,158 @@ +#! /usr/bin/env perl + +# +# Copyright (c) 2004 Richard Evans <rich@ridas.com> +# +# License: LGPL 2.0 +# + +sub usage +{ + warn <<"EOF"; + +extractattr [flags] filenames + +This script extracts element attributes from designer (.ui) and XMLGIU (.rc) files +and writes on standard output (usually redirected to rc.cpp) the equivalent +i18n() calls so that xgettext can parse them. + +--attr=spec : Specify the attribute to be extracted. The specification + consists of the following comma separated arguments: + + Element,attribute[,context] + + The context is optional and overrides the name set by + --context below. Repeat the flag to specify multiple + attributes: + + --attr=Title,data --attr=Description,data,Stencils + +--context=name : Give i18n calls a context name: i18n("name", ...) +--lines : Include source line numbers in comments (deprecated, it is switched on by default now) +--help|? : Display this summary + +EOF + + exit; +} + +########################################################################################### + +use strict; +use warnings; +use Getopt::Long; + +########################################################################################### +# Add options here as necessary - perldoc Getopt::Long for details on GetOptions + +GetOptions ( "attr=s" => \my @opt_attr, + "context=s" => \my $opt_context, + "lines" => \my $opt_lines, + "help|?" => \&usage ); + +unless ( @ARGV ) +{ + warn "No filename specified"; + exit; +} + +unless ( @opt_attr ) +{ + warn "No attributes specified"; + exit; +} + +########################################################################################### +# Program start proper - NB $. is the current line number + +my $code =<<'EOF'; +our $file_name; + +for $file_name ( @ARGV ) +{ + my $fh; + + unless ( open $fh, "<", $file_name ) + { + warn "Failed to open: '$file_name': $!"; + next; + } + + while ( <$fh> ) + { + last if $. == 1 and $_ !~ /^(?:<!DOCTYPE|<\?xml)/; +EOF + +$code .= build_code(@opt_attr) . <<'EOF'; + } + + close $fh or warn "Failed to close: '$file_name': $!"; +} + +1; +EOF + +# warn "CODE TO EVAL:\n$code\n"; + +eval $code or die; + + +sub build_code +{ + my $code = "\n"; + + my %seen; + + for ( @_ ) + { + my ($element, $attribute, $context) = ((split /,/), "", "", ""); + + length $element or die "Missing element in --attr=$_"; + length $attribute or die "Missing attribute in --attr=$_"; + + if ( $seen{$element . '<' . $attribute}++ ) + { + warn "Skipping duplicate flag --attr=$_ (element/attribute pair has already been specified)"; + next; + } + + $code .= " /<" . quotemeta($element) . qq| [^>]*?| . + quotemeta($attribute) . qq|="([^"]+)"/ and write_i18n('| . $context . qq|', \$1);\n|; + } + + return "$code\n"; +} + +sub write_i18n +{ + my ($context, $text) = @_; + + our $file_name; + + unless ( $text ) + { + print "// Skipped empty message at $file_name line $.\n"; + return; + } + + $text =~ s/</</g; + $text =~ s/>/>/g; + $text =~ s/'/\'/g; + $text =~ s/"/\"/g; + $text =~ s/&/&/g; + + # Escape characters exactly like uic does it + # (As extractrc needs it, we follow the same rule to avoid to be different.) + $text =~ s/\\/\\\\/g; # escape \ + $text =~ s/\"/\\\"/g; # escape " + $text =~ s/\r//g; # remove CR (Carriage Return) + $text =~ s/\n/\\n\"\n\"/g; # escape LF (Line Feed). uic also change the code line at a LF, we do not do that. + + $context ||= $opt_context; + + print "//i18n: file $file_name line $.\n"; + print qq|i18n("|; + print qq|$context", "| if $context; + print qq|$text");\n|; +} + diff --git a/scripts/extractrc b/scripts/extractrc new file mode 100755 index 00000000..54c1123a --- /dev/null +++ b/scripts/extractrc @@ -0,0 +1,174 @@ +#! /usr/bin/env perl + +### TODO: other copyrights, license? +# Copyright (c) 2004 Richard Evans <rich@ridas.com> + +sub usage +{ + warn <<"EOF"; + +extractrc [flags] filenames + +This script extracts messages from designer (.ui) and XMLGUI (.rc) files and +writes on standard output (usually redirected to rc.cpp) the equivalent +i18n() calls so that xgettext can parse them. + +--tag=name : Also extract the tag name(s). Repeat the flag to specify + multiple names: --tag=tag_one --tag=tag_two + +--tag-group=group : Use a group of tags - uses 'default' if omitted. + Valid groups are: @{[TAG_GROUPS()]} + +--context=name : Give i18n calls a context name: i18n("name", ...) +--lines : Include source line numbers in comments (deprecated, it is switched on by default now) +--help|? : Display this summary + +EOF + + exit; +} + +########################################################################################### + +use strict; +use warnings; +use Getopt::Long; + +use constant TAG_GROUP => +{ + default => "[tT][eE][xX][tT]|title|string|whatsthis|tooltip|label", + koffice => "Example|GroupName|Text|Comment|Syntax|TypeName", + none => "", +}; + +use constant TAG_GROUPS => join ", ", map "'$_'", sort keys %{&TAG_GROUP}; + + +########################################################################################### +# Add options here as necessary - perldoc Getopt::Long for details on GetOptions + +GetOptions ( "tag=s" => \my @opt_extra_tags, + "tag-group=s" => \my $opt_tag_group, + "context=s" => \my $opt_context, # I18N context + "lines" => \my $opt_lines, + "help|?" => \&usage ); + +unless( @ARGV ) +{ + warn "No filename specified"; + exit; +} + +$opt_tag_group ||= "default"; + +die "Unknown tag group: '$opt_tag_group', should be one of " . TAG_GROUPS + unless exists TAG_GROUP->{$opt_tag_group}; + +my $tags = TAG_GROUP->{$opt_tag_group}; +my $extra_tags = join "", map "|" . quotemeta, @opt_extra_tags; +my $text_string = qr/($tags$extra_tags)( [^>]*)?>/; # Precompile regexp + + +########################################################################################### +# Program start proper - NB $. is the current line number + +for my $file_name ( @ARGV ) +{ + my $fh; + + unless ( open $fh, "<", $file_name ) + { + # warn "Failed to open: '$file_name': $!"; + next; + } + + my $string = ""; + my $in_text = 0; + my $start_line_no = 0; + my $in_skipped_prop = 0; + my $tag = ""; + my $attr = ""; + my $context = ""; + + while ( <$fh> ) + { + last if $. == 1 and $_ !~ /^(?:<!DOCTYPE|<\?xml|<!--)/; + + chomp; + + $string .= "\n" . $_; + + # 'database', 'associations' properties contain strings that shouldn't be translated + + if ( $in_skipped_prop == 0 and $string =~ /<property name=\"(?:database|associations|populationText)\"/ ) + { + $in_skipped_prop = 1; + } + elsif ( $in_skipped_prop and $string =~ /<\/property/ ) + { + $string = ""; + $in_skipped_prop = 0; + } + + $context = $opt_context; + + unless ( $in_skipped_prop or $in_text ) + { + if ( ($tag, $attr) = $string =~ /<$text_string/o ) + { + ($attr) = $attr =~ /\w*context=\"([^\"]*)\"/ if $attr; + $context = $attr if $attr; + + $string =~ s/^.*<$text_string//so; + $in_text = 1; + $start_line_no = $.; + } + else + { + $string = ""; + } + } + + next unless $in_text; + next unless $string =~ /<\/$text_string/o; + + my $text = $string; + + $text =~ s/<\/$text_string.*$//o; + $text =~ s/</</g; + $text =~ s/>/>/g; + $text =~ s/&/&/g; + + # We need to escape characters exactly like uic does it: + $text =~ s/\\/\\\\/g; # escape \ + $text =~ s/\"/\\\"/g; # escape " + $text =~ s/\r//g; # remove CR (Carriage Return) + $text =~ s/\n/\\n\"\n\"/g; # escape LF (Line Feed). uic also change the code line at a LF, we do not do that. + + if ( $text cmp "" ) + { + print "//i18n: file $file_name line $.\n"; + print "// xgettext: no-c-format\n"; + print q|i18n("|; + print qq|$context","| if $context; # We have a I18N context + print qq|$text");\n|; + } + else + { + #print "// Skipped empty message at $file_name line $.\n"; + # - seems this comment may confuse old custom xgettext of KDE3; not needed anyway + } + + $string =~ s/^.*<\/$text_string//o; + $in_text = 0; + + # Text can be multiline in .ui files (possibly), but we warn about it in XMLGUI .rc files. + + warn "there is <text> floating in: '$file_name'" if $. != $start_line_no and $file_name =~ /\.rc$/i; + } + + close $fh or warn "Failed to close: '$file_name': $!"; + + die "parsing error in $file_name" if $in_text; +} + diff --git a/scripts/findmissingcrystal b/scripts/findmissingcrystal new file mode 100755 index 00000000..258119c3 --- /dev/null +++ b/scripts/findmissingcrystal @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Small script to look at Crystal icons and see which ones are still the +# same as kdeclassic/hicolor. + +if [ -z "$1" ] ; then + echo "usage: findmissingcrystal module" + exit 1 +fi + +for icon in `find $1 -name cr*.png` ; do + fullname=`echo $icon | sed 's,.*cr,,'` + res=`echo $fullname | cut -d- -f1` + type=`echo $fullname | cut -d- -f2` + name=`echo $fullname | cut -d- -f3` + dir="kdeartwork/IconThemes/kdeclassic/${res}x${res}/${type}s/" + if [ -d "$dir" ]; then + classic=`find "${dir}" -name "$name"` + if [ -s "$classic" ]; then + diff=`diff $icon $classic` + if [ -z "$diff" ]; then + echo "ERR/same: $icon" + else + echo "OK /diff: $icon" + fi + else + echo "OK /new : $icon" + fi + else + echo "OK /new : $icon" + fi +done diff --git a/scripts/fixfsfaddr.sed b/scripts/fixfsfaddr.sed new file mode 100644 index 00000000..ab96de23 --- /dev/null +++ b/scripts/fixfsfaddr.sed @@ -0,0 +1,30 @@ +#! /usr/bin/sed + +# Copyright 2005 Nicolas GOUTTE <goutte@kde.org> +# License LGPL V2+ + +# The script helps to fix the FSF address +# Use: +# find . -name .svn -prune , type f | xargs fgrep -l "Free Software Foundation" | xargs sed -i -f fixfsfaddr.sed +# Note: you should check the changes before committing them. + +# Implementation note: we need to replace phrase by phrase, as +# the wrapping of the FSF address is at different places. + +# Current FSF address: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + +# Old address: 59 Temple Place, Suite 330, Boston, MA 02111-1307 +s/59 Temple Place,/51 Franklin Street,/ +s/59 Temple Place -/51 Franklin Street,/ +s/Suite 330,/Fifth Floor,/ +s/Suite 330$/Fifth Floor/ +s/02111-1307/02110-1301/ + +# Very old address: 675 Mass Ave, Cambridge, MA 02139 +s/675 Mass Ave/51 Franklin Street, Fifth Floor/ +s/Cambridge/Boston/ +s/02139/02110-1301/ +# Warning: the last two replaces seem to match the address of the MIT too. + +# Typo in KDE: Franklin Steet +s/Franklin Steet/Franklin Street/ diff --git a/scripts/fixheaders b/scripts/fixheaders new file mode 100644 index 00000000..b1b0a15b --- /dev/null +++ b/scripts/fixheaders @@ -0,0 +1,214 @@ +#! /usr/bin/env perl + +# this script is written by Stephan Kulow <coolo@kde.org> with +# much help from Sirtaj Singh Kang <ssk@physics.unimelb.edu.au> + +if ($ARGV[0]) { + $topdir = $ARGV[0]; +} else { + $topdir=`pwd`; +} +chomp $topdir; + +$lastdir = '.'; + + +# this is the important part. Left from the '=>' you find the regular +# expression for the g++ output and right from '=>' the header file to +# include +%messages = +( + 'implicit declaration of function `int i18n\(\.\.\.\)\'' => "klocale", + '`i18n\' undeclared \(first use this function\)' => "klocale", + 'variable `class QPixmap \S*\' has initializer but incomplete type' => "qpixmap", + '`kapp\' undeclared \(first use this function\)' => "kapplication", + 'no matching function for call to `KLocale::' => "klocale", + '`klocale\' undeclared \(first use this function\)' => "klocale", + 'no matching function for call to `QPopupMenu::' => "qpopupmenu", + '`QTextStream\' undeclared \(first use this function\)' => "qtextstream", + '`QTextStream\' was not declared in this scope' => "qtextstream", + 'incomplete type `QSocketNotifier\'' => "qsocketnotifier", + 'no matching function for call to `KConfig' => "kconfig", + 'variable `class KConfig \S*\' has initializer but incomplete type' => "kconfig", + 'implicit declaration of function `int kdDebug' => "kdebug", + 'implicit declaration of function `int kdWarning' => "kdebug", + '`QFile\' undeclared \(first use this function' => "qfile", + 'variable `QFile \S*\' has initializer but incomplete type' => "qfile", + 'type `KConfigBase\' is not a base type for type `KConfig' => "kconfig", + 'invalid use of undefined type `class QAccel' => "qaccel", + 'invalid use of undefined type `class KAboutData' => "kaboutdata", + 'incomplete type `KAboutData\'' => "kaboutdata", + 'incomplete type `QGrid\'' => "qgrid", + 'invalid use of undefined type `class QGrid\'' => "qgrid", + 'aggregate `class KConfig \S*\' has incomplete type' => "kconfig", + '`stderr\' undeclared \(first use this function' => "stdio", + 'invalid use of undefined type `class KConfig' => "kconfig", + 'implicit declaration of function `int f?printf' => "stdio", + 'no method `KGlobal::' => "kglobal", + '`KGlobal\' undeclared \(first use this function\)' => "kglobal", + 'implicit declaration of function `int locate\(\.\.\.\)' => "kstddirs", + '`locate\' undeclared \(first use this function\)' => "kstddirs", + 'no matching function for call to `KStandardDirs' => "kstddirs", + 'no method `KStandardDirs::' => "kstddirs", + 'variable `class QFile \S*\' has initializer but incomplete type' => "qfile", + 'implicit declaration of function `int ICON\(\.\.\.\)' => "kiconloader", + '`QMessageBox\' undeclared \(first use this function\)' => "qmessagebox", + 'no matching function for call to `QBoxLayout::QBoxLayout' => "qlayout", + '`QUriDrag\' undeclared \(first use this function\)' => "qdragobject", + '`kdDebug\' undeclared \(first use this function\)' => "kdebug", + '`kdWarning\' undeclared \(first use this function\)' => "kdebug", + 'no matching function for call to `KMenuBar::insertItem\(QString, KPopupMenu' => "kpopupmenu", + 'no matching function for call to `KMenuBar::' => "kmenubar", + 'invalid use of undefined type `class QPointArray' => "qpointarray", + 'variable `QPainter \S*\' has initializer but incomplete type' => "qpainter", + 'invalid use of undefined type `class QRegExp' => "qregexp", + 'invalid use of undefined type `class QPushButton' => "qpushbutton", + 'cannot convert `QPushButton \*\' to `QButton \*' => "qpushbutton", + 'invalid use of undefined type `class QButton' => "qbutton", + '`QButton\' undeclared \(first use this function\)' => "qbutton", + 'no method `QCursor::pos' => "qcursor", + '`DesktopIcon\' undeclared \(first use this function\)' => "kiconloader", + '`BarIcon\' undeclared \(first use this function\)' => "kiconloader", + '`SmallIcon\' undeclared \(first use this function\)' => "kiconloader", + '`UserIcon\' undeclared \(first use this function\)' => "kiconloader", + 'implicit declaration of function `int UserIcon\(...\)\'' => "kiconloader", + '`KIcon\' undeclared \(first use this function\)' => "kiconloader", + 'invalid use of undefined type `class KIconLoader' => "kiconloader", + 'invalid use of undefined type `class KInstance' => "kinstance", + 'invalid use of undefined type `class DCOPClient' => "dcopclient", + '`DCOPClient\' undeclared \(first use this function\)' => "dcopclient", + 'invalid use of undefined type `class KStatusBar\'' => "kstatusbar", + 'invalid use of undefined type `class QLabel\'' => "qlabel", + 'invalid use of undefined type `class QImage\'' => "qimage", + 'invalid use of undefined type `class QImageIO\'' => "qimage", + 'invalid use of undefined type `class QLineEdit\'' => "qlineedit", + 'invalid use of undefined type `class QComboBox\'' => "qcombobox", + 'invalid use of undefined type `class QStyle\'' => "qstyle", + 'invalid use of undefined type `class KPopupMenu\'' => "kpopupmenu", + 'invalid use of undefined type `class QPopupMenu\'' => "qpopupmenu", + 'cannot convert `KPopupMenu \*\' to `QPopupMenu \*' => "kpopupmenu", + 'aggregate `QPopupMenu \S*\' has incomplete type' => "qpopupmenu", + 'invalid use of undefined type `class KURL' => "kurl", + 'no method `QApplication::' => "qapplication", + 'no method `QFile::' => "qfile", + 'error: \'Q3CString\' is used as a type' => "q3cstring", + 'error: ISO C\+\+ forbids declaration of \`Q3CString\' with' => "q3cstring", + 'error: incomplete type \'QPixmap\' cannot be used' => 'qpixmap', + 'error: invalid use of undefined type `struct QVector' => 'qvector', + 'error: incomplete type `Q3ValueList' => 'q3valuelist', + 'error: variable `Q3ValueList<' => 'q3valuelist', + 'error: `Q3PointArray\' undeclared' => 'q3pointarray', + 'error: invalid use of undefined type \`struct QColor' => 'qcolor', + 'error: `QX11Info::' => 'qx11info_x11', + 'error: incomplete type \'QX11Info' => 'qx11info_x11', + 'error: \'Q3AsciiDi' => 'q3asciidict' +); + +# Initial values are simply to get into the while +$exitcode=2; # exit-code from last 'make' command +$addedone=1; # 1 when something has been fixed, means we can try again + +while ( $exitcode != 0 && $addedone != 0 ) +{ + $addedone = 0; + + %changes = (); + open(INPUT,"makeobj -j10 -k 2>&1 |") || die "Couldn't run makeobj"; + while(<INPUT>) + { + if (/make.*Entering directory \`(.+)\'/) { + $lastdir = $1; + $lastdir =~ s/^$topdir\///; + print STDERR "entering $lastdir\n"; + next; + } + if (/^([^:]*):\d*: (.*)$/) { + $file = $1; + $line = $2; + if ($file !~ m,^\/,) { + $file = "$lastdir/$file"; + } + #print STDERR "file=$file\n"; + } else { + # This could be a continuation line + if ( defined $line && $line ne "" ) { + $line .= $_; + #print STDERR "file still $file\n"; + #print STDERR "line=$line\n"; + } else { + # Compilation line, or other unparsable line -> ignore + print STDOUT $_; + next; + } + } + + #print STDERR "Already having changes for $file\n" if defined($changes{$file}); + next if defined($changes{$file}); + + print STDOUT $_; + + foreach $message (keys %messages) { + if ($line =~ /$message/) { + $changes{$file} = $messages{$message}; + $addedone = fixFile($file, $messages{$message}); + } + } + + if (defined($changes{$file})) { $file=""; $line=""; } + } # end of while(<INPUT>) + close(INPUT); + $exitcode=($?>>8); +} # end of main while + +sub fixFile +{ + my( $file, $adding ) = @_; + + my $lastinclude = ""; + + # read file + open ( FILE, "$file" ) || die "Can't read $file"; + + my $flines; + my $cpplevel = 0; + + while (<FILE>) { + $flines .= $_; + if ($_ =~ m/^#if/ && $_ !~ m/^#ifn/) { + $cpplevel = $cpplevel + 1; + } + if ($_ =~ m/^#endif/) { + $cpplevel = $cpplevel - 1; + } + if ($cpplevel == 0 && $_ =~ m/^(#include\s*[\"<]q\S*\.h[\">]\S*)/) { + $lastinclude = $1; + } + } + + close FILE; + + if (!$lastinclude) { + print STDERR "ERROR: no include found in $file! (tried to add $adding.h)\n"; + return 0; + } + + if ($flines =~ m/#include\s*[\"<]$adding\.h[\">]\s*\n/) { + print STDERR "ERROR: $adding.h already included in $file!\n"; + return 0; + } + if ($flines =~ /(\n$lastinclude)/) { + $flines =~ s/$lastinclude(.*\n)/$lastinclude$1#include <$adding.h>\n/; + print STDERR "ADDED <$adding.h> after \"$lastinclude\" in $file\n"; + } else { + print STDERR "ERROR: can't find $lastinclude in $file\n"; + return 0; + } + + # write file + + rename($file, "$file.old"); + open( FILE, ">$file" ) || die "Can't write to $file"; + print FILE $flines; + close FILE; + return 1; +} diff --git a/scripts/fixkdeincludes b/scripts/fixkdeincludes new file mode 100644 index 00000000..54e4e9f6 --- /dev/null +++ b/scripts/fixkdeincludes @@ -0,0 +1,756 @@ +#!/usr/bin/perl -w +# tries to reduce the number of includes in KDE source files +# (c) 2001-2003 Dirk Mueller <mueller@kde.org> + +use File::Basename; +use Cwd; + +# declaration of useful subroutines +sub find_src_includes($); +sub find_fixable_sources ($); +sub find_fixable_headers($); +sub find_removable_includes ($); +sub warn_before_modifying ($); +sub remove_include ($$$); +sub replace_include ($$$); +sub replace_include_type ($$); +sub fix_duplicates($); +sub fix_compat_includes($); +sub fix_unnecessary($); +sub fix_include_type($); +sub copy_file($$); +sub process_source_file($); +sub extract_gcc_error($); + +# some global variables +$verbose = 0; # turns on debugging +$modify = 0; # if 1 it should try to fix the files as well +$experimental = 0; # try&error if an include is obsolete (slow!!) +@explicitfiles = (); # filled in if passing files on the command line + +# statistic variables +$exp_success = 0; +$exp_failure = 0; + +while (defined ($ARGV[0])) +{ + $_ = shift; + if (/^--help$|^-h$/) { + print "Usage: fixkdeincludes [--verbose | -v] [--experimental | -e ] [--modify | -m ]\n"; + exit 0; + } + elsif (/^--verbose$|^-v$/) { + $verbose = 1; # Oh is there a problem...? + } + elsif (/^--modify$|^-m$/) { + $modify = 1; + } + elsif (/^--experimental$|^-e$/) { + $modify = 1; + $experimental = 1; + } + elsif (!/^-/) { + push @explicitfiles, $_; + } +} + +$cppExt = "(cpp|cc|cxx|C|c\\+\\+)"; +$hExt = "(h|H|hh|hxx|hpp|h\\+\\+)"; + +# list of compat headers. scroll down ... much of boring stuff here.. +%compatmap = ( + 'qapp.h' => "qapplication.h", + 'qarray.h' => "qmemarray.h", + 'qbitarry.h' => "qbitarray.h", + 'qbttngrp.h' => "qbuttongroup.h", + 'qchkbox.h' => "qcheckbox.h", + 'qclipbrd.h' => "qclipboard.h", + 'qcollect.h' => "qptrcollection.h", + 'qcollection.h' => "qptrcollection.h", + 'qcombo.h' => "qcombobox.h", + 'qconnect.h' => "qconnection.h", + 'qdatetm.h' => "qdatetime.h", + 'qdrawutl.h' => "qdrawutil.h", + 'qdstream.h' => "qdatastream.h", + 'qfiledef.h' => "private/qfiledefs_p.h", + 'qfiledlg.h' => "qfiledialog.h", + 'qfileinf.h' => "qfileinfo.h", + 'qfontdta.h' => "qfontdata.h", + 'qfontinf.h' => "qfontinfo.h", + 'qfontmet.h' => "qfontmetrics.h", + 'qgrpbox.h' => "qgroupbox.h", + 'qintcach.h' => "qintcache.h", + 'qiodev.h' => "qiodevice.h", + 'qlcdnum.h' => "qlcdnumber.h", + 'qlined.h' => "qlineedit.h", + 'qlist.h' => "qptrlist.h", + 'qmenudta.h' => "qmenudata.h", + 'qmetaobj.h' => "qmetaobject.h", + 'qmlined.h' => "qtmultilineedit.h", + 'qmsgbox.h' => "qmessagebox.h", + 'qmultilinedit.h' => "qmultilineedit.h", + 'qobjcoll.h' => "qobjectlist.h>\n\#include <qobjectdict.h", + 'qobjdefs.h' => "qobjectdefs.h", + 'qpaintd.h' => "qpaintdevice.h", + 'qpaintdc.h' => "qpaintdevicedefs.h", + 'qpdevmet.h' => "qpaintdevicemetrics.h", + 'qpmcache.h' => "qpixmapcache.h", + 'qpntarry.h' => "qpointarray.h", + 'qpopmenu.h' => "qpopupmenu.h", + 'qprndlg.h' => "qprintdialog.h", + 'qprogbar.h' => "qprogressbar.h", + 'qprogdlg.h' => "qprogressdialog.h", + 'qpsprn.h' => "private/qpsprinter_p.h", + 'qpushbt.h' => "qpushbutton.h", + 'qqueue.h' => "qptrqueue.h", + 'qradiobt.h' => "qradiobutton.h", + 'qrangect.h' => "qrangecontrol.h", + 'qscrbar.h' => "qscrollbar.h", + 'qsocknot.h' => "qsocketnotifier.h", + 'qstack.h' => "qptrstack.h", + 'qtabdlg.h' => "qtabdialog.h", + 'qtstream.h' => "qtextstream.h", + 'qvector.h' => "qptrvector.h", + 'qwidcoll.h' => "qwidgetlist.h>\n\#include <qwidgetintdict.h", + 'qwindefs.h' => "qwindowdefs.h", + +# and now the KDE specific compat includes + 'kapp.h' => "kapplication.h", + 'kstddirs.h' => "kstandarddirs.h", + 'kuniqueapp.h' => "kuniqueapplication.h", + 'ktmainwindow.h'=> "kmainwindow.h", + 'kcolorbtn.h' => "kcolorbutton.h", + 'kcolordlg.h' => "kcolordialog.h", + 'kxmlgui.h' => "kxmlguifactory.h", + 'kdebugclasses.h' => "kdebug.h", +); + + +# now it starts to get interesting again + +# Look for source files in the given directory ($dir, first parameter) +sub find_fixable_sources ($) +{ + # for now I grep the directory (requires srcdir==builddir) + # actually it should read the Makefile and + # find the _SOURCES / _OBJECTS tags that are put there by + # automake and am_edit, but thats an excercise to the reader ;-) + + my ( $dir ) = @_; + + opendir (DIR, "$dir") || die "Couldn't read '$dir'\n"; + my @sources = grep { /^.*\.$cppExt$/o } readdir(DIR); + closedir(DIR); + + print "found sources: [ " . join(' ', @sources) . " ] in $dir\n" if ($verbose); + + # prefix them with $dir + my @retsources = (); + foreach $source(@sources) { + push @retsources, "$dir/$source"; + } + + return @retsources; +} + +# Look for header files in the given directory ($dir, first parameter) +sub find_fixable_headers ($) +{ + # for now I grep the directory (requires srcdir==builddir) + # actually it should read the Makefile and + # find the _HEADERS tags that are put there by + # automake and am_edit, but thats an excercise to the reader ;-) + + my ( $dir ) = @_; + + opendir (DIR, "$dir") || die "Couldn't read '$dir'\n"; + my @headers = grep { /^.*\.$hExt$/o } readdir(DIR); + closedir(DIR); + + print "found headers: [ " . join(' ', @headers) . " ] in $dir\n" if ($verbose); + + # prefix them with $dir + my @retheaders = (); + foreach $source(@headers) { + push @retheaders, "$dir/$source"; + } + + return @retheaders; +} + +sub find_removable_includes ($) +{ + my $srcfile = shift @_; + open(SRC, "< $srcfile") || die "find_removable_includes: couldn't open '$srcfile'\n"; + + my @includes = (); + + # we skip all includes that are somehow ifdefed + + my $cpplevel = 0; + $cpplevel = -1 if ($srcfile=~m/^.*\.$hExt$/); # plan for header-protection #ifndef/#define/#endif + while (<SRC>) { + if ($_ =~ m/^\#if/) { + $cpplevel = $cpplevel + 1; + next; + } + if ($_ =~ m/^\#endif/) { + $cpplevel = $cpplevel - 1; + next; + } + #if ($cpplevel == 0 && $_ =~ m/^\#include\s*[\"<]([qk]\S*\.h)[\">]\S*/) { + if ($cpplevel == 0 && (($_ =~ m/^\#include\s*\"(\S+\.h)\"\S*/) || ($_ =~ m/^\#include\s*\<([qk]\S+.h)\>\S*/))) { + push @includes, $1; + next; + } + } + close SRC; + + print "No fixable includes found in $srcfile\n" if ($verbose and not @includes); + print "found includes: [ " . join(' ', @includes) . " ]\n" if ($verbose and @includes); + + return @includes; +} + +sub find_installed_headers($) +{ + my $sdir = shift @_; + my @includes = (); + + open(I, "<$sdir/Makefile.am") || die "couldn't open $sdir/Makefile.am $!"; + + my $data = join('', <I>); + $data =~ s/\\\s*\n/ /g; + + # now search for not installed headers + foreach my $line (split /^/, $data) { + if($line =~ /^(\w+)_HEADERS\s*=(.*)$/) { + next if $1 eq "noinst"; + push @includes, split (' ', $2); + } + } + close(I); + return @includes; +} + +# first parameter: srcfile +# second parameter: include to remove +# third parameter is the duplicate level: this include is removed $level times +sub remove_include ($$$) +{ + my $srcfile = shift @_; + my $include = quotemeta(shift @_); + my $level = shift @_; + + die "$srcfile is not read/writeable!\n" if( ! -r $srcfile || ! -w $srcfile); + open(I, "< $srcfile") or die "remove_include: couldn't open '$srcfile'\n"; + my @contents = <I>; + close(I); + + # ok, CPU time doesn't count so we do it the lazy way + # we should remove the last occurence of the include in the + # file because in case its a duplicate removing the first + # one could make a difference. + my @revcontents = reverse @contents; + @contents = (); + + # we skip all inludes that are somehow ifdefed + # note the logic is reversed because it operates + # on reversed lines :) + my $cpplevel = 0; + $cpplevel = -1 if ($srcfile=~m/^.*\.$hExt$/); # plan for header-protection #ifndef/#define/#endif + foreach $line (@revcontents) { + if ($line =~ m/^\#if/) { + $cpplevel = $cpplevel - 1; + push @contents, $line; + next; + } + + if ($line =~ m/^\#endif/) { + $cpplevel = $cpplevel + 1; + push @contents, $line; + next; + } + + if ($level && $cpplevel == 0 && + (($line =~ m/^\#include\s*\"$include\"\S*/) || ($line =~ m/^\#include\s*\<$include\>\S*/))) { + $level = $level - 1; + # skipping the line.. + next; + } + + push @contents, $line; + } + + # now we have the fixed contents in @contents, although in wrong order + open(O, "> $srcfile") || die "remove_include: couldn't open '$srcfile' for writing\n"; + print O reverse @contents; + close (O); +} + +# first parameter: srcfile +# second parameter: include to replace +# third parameter the include file to replace it with +sub replace_include ($$$) +{ + my $srcfile = shift @_; + my $include = quotemeta(shift @_); + my $destinclude = shift @_; + + die "$srcfile is not read/writeable!\n" if( ! -r $srcfile || ! -w $srcfile); + open(I, "< $srcfile") or die "replace_include: couldn't open '$srcfile'\n"; + my @contents = <I>; + close(I); + + # ok, CPU time doesn't count so we do it the lazy way + my @revcontents = reverse @contents; + @contents = (); + + # we skip all inludes that are somehow ifdefed + # note the logic is reversed because it operates + # on reversed lines :) + my $cpplevel = 0; + $cpplevel = -1 if ($srcfile=~m/^.*\.$hExt$/); # plan for header-protection #ifndef/#define/#endif + foreach $line (@revcontents) { + if ($line =~ m/^\#if/) { + $cpplevel = $cpplevel - 1; + push @contents, $line; + next; + } + + if ($line =~ m/^\#endif/) { + $cpplevel = $cpplevel + 1; + push @contents, $line; + next; + } + + if ($cpplevel == 0 && + (($line =~ m/^\#include\s*\"$include\"\S*/) || ($line =~ m/^\#include\s*\<$include\>\S*/))) + { + print "HAH! found $include to replace in $srcfile!\n" if($verbose); + $line =~ s/(\#include\s*[\"<])$include([\">]\S*)/$1$destinclude$2/; + } + + push @contents, $line; + } + + # now we have the fixed contents in @contents + open(O, "> $srcfile") || die "replace_include: couldn't open '$srcfile' for writing\n"; + print O reverse @contents; + close (O); +} + +# fixes #include <foo.h> -> #include "foo.h" +sub replace_include_type ($$) +{ + my ($srcfile, $include) = @_; + + die "$srcfile is not read/writeable!\n" if( ! -r $srcfile || ! -w $srcfile); + open(I, "< $srcfile") or die "replace_include: couldn't open '$srcfile'\n"; + my @contents = <I>; + close(I); + + grep(s/^(\#include)\s*<$include>(.*)$/$1 \"$include\"$2/, @contents); + + # now we have the fixed contents in @contents + open(O, "> $srcfile") || die "replace_include: couldn't open '$srcfile' for writing\n"; + print O @contents; + close (O); +} + +sub fix_duplicates($) +{ + my $srcfile = shift @_; + + my @includes = &find_removable_includes($srcfile); + + my %inclMap = (); + + # initialize + foreach $include (@includes) { + $inclMap{$include} = 0; + } + + # count number of occurences + foreach $include (@includes) { + $inclMap{$include} = $inclMap{$include} + 1; + } + + # check for duplicates + foreach $include (keys %inclMap) { + next if $inclMap{$include} <= 1; + + print "$srcfile: duplicate level ". $inclMap{$include} .": ". $include ."\n"; + + &remove_include($srcfile, $include, $inclMap{$include} - 1) if($modify); + } +} + +sub extract_gcc_error($) +{ + my $out = shift; + + # print "out: $out\n"; + + while ($out =~ m/^(.*?):([0-9]+):(.*)$/mg) # filename:lineno:message + { + my $field1 = $1 || ""; + my $field2 = $2 || ""; + my $field3 = $3 || ""; + + # print "f1: $field1, f2: $field2, f3: $field3\n"; + + next if ($field3 =~ m/\s+warning:.*/); + next if ($field3 =~ m/^\s*$/); + return basename($field1); + } + return "BUG!"; +} + +sub fix_compat_includes($) +{ + my $srcfile = shift @_; + + my @includes = &find_removable_includes($srcfile); + + my %inclMap = (); + + # initialize + foreach $include (@includes) { + $inclMap{$include} = 0; + } + + # count number of occurences + foreach $include (@includes) { + $inclMap{$include} = $inclMap{$include} + 1; + } + + # check for compat headers + foreach $include (keys %inclMap) { + if( defined $compatmap{$include}) { + print "$srcfile: compat header: $include, to be replaced by ". $compatmap{$include} ."\n"; + &replace_include($srcfile, $include, $compatmap{$include}) if($modify); + } + } +} + +sub fix_include_type($) +{ + my $srcfile = shift @_; + my $srcdir = dirname($srcfile); + + open(I, "<$srcfile") || die "couldn't open $srcfile in _fix_include_type"; + my @bracketincs = grep s/^\s*\#include\s*<([^>]+)>\s*$/$1/, <I>; + close(I); + + foreach my $include (@bracketincs) { + next if (!(-r "$srcdir/$include")); + next if (grep (/^$include$/, @instheaders)); + next if ($include eq "config.h"); # oh don't get me started on that + + print "$srcfile: #include <$include> should use #include \"...\"\n"; + &replace_include_type($srcfile, $include) if($modify); + } +} + +# copies a file from src to dest, overwrites destination if exists +sub copy_file($$) +{ + my $src = shift(@_); + my $dst = shift(@_); + + open(I, "< $src") or die "copy_file: can't open $src for input\n"; + my @fcontents = <I>; + close(I); + open(O, "> $dst") or die "copy_file: can't open $dst for output\n"; + print O @fcontents; + close(O); +} + +# interrupt handler for fix_unnecessary +sub sighandler_fix_unnecessary() +{ + my($sig) = @_; + print "Caught a SIG$sig--shutting down after restoring $srcfile\n"; + chdir($srcdir); + unlink $srcfile || warn "couldn't unlink $srcfile"; + rename $localbackup, $srcfile || warn "couldn't rename $localbackup to $srcfile"; + exit(1); +} + +sub fix_unnecessary($) +{ + local $srcfile = shift @_; + local $srcdir = dirname($srcfile); + + # find canonical path for srcdir + my $origdir = cwd; + chdir($srcdir); + $srcdir = cwd; + print "srcdir=$srcdir\n" if($verbose); + + my $builddir = $srcdir; + my $makecmd = "make"; + if (defined $ENV{"OBJ_REPLACEMENT"}) + { + # we have to use sed here, because perl can't do s#a#b# + $builddir = `echo $srcdir | sed -e "\$OBJ_REPLACEMENT"`; + chomp $builddir; + $makecmd = "makeobj"; + } + print "builddir=$builddir\n" if($verbose); + + my $tot = $exp_success + $exp_failure; + print "=============== $srcfile (successes: $exp_success; total: $tot)\n"; + + $srcfile = basename($srcfile); + + # first figure out some details + my @includes = &find_removable_includes($srcfile); + + my $blanksrc = $srcfile; + $blanksrc =~ s/(.*)\.[^\.]+/$1/; + + print "Checking for initial compilation: "; + chdir($builddir); + my $objextension = "BUG"; + if($srcfile =~ /\.$hExt$/o) { + $output = `$makecmd all 2>&1`; + $objextension = "all" if ( 0 == ($? >> 8)); + } + else { + unlink "$blanksrc.lo"; + my $output = `$makecmd $blanksrc.lo 2>&1`; + $objextension = ".lo" if ( 0 == ($? >> 8)); + if($objextension eq "BUG") { + print "failed with .lo... "; + unlink "$blanksrc.o"; + $output = `$makecmd $blanksrc.o 2>&1`; + $objextension = ".o" if ( 0 == ($? >> 8)); + } + if($srcfile =~ /$hExt/) { + $output = `$makecmd $blanksrc.o 2>&1`; + $objextension = ".o" if ( 0 == ($? >> 8)); + } + } + if($objextension eq "BUG") { + warn "can't figure out right compile command for $srcfile :-(\n" . + "??? unused, or didn't compile in the first place?\n" . + "$output"; + chdir($origdir); + exit 1; + } + + print "worked with $objextension\n"; + + # now try to drop some includes + foreach $include (@includes) { + # kdatastream is special because + # it will break the application if removed even + # if it continues to compile + next if( $include eq "kdatastream.h"); + # I also like to have kdebug.h still in + # so that it's easy to add kdDebug calls + next if( $include eq "kdebug.h"); + # avoid this one as it might cause + # certain code parts to be disabled from compilation + next if( $include eq "qmodules.h"); + # don't remove this one either. causes conditional + # code to be compiled incorrectly + next if( $include eq "kdeversion.h"); + # don't remove the config.h include + # conditional code may depend on this file + next if( $include eq "config.h"); + # check if it is its own header file + my $blankhdr = $include; + $blankhdr =~ s/(.*)\.[^\.]+/$1/; + next if ($blankhdr eq $blanksrc); + + chdir($srcdir); + + local $localbackup = $srcfile . "#fixkdeincludes"; + + # preserve timestamp if possible for CVS + unlink $localbackup; + rename $srcfile, $localbackup; + copy_file($localbackup, $srcfile); + + # revert to backup in case of interrupt (Ctrl+C) + $SIG{'INT'} = \&sighandler_fix_unnecessary; + + # check if it still compiles + if($verbose) { + chdir($builddir); + # testing headers? need to compile everything + if($objextension eq "all") { + # wait a second for makefile timestamp comparisons + sleep 1; + `$makecmd all 2>&1`; + } + else { + unlink "$blanksrc$objextension"; + `$makecmd $blanksrc$objextension 2>&1`; + } + die "unexpected error $output\nexitcode=" . ($? >> 8) if($? >> 8); + chdir($srcdir); + } + + # duplicates have to be nuked here , so it will be dropped maximum once + print "trying without $include: "; + &remove_include($srcfile, $include, 1); + + chdir($builddir); + + # try if it compiles + if($objextension eq "all") { + sleep 1; + $output=`$makecmd $objextension 2>&1`; + } + else { + unlink "$builddir/$blanksrc$objextension"; + $output=`$makecmd $blanksrc$objextension 2>&1`; + } + my $retcode = ($? >> 8); + #print "retcode=$retcode\n$output" if ($verbose); + + chdir($srcdir); + if($retcode == 0) { + # wow, it worked, lets continue! + print "SUCCESS!\n"; + $SIG{'INT'} = 'DEFAULT'; + unlink $localbackup; + $exp_success = $exp_success + 1; + } + else { + # is this a fixable error? + if($objextension eq "all" and + &extract_gcc_error($output) ne $srcfile) { + print "failed (error in " . &extract_gcc_error($output) . ")\n"; + # FIXME: implement fixup of the compilation error + # so that we can be much more agressive in removing + # unneeded includes from headers + } + else + { + # better luck next time + print "FATALLY failed\n"; + } + unlink $srcfile; + rename $localbackup, $srcfile; + $SIG{'INT'} = 'DEFAULT'; + + $exp_failure = $exp_failure + 1; + } + } + + print "\n"; + + chdir($origdir); +} + +sub process_source_file($) +{ + local $file = shift @_; + my $pure = basename($file); + print "Checking: $file\n" if($verbose); + &fix_include_type($file); + &fix_compat_includes($file); + &fix_duplicates($file); + &fix_unnecessary($file) if ($experimental && !grep (/^$pure$/, @instheaders)); + print "\n" if ($verbose); +} + +sub check_for_automake_srcdir($) +{ + my $dir = shift; + + return 0 if !( -r "$dir/Makefile.am"); + return 1 if !( -r "$dir/Makefile"); + + # ok, now its either srcdir with srcdir==builddir, or its builddir, + # which we don't want. + + open(I, "<$dir/Makefile") || die "couldn't read $dir/Makefile"; + while(<I>) { + if(/^srcdir\s*=\s*(\S+)/) { + close(I); + + if($1 ne ".") { + print "Skipping build dir: $dir\n" if($verbose); + return 0; + } + return 1; + } + } + + close(I); + # ok, this makefile isn't generated by automake, we don't want that + return 0; +} + +############################################################################# +# here is the main logic +# + +# warn about modified files +if($modify) { + `cvscheck | grep '^[MmC]'`; + print "WARNING: you have pending local changes. You might commit them by accident!\n\n" if($? >> 8 == 0); +} + +if($experimental) { + print "WARNING: The experimental mode is indeed experimental.\n"; + print "It tries to reduce includes by testing if it would compile\n"; + print "without a particular include. It might introduce subtle bugs\n"; + print "or break compilation for make check or make final.\n\n"; + print "This operation mode is known to be unsafe. You've been warned.\n"; +} + +# process files from the command line, if any +if ( $#explicitfiles >= 0 ) { + foreach $file( @explicitfiles ) { + &process_source_file( $file ); + } + exit 0; +} + +# first generate a list of subdirectories +@dirlist = (); +push @dirlist, "." if (&check_for_automake_srcdir(".")); +die "current directory isn't srcdir!" if (!scalar @dirlist); +foreach $dir ( @dirlist ) { + opendir (DIR, "$dir") || warn "Couldn't read '$dir'"; + my $subdir = ""; + while( $subdir = readdir(DIR)) { + next if ($subdir =~ /^\./); + next if !( -d "$dir/$subdir"); + next if (! &check_for_automake_srcdir("$dir/$subdir")); + + push @dirlist, "$dir/$subdir"; + } + closedir(DIR); +} + +# now iterate over all subdirs +foreach $dir(@dirlist) { + + # check if this directory wants not to be fixed + if(open(M, "$dir/Makefile.am")) { + my @mcontents = grep /(\-UQT_NO_COMPAT|\-UKDE_NO_COMPAT)/, <M>; + close(M); + if ( @mcontents ) { + print "Skipping directory: $dir\n"; + next; + } + } + + @headers = &find_fixable_headers($dir); + @instheaders = &find_installed_headers($dir); + foreach $file(@headers) { + &process_source_file($file); + } + @sources = &find_fixable_sources($dir); + foreach $file(@sources) { + &process_source_file($file); + } +} diff --git a/scripts/fixuifiles b/scripts/fixuifiles new file mode 100755 index 00000000..785b45b4 --- /dev/null +++ b/scripts/fixuifiles @@ -0,0 +1,293 @@ +#!/usr/bin/perl -w +# fixuifiles processes .ui files and removes some insanity: +# * Too high minimum Qt version (see $minversion_* in the top of the script) +# * Hardcoded untranslatable Alt+Letter accels (auto-added by Qt Designer) +# * Captions that are equal to classname (auto-added by Qt Designer) + +# This script is licensed under the GPL version 2. +# (c) 2004 David Faure <faure@kde.org> +# Based on fixkdeincludes, (c) 2001-2003 Dirk Mueller <mueller@kde.org> + +use strict; +use File::Basename; +use Cwd; + +# Fix the version number in .ui files if it's bigger than this: +my $default_minversion_maj = 3; +my $default_minversion_min = 3; + +# Known words which are ok as captions +my %knowncaptions = ( + 'Settings' => '', + 'Statistics' => '', + 'General' => '', + 'Tracks' => '', + 'Constants' => '', + 'Preferences' => '', + 'Encryption' => '' +); + +# declaration of useful subroutines +sub process_ui_file($); +sub find_ui_files($); +sub read_required_version($); + +# some global variables +my $verbose = 0; # turns on debugging +my $omit_Qt_check = 0; # turns off Qt version checking +my @explicitfiles = (); # filled in if passing files on the command line +my $minversion_maj = $default_minversion_maj; +my $minversion_min = $default_minversion_min; + +while (defined ($ARGV[0])) +{ + $_ = shift; + if (/^--help$|^-h$/) { + print "Usage: fixuifiles [OPTIONS] files...\n"; + print "Options are:\n"; + print "\t-v, --verbose\tBe verbose\n"; + print "\t--omitqtcheck\tDoes not check for Qt minimum version\n"; + exit 0; + } + elsif (/^--verbose$|^-v$/) { + $verbose = 1; + }elsif (/^--omitqtcheck/) { + $omit_Qt_check = 1; + } + elsif (!/^-/) { + push @explicitfiles, $_; + } +} + +# Find .ui files in the given dir +sub find_ui_files($) +{ + my ( $dir ) = @_; + + opendir (DIR, "$dir") || die "Couldn't read '$dir'\n"; + my @files = grep { /^.*\.ui$/ } readdir(DIR); + closedir(DIR); + + #print "found files: [ " . join(' ', @files) . " ] in $dir\n" if ($verbose); + + # prefix them with $dir + my @retfiles = (); + foreach my $file(@files) { + push @retfiles, "$dir/$file"; + } + + return @retfiles; +} + +# Ensure the version at the top of the file is not too high +sub fix_version($) +{ + my $srcfile = shift @_; + open(SRC, "< $srcfile") || die "fix_version: couldn't open '$srcfile'\n"; + my @contents = <SRC>; + my @fixedcontents = (); + close(SRC); + my $needfix = 0; + my $foundversion = 0; + foreach my $line (@contents) { + if (!$foundversion && $line =~ m/version=\"([0-9]+)\.([0-9]+)(\.[0-9]+)?\"/) { + my $version_maj = $1; + my $version_min = $2; + if ( $version_maj > $minversion_maj || + ( $version_maj == $minversion_maj && $version_min > $minversion_min ) ) { + $line =~ s/version=\"[0-9]+\.[0-9]+\"/version=\"$minversion_maj.$minversion_min\"/o; + $needfix = 1; + print "$srcfile: version was $version_maj.$version_min, set to $minversion_maj.$minversion_min\n"; + } + $foundversion = 1; + } + push @fixedcontents, $line; + } + if (!$foundversion) { + # TODO improve so that the script adds the necessary line + print "$srcfile has no UI version, please fix it\n"; + } + if ($needfix) { + open(SRC, "> $srcfile") || die "fix_version: couldn't open '$srcfile' for writing\n"; + print SRC @fixedcontents; + close(SRC); + } +} + +# Ensure no auto-added Alt+letter accel exists - those are untranslatable +sub fix_accels($) +{ + my $srcfile = shift @_; + open(SRC, "< $srcfile") || die "fix_accels: couldn't open '$srcfile'\n"; + my @contents = <SRC>; + close(SRC); + return if ( !grep( /<string>Alt\+[A-Z]<\/string>/, @contents )); + my @fixedcontents = (); + + my $firstline; + my $accelsremoved = 0; + my $inside_accel = 0; + # inside_accel is 0 before <property> + # 1 after <property> and before <string> + # 2 after <string> if alt+letter, and before </property> + foreach my $line (@contents) { + if ( $inside_accel == 1 ) { + if ( $line =~ m/<string>(Alt\+[A-Z])<\/string>/ ) { + print "$srcfile: accel $1 removed\n" if ($verbose); + $inside_accel = 2; + $accelsremoved++; + } else { # Not alt+letter, keep accel + push @fixedcontents, $firstline; + $inside_accel = 0; + } + } + if ($line =~ m/property name=\"accel\"/) { + $inside_accel = 1; + $firstline = $line; + } + if ($inside_accel == 0) { + push @fixedcontents, $line; + } + $inside_accel = 0 if ($inside_accel && $line =~ m/<\/property>/); + } + if ($accelsremoved) { + print "$srcfile: $accelsremoved accels removed\n"; + open(SRC, "> $srcfile") || die "fix_accels: couldn't open '$srcfile' for writing\n"; + print SRC @fixedcontents; + close(SRC); + } +} + +# Ensure no auto-added caption exists - it's pretty stupid to have to +# translate Form1 or MyClassName +sub fix_captions($) +{ + my $srcfile = shift @_; + open(SRC, "< $srcfile") || die "fix_captions: couldn't open '$srcfile'\n"; + my @contents = <SRC>; + close(SRC); + my @fixedcontents = (); + + my $firstline; + my $class = ""; + my $captionsremoved = 0; + my $inside_caption = 0; + # inside_caption is 0 before <property> + # 1 after <property> and before <string> + # 2 after <string> if caption should be removed, and before </property> + foreach my $line (@contents) { + $class = $1 if ($line =~ m/<class>(.*)<\/class>/); + if ( $inside_caption == 1 ) { + $line =~ m/<string>(.*)<\/string>/ || die "Malformed XML (no string under caption)"; + my $caption = $1; + print "$srcfile: caption='$caption' class='$class'\n" if ($verbose); + if ( ( $caption eq $class && !defined $knowncaptions{$caption} ) || + ($caption =~ m/Form[0-9]/) ) { + if ( $caption =~ m/^[A-Z][a-z]*$/ ) { + print "$srcfile: removing caption '$caption' (warning! could be real caption)\n"; + } else { + print "$srcfile: removing caption '$caption'\n"; + } + $inside_caption = 2; + $captionsremoved++; + } else { # Real caption, keep it + print "$srcfile: keeping caption '$caption'\n" if ($verbose); + push @fixedcontents, $firstline; + $inside_caption = 0; + } + } + if ($line =~ m/property name=\"caption\"/) { + $inside_caption = 1; + $firstline = $line; + } + if ($inside_caption == 0) { + push @fixedcontents, $line; + } + $inside_caption = 0 if ($inside_caption && $line =~ m/<\/property>/); + } + if ($captionsremoved) { + open(SRC, "> $srcfile") || die "fix_captions: couldn't open '$srcfile' for writing\n"; + print SRC @fixedcontents; + close(SRC); + } +} + +# Find a .qt_minversion in $dir or any parent directory. +sub read_required_version($) +{ + my $dir = Cwd::abs_path( shift @_ ); + + $minversion_maj = $default_minversion_maj; + $minversion_min = $default_minversion_min; + while ( length($dir) > 1 ) { + my $versfile = "$dir/.qt_minversion"; + my $version; + if ( open (VERSFILE, "< $versfile") ) { + while (<VERSFILE>) { + $version = $_ if (!/^#/); + } + close(VERSFILE); + } else { + $versfile = "$dir/configure.in.in"; + if ( open (VERSFILE, "< $versfile") ) { + while (<VERSFILE>) { + $version = $1 if m/^#MIN_CONFIG\(([0-9]+.[0-9]+)\)/; + } + close(VERSFILE); + } + } + if (defined $version && $version =~ m/([0-9]+)\.([0-9]+)/) { + $minversion_maj = $1; + $minversion_min = $2; + print "Found min version $1.$2 in $versfile\n" if ($verbose); + return; + } + $dir = dirname($dir); + } +} + +# Process one .ui file +sub process_ui_file($) +{ + my $file = shift @_; + &read_required_version( dirname($file) ); + + print "Checking: $file\n" if($verbose); + &fix_version($file) if(!$omit_Qt_check); + &fix_accels($file); + &fix_captions($file); +} + +############################################################################# +# here is the main logic +# + +# process files from the command line, if any +if ( $#explicitfiles >= 0 ) { + foreach my $file( @explicitfiles ) { + &process_ui_file( $file ); + } + exit 0; +} + +# first generate a list of subdirectories +my @dirlist = (); +push @dirlist, "."; +foreach my $dir ( @dirlist ) { + opendir (DIR, "$dir") || warn "Couldn't read '$dir'"; + my $subdir = ""; + while( $subdir = readdir(DIR)) { + next if ($subdir =~ /^\./); + next if !( -d "$dir/$subdir"); + push @dirlist, "$dir/$subdir"; + } + closedir(DIR); +} + +# now iterate over all subdirs +foreach my $dir(@dirlist) { + my @uifile = find_ui_files($dir); + foreach my $file(@uifile) { + &process_ui_file($file); + } +} diff --git a/scripts/gettext.patch b/scripts/gettext.patch new file mode 100644 index 00000000..9470c6f9 --- /dev/null +++ b/scripts/gettext.patch @@ -0,0 +1,194 @@ +diff -ru src.orig/xget-lex.c src/xget-lex.c +--- src.orig/xget-lex.c Fri May 1 06:45:12 1998 ++++ src/xget-lex.c Fri Apr 27 16:05:06 2001 +@@ -78,17 +78,18 @@ + + enum token_type_ty + { +- token_type_character_constant, +- token_type_eof, +- token_type_eoln, +- token_type_hash, +- token_type_lp, +- token_type_comma, +- token_type_name, +- token_type_number, +- token_type_string_literal, +- token_type_symbol, +- token_type_white_space ++ token_type_character_constant = 0, ++ token_type_eof = 1, ++ token_type_eoln = 2, ++ token_type_hash = 3, ++ token_type_lp = 4, ++ token_type_rp = 5, ++ token_type_comma = 6, ++ token_type_name = 7, ++ token_type_number = 8, ++ token_type_string_literal = 9, ++ token_type_symbol = 10, ++ token_type_white_space = 11 + }; + typedef enum token_type_ty token_type_ty; + +@@ -941,6 +942,10 @@ + tp->type = token_type_lp; + return; + ++ case ')': ++ tp->type = token_type_rp; ++ return; ++ + case ',': + tp->type = token_type_comma; + return; +@@ -1236,6 +1241,11 @@ + tp->type = xgettext_token_type_lp; + return; + ++ case token_type_rp: ++ last_non_comment_line = newline_count; ++ tp->type = xgettext_token_type_rp; ++ return; ++ + case token_type_comma: + last_non_comment_line = newline_count; + +diff -ru src.orig/xget-lex.h src/xget-lex.h +--- src.orig/xget-lex.h Fri May 1 06:45:23 1998 ++++ src/xget-lex.h Fri Apr 27 16:05:06 2001 +@@ -22,13 +22,14 @@ + + enum xgettext_token_type_ty + { +- xgettext_token_type_eof, +- xgettext_token_type_keyword1, +- xgettext_token_type_keyword2, +- xgettext_token_type_lp, +- xgettext_token_type_comma, +- xgettext_token_type_string_literal, +- xgettext_token_type_symbol ++ xgettext_token_type_eof = 0, ++ xgettext_token_type_keyword1 = 1, ++ xgettext_token_type_keyword2 = 2, ++ xgettext_token_type_lp = 3, ++ xgettext_token_type_rp = 4, ++ xgettext_token_type_comma = 5, ++ xgettext_token_type_string_literal = 6, ++ xgettext_token_type_symbol = 7 + }; + typedef enum xgettext_token_type_ty xgettext_token_type_ty; + +diff -ru src.orig/xgettext.c src/xgettext.c +--- src.orig/xgettext.c Wed Apr 29 18:57:50 1998 ++++ src/xgettext.c Fri Apr 27 16:33:46 2001 +@@ -835,7 +835,8 @@ + int is_cpp_file; + { + int state; +- ++ char *msgid = 0; ++ + /* Inform scanner whether we have C++ files or not. */ + if (is_cpp_file) + xgettext_lex_cplusplus (); +@@ -861,8 +862,12 @@ + State 3 = seen one of our keywords with string in second parameter + State 4 = was in state 3 and now saw a left paren + State 5 = waiting for comma after being in state 4 +- State 6 = saw comma after being in state 5 */ ++ State 6 = saw comma after being in state 5 ++ State 7 = after comma and being in state 2 ++ State 8 = after string and being in state 7 ++ */ + xgettext_lex (&token); ++ + switch (token.type) + { + case xgettext_token_type_keyword1: +@@ -886,18 +891,62 @@ + state = 0; + } + continue; ++ ++ case xgettext_token_type_rp: ++ if (state == 2 || state == 8) { ++ token.string = strdup(msgid); ++ remember_a_message (mlp, &token); ++ free(msgid); ++ msgid = 0; ++ state = 0; ++ } ++ continue; + + case xgettext_token_type_comma: +- state = state == 5 ? 6 : 0; ++ switch (state) { ++ case 5: ++ state = 6; ++ break; ++ case 2: ++ state = 7; ++ break; ++ case 8: { ++ char *newstring = (char*)malloc(strlen(msgid) + 2); ++ strcpy(newstring, "_n:"); ++ strcat(newstring, msgid + 2); ++ free(msgid); ++ token.string = newstring; ++ remember_a_message (mlp, &token); ++ msgid = 0; ++ state = 0; ++ break; ++ } ++ default: ++ state = 0; ++ break; ++ } + continue; + + case xgettext_token_type_string_literal: + if (extract_all || state == 2 || state == 6) + { +- remember_a_message (mlp, &token); +- state = 0; ++ if (msgid) ++ free(msgid); ++ msgid = strdup(token.string); ++ // state = 0; + } +- else ++ else if (state == 7) ++ { ++ if (msgid) { ++ char *newstring = (char*)malloc(strlen(msgid) + strlen(token.string) + 20); ++ sprintf(newstring, "_: %s\n%s", msgid, token.string); ++ free(msgid); ++ free(token.string); ++ token.string = msgid = newstring; ++ state = 8; ++ } ++ } ++ else + { + free (token.string); + state = (state == 4 || state == 5) ? 5 : 0; +@@ -905,8 +954,8 @@ + continue; + + case xgettext_token_type_symbol: +- state = (state == 4 || state == 5) ? 5 : 0; +- continue; ++ state = (state == 4 || state == 5) ? 5 : 0; ++ continue; + + default: + state = 0; +@@ -915,6 +964,7 @@ + case xgettext_token_type_eof: + break; + } ++ + break; + } + diff --git a/scripts/includemocs b/scripts/includemocs new file mode 100755 index 00000000..32df1b20 --- /dev/null +++ b/scripts/includemocs @@ -0,0 +1,102 @@ +#! /usr/bin/env perl + +use strict; +use Cwd; +use File::Find; + +my %dir2files=(); +my $cppExt=" cpp cc cxx C c++ "; +my $cppFiles="*.cpp *.cc *.cxx *.C *.c++"; + +sub collectthing() +{ + if (/\.([^.]+)$/) { + my $ext=$1; + if (" h H hh hxx h++ " =~ / $ext /) { + my $line=`grep -l '^[{ \t]*Q_OBJECT' $_ 2> /dev/null`; + chomp($line); + if ($line) { + $dir2files{$File::Find::dir}->{headers}->{$_} = 1; + } + } elsif ($cppExt =~ / $ext /) { + $dir2files{$File::Find::dir}->{sources}->{$_} = 1; + } + } +} + +sub checkdir($) +{ + my ($dir)=@_; + chdir($dir); + my $hdrs=$dir2files{$dir}->{headers}; + my $srcs=$dir2files{$dir}->{sources}; + foreach my $h (keys %$hdrs) { + (my $name=$h) =~ s/\.[^.]+$//; + my @answer = `grep -l "^#include[ ]*.$name\.moc." $cppFiles 2> /dev/null`; + if (@answer == 0) { + my $s; + foreach my $e (split(/\s+/, $cppExt)) { + if (exists $srcs->{$name.".".$e}) { + $s=$dir."/".$name.".".$e; last; + } + } + if ($s) { + print "echo >> $s ;\n"; + print "echo '#include \"$name.moc\"' >> $s ;\n"; + } else { + print "echo \"can't guess a C++ file for $dir/$h\" ;\n"; + } + } + } +} + +find (\&collectthing, cwd()); + +foreach my $k (keys %dir2files) { + print STDERR "Directory $k:\n headers=["; + print STDERR join(", ", keys %{$dir2files{$k}->{headers}}); + print STDERR "]\n sources=["; + print STDERR join(", ", keys %{$dir2files{$k}->{sources}}); + print STDERR "]\n"; + checkdir($k); +} + +=head1 NAME + +includemocs -- handle mocifyable headers, whose .moc file is nowhere included. + +=head1 SYNOPSIS + + includemocs + +=head1 DESCRIPTION + +Header files declaring a QObject descendant have to be run through moc to +produce a .moc file. This .moc file has to be compiled, for which two +possibilities exists: compile it separately, or #include it in the C++ file +implementing that above mentioned class. The latter is more efficient in term +of compilation speed. + +This script searches in the current directory and its subdirs for header files +declaring a QObject descendant class. If it finds some, it looks, if there is +a C++ file containing an '#include' for the generated .moc file. If thats not +the case, it tries to guess into which C++ file that '#include' is placed best +(based on the filename). If it fails to guess a proper place, it mentions +that. + +On stdout commands are ouput, suitable for a shell, which, when +evaluated, add the suggested '#include' at the end of the files. + +On stderr some informational messages are printed. + +=head1 EXAMPLES + + cd kdebase ; includemocs + cd kdebase ; `eval includemocs 2> /dev/null` + +=head1 AUTHOR + +Michael Matz <matz@ifh.de> + +=cut + diff --git a/scripts/kDebug2kdDebug.sh b/scripts/kDebug2kdDebug.sh new file mode 100755 index 00000000..a238845e --- /dev/null +++ b/scripts/kDebug2kdDebug.sh @@ -0,0 +1,154 @@ +## kDebug2kdDebug.sh +## Script to port from qDebug, kdebug, kDebugInfo etc. to kdDebug/kdWarning/... +## Example: +## kDebugInfo( [area,] "format %a - %b", arga, argb ) +## becomes +## kdDebug( [area] ) << "format " << arga << " - " << argb << endl; +## +## Written by David Faure <faure@kde.org>, licensed under GPL. +## 17/03/2000 + +find $1 -name '*[cCph]' -type f | xargs grep -H -i 'ebug(\|warning(' \ +| grep -v 'kdDebug\|kdWarning' \ +| grep -v include \ +| sed -e "s#:.*##" \ +| sort -u \ +| while read file; do +echo -n "working on $file " +cp $file $file.tmp +perl -w -i -e \ +' +$inkdebug=0; +while (<>) +{ + if ( $inkdebug ) + { + chop; + #print "Reading line : " . $_ . "\n"; + $statement .= $_; + } + elsif ( /kdebug\s*\(/ || /kDebug[a-zA-Z]*\s*\(/ || /qDebug\s*/ || /qWarning\s*/ ) + { + # Very old kdebug stuff :) + s/kdebug\s*\(\s*KDEBUG_INFO,/kDebugInfo\(/; + s/kdebug\s*\(\s*0,/kDebugInfo\(/; + s/kdebug\s*\(\s*KDEBUG_WARN,/kDebugWarning\(/; + s/kdebug\s*\(\s*KDEBUG_ERROR,/kDebugError\(/; + s/kdebug\s*\(\s*KDEBUG_FATAL,/kDebugFatal\(/; + + $inkdebug = 1; + chop; + $statement = $_; + } + + if ( $inkdebug ) + { + if ( /\)\s*;/ ) # look for ); + { + $inkdebug = 0; + $_ = $statement; + ## Ok, now we have the full line + ## 1 - Parse + if (s/(^.*kDebug[a-zA-Z]*)\s*\(\s*//) { + $line=$1; # has the indentation, //, and the kDebug* name + } elsif (s/(^.*qDebug)\s*\(\s*// || s/(^.*qWarning)\s*\(\s*//) { + $line=$1; + } else { die "parse error on kDebug/qDebug/qWarning..."; } + $line=$1; # has the indentation, //, and the kDebug* name + $line =~ s/kDebugInfo/kdDebug/; + $line =~ s/kDebugArea/kdDebug/; + $line =~ s/qDebug/kdDebug/; + $line =~ s/qWarning/kdWarning/; + $line =~ s/kDebugWarning/kdWarning/; + $line =~ s/kDebugError/kdError/; + $line =~ s/kDebugFatal/kdFatal/; + $area = ""; + if ( s/^([0-9]+)\s*,\s*//) # There is an area + { + $area = $1; # Store it + $line .= "(" . $area . ")"; + } elsif ( s/^(KBABEL[^,]*)\s*,\s*//) + { # Example of support for #defined area (here KBABEL.*) + $area = $1; # Store it + $line .= "(" . $area . ")"; + } else + { $line .= "()"; } # You can set an area here if converting qDebugs + + $arguments = ""; # for final test + $commented = 0; + if ( !s/^\"([^\"]*)\"// ) # There is no format + { + s/\s*\)\s*;\s*$//; + $commented = s/\s*\)\s*;\s*\*\/$//; # terminating with */ + $line = $line . " << " . $_ ; + } else + { + $format = $1; + # If we stopped on a \" we need to keep adding to format + while ( $format =~ m/\\$/ ) + { s/^([^\"]*)\"// || die "problem"; $format .= "\"" . $1; } + s/\s*\)\s*;\s*$/,/; # replace trailing junk with , for what follows + $commented = s/\s*\)\s*;\s*\*\/$/,/; # terminating with */ + $arguments = $_; + + ## 2 - Look for %x + @stringbits = split( "(%[0-9]*[a-z])", $format ); + foreach ( @stringbits ) + { + #print $_ . "\n"; + if ( /(%[0-9]*[a-z])/ ) # This item is a format + { + ## 3 - Find argument + # kludge for QString(a,b) constructions + $arguments =~ s/(QString\s*\([^,]+,[^,]+\))/QStrKLUDGE/; + $kludge = $1; + $arguments =~ s/\s*([^,]+)\s*,//; + # Remove trailing .ascii() and latin1() + $arg = $1; + $arg =~ s/QStrKLUDGE/$kludge/; ## restore original arg + $arg =~ s/\.ascii\(\)$//; # remove + $arg =~ s/\.latin1\(\)$//; # remove + $arg =~ s/debugString\(([^\)]+)\)/$1/; # remove + # If "a ? b : c" then add parenthesis + if ( $arg =~ m/.+\s*\?\s*.+\s*:\s*.+/ ) { + $arg = "(" . $arg . ")"; + } + $line = $line . " << " . $arg; + } else # This item is some litteral + { + $line = $line . " << \"" . $_ . "\"" if ($_); + } + } + + } + $arguments =~ s/,$//; # Remove trailing slash before next check + if ( $arguments ) { + print STDERR "Non-processed (Information lost! Check the file!) : " . $arguments . "\n"; + } + $line = $line . " << endl;\n"; + if ( $commented ) { $line .= "\*/"; } + print $line; + } + } + else + { + # Normal line + print; + } +} +if ( $inkdebug ) +{ + print STDERR "Warning, unterminated kDebug call !! Check the file !\n"; + print $arguments; +} +' $file.tmp +if cmp -s $file $file.tmp > /dev/null 2>&1 ; then + echo "unchanged" + rm $file.tmp +else + echo "patching" + mv $file.tmp $file +fi + +done + diff --git a/scripts/kde-build b/scripts/kde-build new file mode 100755 index 00000000..5c9a111d --- /dev/null +++ b/scripts/kde-build @@ -0,0 +1,898 @@ +#! /usr/bin/env bash +################################################################################ +# Updates and recompiles a local KDE tree from SVN # +# (c) 2000, 2001, 2002, 2003 by Frerich Raabe <raabe@kde.org> # +# (c) 2002, 2003 by Stephan Kulow <coolo@kde.org> # +################################################################################ +# Do not edit this file, change kde-buildrc instead! # +################################################################################ + +# These strings are defined as variables to make the output look more +# consistent. +# +str_okay="done!" +str_error="failed!" + +# The variables whose name is prefixed with ERR_ hold the error codes which +# are returned by the script and depend on the reason for aborting the +# execution. +# +# No error has been noticed, everything seems to be fine. +# +err_no_error="0" + +# Could not change into a directory of a module - wrong owner/access +# settings? +# +err_change_into_mod_dir="1" + +# Could not find the file 'Makefile.in' for a module, mostly happens if +# 'make -f Makefile.cvs' hasn't been executed for a module. +# +err_no_makefile_in="2" + +# The 'configure' command failed for a module because the system doesn't +# support certain features - I hope you activated logfile generation... ;) +# +err_configure_fail="3" + +# The compilation of a module failed - if the module is defined in +# $critical_modules (see below) the execution is aborted, otherwise the script +# will continue with the next module. +# +err_compile_fail="4" + +# The installation of a module failed - this mostly happens if there's not +# enough free disk space on the partition which $KDEDIRS is mounted to. +# +err_install_fail="5" + +# The $KDESRCDIR variable wasn't set or contains a non-existant directory. +# +err_inv_kdesrcdir="6" + +# The $QTDIR variable wasn't set, points to a non-existant directory or +# doesn't contain a bin/, lib/, or include/ subdirectory. +# +err_inv_qtdir="7" + +# .... + +# The configuration file couldn't be found. +# +err_no_config="11" + +# You can't mix CVS_CLEAN and INCREMENTAL_BUILD +# +err_cvsclean_incremental="12" + +# You can't mix BUILD_CLEAN and INCREMENTAL_BUILD +# +err_buildclean_incremental="13" + +# Certain modules depend on others - those "base" modules which are required +# by others to compile and/or run should be listed here to ensure that the +# script is aborted in case on of these modules doesn't build. +# These modules needs to be build and installed in this specific order! +# +critical_modules="arts kdelibs kdebase" + +# Internal variable, do not change. +# +dateformat="`date +%Y%m%d`" + +# Private variables fro controlling kppp +# +we_started_kppp="FALSE" + +# Connects to the internet using kppp if desired +# +kppp_connect() +{ +if [ "$USE_KPPP" = "TRUE" ]; then + kppp_process=`dcopfind -a kppp-*` + if [ "$kppp_process" = "" ]; then + #kppp not running + kppp > /dev/null 2>&1 & + sleep $KPPP_LOAD_TIME + `dcop $(dcopfind -a kppp-*) KpppIface beginConnect` + #wait for a while + sleep $KPPP_CONNECT_TIME + kppp_connected=`dcop $(dcopfind -a kppp-*) KpppIface isConnected` + if [ "$kppp_connected" = "true" ]; then + we_started_kppp="TRUE" + echo Connected OK + else + echo Could not connect, maybe you need to increase KPPP_CONNECT_TIME + fi + + else + kppp_connected=`dcop $(dcopfind -a kppp-*) KpppIface isConnected` + if [ "$kppp_connected" = "false" ]; then + #Start a connection + `dcop $(dcopfind -a kppp-*) KpppIface beginConnect` + #wait for a while + sleep $KPPP_CONNECT_TIME + kppp_connected=`dcop $(dcopfind -a kppp-*) KpppIface isConnected` + if [ "$kppp_connected" = "true" ]; then + we_started_kppp="TRUE" + echo Connected OK + else + echo Could not connect, maybe you need to increase KPPP_CONNECT_TIME + fi + else + echo Kppp is already connected to the internet + fi + fi +fi +} + +# Disconnects from the internet using kppp if desired +# +kppp_disconnect() +{ +if [ "$USE_KPPP" = "TRUE" ]; then + if [ $(dcopfind -a kppp-*) = "" ]; then + #kppp not running + echo Kppp was not running so cannot be disconnected + else + if [ "$we_started_kppp" = "TRUE" ]; then + echo Disconnecting kppp + `dcop $(dcopfind -a kppp-*) KpppIface disconnect` + else + echo We didnt connect using kppp so we wont disconnect + fi + fi +fi +} + +# This method gives some kind of status message in the title bar of Konsole, +# xterm, etc.. Thanks have to go to Malte Starostik +# <malte@kde.org> for the code :-) +set_title() { + which printf > /dev/null 2>&1 || return + if ([ "$TERM" = "xterm" ] || [ "$TERM" = "xterm-color" ] || [ "$TERM" = "screen" ]) && tty -s; then + printf "\033]0;$1\007" + fi +} + +# moves a log file to be named $1, so one can see on first glance +move_logfile() { + rename_logfile=`echo $logfile | sed -e "s,-build-,-$1-,"` + mv "$logfile" "$rename_logfile" + logfile=$rename_logfile +} + +# Executes the given command, logging the output to $logfile if requested. +# +log_cmd() { + if [ -n "$logfile" ]; then + eval "$1 >> $logfile 2>&1" + else + eval "$1" + fi + return $? +} + +module_variable() { + eval "$1=\$BASE_$1" + varname="$1_"`echo $module|tr a-z A-Z|tr - _|sed "s/\(.*\)-[0-9]*/\1/g"`; # e.g. $1_ARTS etc. + varvalue=`eval echo '$'$varname` + if [ -n "$varvalue" ]; then + eval "$1=\"$varvalue\"" + fi +} + +# Inserts a "-> blah <---" style separator into $logfile, and starts a timer +log_section() { + [ -z "$logfile" ] && return 0 + len=`echo $1 | wc -m | sed -e "s,^ *,,"` + echo "------------------------------------------------------------------------" \ + | sed -e "s,^,-> $1 <," -e "s,.\{$len\}$,," >> $logfile 2>&1 + starttime=`date +%s` +} + +# Computes the time elapsed since the last log_section call, +# inserts a "----" separator, and the time needed, into $logfile +log_endsection() { + [ -z "$logfile" ] && return 0 + compute_time + echo "----------------------------------------------------------------------------" >> $logfile 2>&1 + printf "%s for module %s done. Time needed: %02d:%02d:%02d\n" "$1" $module $hours $minutes $seconds >> $logfile 2>&1 + echo "" >> $logfile 2>&1 +} + +# This function computes the time which was needed for a certain task, using +# expr (instead of shell-specific features) for portability. +# +compute_time() { + duration=`expr \`date +%s\` - $starttime` + hours=`expr $duration / 3600` + minutes=`expr $duration % 3600 / 60` + seconds=`expr $duration % 60` +} + +prepare_update() { + # This checks whether the user wants a certain branch and generates the + # command line. + # + cmd_update="svn" + if test -d $KDESRCDIR/$module; then + test -z "$SUBDIR" && { cmd_update="$cmd_update update" ; return; } + cmd_update="$cmd_update switch -r HEAD" + else + cmd_update="$cmd_update co" + fi + if [ -z "$ACCOUNT" ]; then + cmd_update="$cmd_update $ANONSVNROOT$SUBDIR" + else + cmd_update="$cmd_update" + if [ "$SSHACCOUNT" = "yes" ]; then + cmd_update="$cmd_update svn+ssh://$ACCOUNT@svn.kde.org/home/kde$SUBDIR" + else + cmd_update="$cmd_update https://$ACCOUNT@svn.kde.org/home/kde$SUBDIR" + fi + fi + if [ -n "$CHECKOUT_PARTIAL" -a "$1" = "toponly" ]; then # TODO + cmd_update="$cmd_update -N" + fi + if test ! -d $KDESRCDIR/$module; then + cmd_update="$cmd_update $module" + fi +} + +# This function installs a compiled CVS module. +# +install_module() { + echo -n " Installing..." + set_title "Installing module $module..." + log_section "Installation" + + if log_cmd "$cmd_make_install"; then + log_endsection "Installation" + if [ -n "$KDELOGDIR" ]; then + echo "Build of module $module successfully finished at `date +%c`" >> $logfile + [ -n "$cmd_compress" ] && eval "$cmd_compress $logfile" + fi + echo "$str_okay" + echo "Module $module successfully installed in $KDEDIRS!" + move_logfile "finished" + else + echo "$str_error" + move_logfile "failed" + [ -n "$cmd_compress" ] && eval "$cmd_compress $logfile" + [ $critical -eq 0 ] || exit $err_compile_fail + fi +} + +make_makefile_cvs() { + cmd_make_makefile_cvs="$MAKE -f Makefile.cvs" + if [ "$NICECOMPILE" = yes ]; then + cmd_make_makefile_cvs="nice $cmd_make_makefile_cvs" + fi + unset UNSERMAKE || true + if [ -n "$USE_UNSERMAKE" ] && \ + !(echo $NO_UNSERMAKE_MODULES | grep $module > /dev/null 2>&1); then + export UNSERMAKE=$USE_UNSERMAKE + fi + + if [ "$INCREMENTAL_BUILD" = "yes" -a -e "Makefile.in" ]; then + cmd_make_makefile_cvs="echo Warning: no Makefile.cvs for module $module - as requested" + fi + + if log_cmd "$cmd_make_makefile_cvs"; then + echo "$str_okay" + else + echo "$str_error" + fi +} + +# Disable zsh feature +CDPATH= + +# Get current configuration, bail out if it couldn't be found. +# Search order is $PWD:$HOME:`dirname $0` +# The name in $HOME is .kde-buildrc (note the leading '.') +if [ -e "$PWD/kde-buildrc" ]; then + rc_file="$PWD/kde-buildrc" +else + if [ -e "$HOME/.kde-buildrc" ]; then + rc_file="$HOME/.kde-buildrc" + else + if [ -e "`dirname $0`/kde-buildrc" ]; then + rc_file="`dirname $0`/kde-buildrc" + else + echo "ERROR: Cannot locate configuration file kde-buildrc!"; exit $err_no_config + fi + fi +fi + +INCREMENTAL_BUILD="no" + +. $rc_file + +if [ "${INCREMENTAL_BUILD}" = "yes" -a "${CVS_CLEAN}" = "yes" ]; then + echo "ERROR: Cannot use CVS_CLEAN=\"yes\" and INCREMENTAL_BUILD=\"yes\" together!"; exit $err_cvsclean_incremental +fi + +if [ "${INCREMENTAL_BUILD}" = "yes" -a "${BUILD_CLEAN}" = "yes" ]; then + echo "ERROR: Cannot use BUILD_CLEAN=\"yes\" and INCREMENTAL_BUILD=\"yes\" together!"; exit $err_buildclean_incremental +fi + +domakecvs=1 +dosvnupdate=1 +dousage=0 +specifiedModules="" + +# Parse args +# +while [ $# != 0 ] +do + arg=$1 + case "$arg" in + --help) + dousage=1 + break ;; + --version) + # Show version + echo "$0 version 0.8.15" + exit $err_no_error ;; + --no-update) + dosvnupdate=0 ;; + --no-check) + domakecvs=0 ;; + --incremental) + INCREMENTAL_BUILD="yes" + ;; + --full) + INCREMENTAL_BUILD="no" + ;; + -*) + echo "Unhandled option $arg" + dousage=1 + break ;; + *) + specifiedModules="$specifiedModules $arg" ;; + esac + shift +done + +# Show help info +if [ "$dousage" -eq 1 ]; then + echo "usage: $0 [--options] [modules]" + echo "--no-update Do not update from SVN." + echo "--no-check Do not re-run Makefile.cvs." + echo "--incremental Start make right after update - risky. This also" + echo " disables the BUILD_CLEAN and CVS_CLEAN options." + echo "--full Do full setup even when INCREMENTAL_BUILD is set." + echo "--help Show this message." + exit $err_no_error +fi + +# Expand ~ +QTDIR=`echo "$QTDIR" | sed -e "s,^\~/,$HOME/,"` +KDESRCDIR=`echo "$KDESRCDIR" | sed -e "s,^\~/,$HOME/,"` +KDEBUILDDIR=`echo "$KDEBUILDDIR" |sed -e "s,^\~/,$HOME/,"` +KDEDIRS=`echo "$KDEDIRS" |sed -e "s,^\~/,$HOME/,"` +KDELOGDIR=`echo "$KDELOGDIR" |sed -e "s,^\~/,$HOME/,"` + +# Make sure some paths are according to the rc file. Note that there are AFAIK +# UNIX flavors which don't support LD_LIBRARY_PATH +PATH=$QTDIR/bin:$KDEDIRS/bin:$PATH +MANPATH=$QTDIR/doc/man:$MANPATH +LD_LIBRARY_PATH=$KDEDIRS/lib:$QTDIR/lib:$LD_LIBRARY_PATH + +if [ -n "$USE_UNSERMAKE" ]; then + if [ -n "$MAKE" ]; then + echo "overwriting MAKE=$USE_UNSERMAKE" + fi + MAKE=$USE_UNSERMAKE + UNSERMAKE_PATH=`dirname $USE_UNSERMAKE` + PATH=$UNSERMAKE_PATH:$PATH +fi + +if [ -z "$MAKE" ]; then + MAKE=make +fi + +if [ -n "$specifiedModules" ]; then + # In case someone with a kdebase dir in $PWD does autocompletion.. + modules=$( echo $specifiedModules | sed -e 's/\///g' ) +else + if [ "$ONLYLISTEDMODULES" = yes ]; then + if [ "$USEKDESUPPORT" = yes ]; then + modules="kdesupport $critical_modules $KDEMODULES" + else + modules="$critical_modules $KDEMODULES" + fi + else + modules="$critical_modules" + # This generates in 'modules' a list of the modules which shall be updated. + # + potential_modules=`find $KDESRCDIR -type d -mindepth 1 \ + -maxdepth 1 -follow | sed -e "s@.*/?*@@"` + for module in $potential_modules; do + if [ -d $KDESRCDIR/$module/CVS -a -w $KDESRCDIR/$module ] \ + && !(echo $EXCLUDE | grep -q $module) \ + && !(echo $modules | grep -q $module) ; then + modules="$modules $module" + fi + done + fi +fi + +# Various checks to ensure that the user didn't specify invalid data which +# would make our script break. +# +if [ -n "$KDELOGDIR" -a ! -d "$KDELOGDIR" ]; then + if ! mkdir -p "$KDELOGDIR" > /dev/null 2>&1; then + echo "WARNING: Could not create logfile-directory." + echo "WARNING: Logfile generation deactivated." + KDELOGDIR="" + fi +else + if [ -n "$KDELOGDIR" -a ! -w "$KDELOGDIR" ]; then + echo "WARNING: Could not obtain write access to specified logfile-directory." + echo "WARNING: Logfile generation deactivated." + KDELOGDIR="" + fi +fi + +if [ -n "$KDELOGDIR" ]; then + str_error="$str_error Check the logfile in $KDELOGDIR for further information." +fi + +if [ ! -d "$KDESRCDIR" ]; then + echo "ERROR: Invalid source directory specified!"; exit $err_inv_kdesrcdir +fi +if [ ! -d "$QTDIR" -o ! -d "$QTDIR/lib" -o ! -d "$QTDIR/bin" -o ! -d "$QTDIR/include" ]; then + echo "ERROR: Invalid Qt directory specified!"; exit $err_inv_qtdir +fi + +if [ "$COMPRESSLOGS" = yes ]; then + if which bzip2 > /dev/null 2>&1; then + cmd_compress="`which bzip2` -f " + else + if which gzip > /dev/null 2>&1; then + cmd_compress="`which gzip` -f " + else + echo "WARNING: Neither bzip2 nor gzip was found, disabling compression of logfiles." + cmd_compress="" + fi + fi +fi + +if which sudo > /dev/null 2>&1; then + cmd_sudo="sudo" +else + cmd_sudo="su -c" +fi + +# Clean the installation directory if selected. +# +if test "$INSTALLFROMSCRATCH" = yes && test -z "$specifiedModules" ; then + mkdir -p $KDEDIRS 2> /dev/null + if [ ! -w $KDEDIRS ]; then + echo "Enter the root password to clean the installation directory." + echo "WARNING: All files and directories in $KDEDIRS will be deleted!" + echo -n "Please enter root " + eval "$cmd_sudo rm -rf $KDEDIRS/*" + else + rm -rf $KDEDIRS/* + fi +fi + +# Optionally activate cheap tweaks. +# +if [ "$TWEAKCOMPILE" = yes ]; then + CFLAGS="-O0" + CXXFLAGS="-O0" + export CFLAGS CXXFLAGS +fi + +# Preprocess configuration keys, expand keywords (DISTCC) +# +if echo $MAKE_OPTS_COMPILE | grep DISTCC > /dev/null; then + if [ -n "$DISTCC_HOSTS" ]; then + hosts=0 + for host in $DISTCC_HOSTS; do + hosts=$((${hosts} + 1)) + done + hosts=$((${hosts} * 2)) + else + hosts=1 + fi + MAKE_OPTS_COMPILE=`echo $MAKE_OPTS_COMPILE | sed -e "s,DISTCC,$hosts,"` +fi + +if echo $MAKE_OPTS_COMPILE | grep TEAMBUILDER > /dev/null; then + if ! which tbcompiler > /dev/null 2>&1; then + echo "TEAMBUILDER is not in PATH and OPTS_COMPILE has TEAMBUILDER" + exit 1 + fi + hosts=`tbcompiler -joblimit` + if [ -z "$hosts" ]; then + hosts=1 + fi + MAKE_OPTS_COMPILE=`echo $MAKE_OPTS_COMPILE | sed -e "s,TEAMBUILDER,$hosts,"` +fi + +#Connect to the internet before we start enything +# +kppp_connect + +# Guess what? We'll finally start checking out the modules. :-) +# +# If we want to use unsermake, update that at the very beginning, so that +# all the modules make use of the most recent unsermake version. +# +if [ -n "$USE_UNSERMAKE" ] && [ "$dosvnupdate" -eq 1 ]; then + echo -n "Updating unsermake copy in $UNSERMAKE_PATH..." + cd "$UNSERMAKE_PATH" + svn up > /dev/null 2>&1 + echo $str_okay +fi + +BASE_CONFIGUREFLAGS="$CONFIGUREFLAGS" +BASE_SUBDIR=$SUBDIR +BASE_CHECKOUT_PARTIAL="$CHECKOUT_PARTIAL" + +for module in $modules; do + module_variable SUBDIR + SUBDIR=`echo $SUBDIR | sed -e "s,@MODULE@,$module,"` + module_variable CHECKOUT_PARTIAL + + if [ -n "$KDELOGDIR" ]; then + rm -f $KDELOGDIR/$module-build-* + rm -f $KDELOGDIR/$module-failed-* + rm -f $KDELOGDIR/$module-finished-* + logfile="$KDELOGDIR/$module-build-$dateformat.log" + echo "===============================================================================" > $logfile + echo "Build log of module $module, started on `date +%c`" >> $logfile + echo "===============================================================================" >> $logfile + echo "" >> $logfile + fi + + set_title "Updating module $module..." + if [ "$dosvnupdate" -eq 0 ]; then + echo -n "Checking module $module (no svn update)..." + cmd_update_raw="echo Warning: no svn update of module $module - as requested" + else + if [ -n "$BRANCH" ]; then + echo -n "Updating module $module ($BRANCH)..." + else + echo -n "Updating module $module ..." + fi + prepare_update + cmd_update_raw="$cmd_update" + fi + + log_section "Update $cmd_update" + + if [ "$dosvnupdate" -ne 0 -a -n "$CHECKOUT_PARTIAL" ]; then + cmd_update_raw="$cmd_update -l $module" + fi + + if test -d $KDESRCDIR/$module; then + cd $KDESRCDIR/$module + else + cd $KDESRCDIR + fi + + if ! log_cmd "$cmd_update_raw"; then + echo "$str_error" + continue + fi + + if [ "$dosvnupdate" -ne 0 -a -n "$CHECKOUT_PARTIAL" ]; then + prepare_update toponly + echo "defined subdirs!" + for part_dir in $CHECKOUT_PARTIAL; do + echo -n "Updating subdirectory $part_dir" + log_cmd "$cmd_update $module/$part_dir" + echo " $str_okay" + done + echo -n "Final touch..." + fi + + if [ "$CVS_CLEAN" = "yes" -a -e admin/Makefile.common -a "$INCREMENTAL_BUILD" != "yes" ]; then + cmd_make_cvs_clean="$MAKE -f admin/Makefile.common cvs-clean" + fi + + if ! log_cmd "$cmd_make_cvs_clean"; then + echo "$str_error" + continue + fi + + if [ ! -e Makefile.cvs ]; then + echo "$str_okay" + continue + fi + + if [ $domakecvs = 1 ] ; then + make_makefile_cvs + else + echo "$src_okay" + continue + fi + + log_endsection "Updating" +done + +# Now disconnect from the internet as we've finished updating +# +kppp_disconnect + +for module in $modules; do + module_variable CONFIGUREFLAGS + + # Nothing to do for kde-common + [ "$module" = "kde-common" ] && continue + logfile="$KDELOGDIR/$module-build-$dateformat.log" + + critical=0 + for m in $critical_modules; do if [ $m = $module ]; then critical=1; fi; done + + if ! cd $KDESRCDIR/$module; then + if [ $critical -eq 1 ]; then + echo "ERROR: Could not change into directory $KDESRCDIR/$module!" + exit $err_change_into_mod_dir + else + echo "WARNING: Could not change into directory $KDESRCDIR/$module." + echo "WARNING: Skipping module $module." + continue + fi + fi + + # Check whether 'make -f Makefile.cvs' has been called. + # + if [ ! -e "Makefile.in" ]; then + if [ $critical -eq 1 ]; then + echo "ERROR: Please execute '$MAKE -f Makefile.cvs' first for module $module!" + exit $err_no_makefile_in + else + echo "WARNING: '$MAKE -f Makefile.cvs' seems not to be executed for" + echo "WARNING: module $module, skipping compilation." + continue + fi + fi + + echo "Building module: $module" + + if [ -n "$KDEBUILDDIR" ]; then + + if [ "$BUILD_CLEAN" = "yes" -a "$INCREMENTAL_BUILD" != "yes" ]; then + if [ -d $KDEBUILDDIR/$module ]; then + echo -n " Removing build dir..." + set_title "Removing build dir for module $module..." + rm -rf $KDEBUILDDIR/$module + echo $str_okay + fi + fi + mkdir -p $KDEBUILDDIR/$module + cd $KDEBUILDDIR/$module + fi + + # Configure the module. + # + echo -n " Configuring..." + set_title "Configuring module $module..." + if [ -n "$KDEBUILDDIR" ]; then + cmd_configure="$KDESRCDIR/$module/configure $CONFIGUREFLAGS --with-qt-dir=$QTDIR" + else + cmd_configure="./configure $CONFIGUREFLAGS --with-qt-dir=$QTDIR" + fi + if echo $CONFIGUREFLAGS | grep -v -- "--prefix=" 2>/dev/null >/dev/null; then + cmd_configure="$cmd_configure --prefix=$KDEDIRS" + fi + [ "$NICECOMPILE" = yes ] && cmd_configure="nice $cmd_configure" + configure_skipped=0 + if [ "$INCREMENTAL_BUILD" = "yes" -a -e "Makefile" ]; then + cmd_configure_orig=$cmd_configure + cmd_configure="echo Warning: no configure for module $module - as requested" + configure_skipped=1 + fi + log_section "Configuration" + if [ -n "$KDELOGDIR" -a $configure_skipped -ne 1 ]; then + echo $cmd_configure >> $logfile + fi + + if ! log_cmd "$cmd_configure"; then + echo "$str_error" + move_logfile "failed" + [ -n "$cmd_compress" ] && eval "$cmd_compress $logfile" + [ $critical -eq 0 ] || exit $err_compile_fail + continue + fi + + log_endsection "Configuration" + if [ $configure_skipped -eq 1 ]; then + echo " skipped." + else + echo "$str_okay" + fi + + if [ $configure_skipped -eq 1 ]; then + echo -n " Updating Makefile..." + cmd_make_makefile="$MAKE $MAKE_OPTS Makefile" + [ "$NICECOMPILE" = yes ] && cmd_make_makefile="nice $cmd_make_makefile" + log_section "Updating Makefile" + if [ -n "$KDELOGDIR" ]; then + echo $cmd_make_makefile >> $logfile + fi + if ! log_cmd "$cmd_make_makefile"; then + echo -n " Falling back to normal Makefile.cvs ..." + worked=0 + + if [ -n "$KDEBUILDDIR" ]; then + cd $KDESRCDIR/$module # get back to the supermarket + fi + rm Makefile.in + make_makefile_cvs + if [ -n "$KDEBUILDDIR" ]; then + cd $KDEBUILDDIR/$module # got the sugar, honey? + fi + echo -n " Configuring..." + if log_cmd "$cmd_configure_orig"; then + if log_cmd "$cmd_make_makefile"; then + worked=1 + fi + fi + if [ $worked -ne 1 ]; then + echo "$str_error" + move_logfile "failed" + [ -n "$cmd_compress" ] && eval "$cmd_compress $logfile" + [ $critical -eq 0 ] || exit $err_compile_fail + continue + fi + fi + + log_endsection "Updating Makefile" + echo "$str_okay" + fi + + # Compile the module. + # + echo -n " Compiling..." + set_title "Compiling module $module..." + use_compile_target=no + [ -f $KDESRCDIR/$module/Makefile.am.in ] && [ -n "$MAKE_OPTS_COMPILE" ] && [ -n "$USE_UNSERMAKE" ] \ + && ! (echo $NO_UNSERMAKE_MODULES | grep $module > /dev/null 2>&1) \ + && use_compile_target=yes + if [ "$use_compile_target" = yes ]; then + cmd_make="$MAKE $MAKE_OPTS_COMPILE" + else + cmd_make="$MAKE $MAKE_OPTS" + fi + + [ $critical -eq 0 ] && cmd_make="$cmd_make -k" + [ "$NICECOMPILE" = yes ] && cmd_make="nice $cmd_make" + [ "$use_compile_target" = yes ] && cmd_make="$cmd_make compile" + + log_section "Compilation $cmd_make" + log_cmd "$cmd_make" + retval=$? + + if [ $retval -eq 0 ]; then + log_endsection "Compilation" + echo "$str_okay" + + # Link the module + if [ "$use_compile_target" = yes ]; then + echo -n " Linking..." + set_title "Linking module $module..." + cmd_make="$MAKE $MAKE_OPTS" + [ $critical -eq 0 ] && cmd_make="$cmd_make -k" + [ "$NICECOMPILE" = yes ] && cmd_make="nice $cmd_make" + + log_section "Linking $cmd_make" + log_cmd "$cmd_make" + retval=$? + if [ $retval -eq 0 ]; then + log_endsection "Linking" + echo "$str_okay" + fi + fi + fi + + if [ $retval -eq 0 ]; then + # Install the module. + # + cmd_make_install="$MAKE $MAKE_OPTS" + [ $critical -eq 0 ] && cmd_make_install="$cmd_make_install -k" + [ "$NICECOMPILE" = yes ] && cmd_make_install="nice $cmd_make_install" + cmd_make_install="$cmd_make_install install" + if [ ! -w $KDEDIRS ]; then + eval "$cmd_sudo \"$cmd_make_install\"" + else + install_module + fi + else + echo "$str_error" + # Attempt to display the actual error + grep -m1 -A2 ":[0-9]*: error:" $logfile + move_logfile "failed" + [ -n "$cmd_compress" ] && eval "$cmd_compress $logfile" + [ $critical -eq 0 ] || exit $err_compile_fail + fi +done + +set_title "KDE build finished." + +exit $err_no_error + +=head1 NAME + +kde-build - Updates and recompiles a tree of KDE modules + +=head1 SYNOPSIS + + kde-build + +=head1 DESCRIPTION + +kde-build has been designed to keep a local copy of several KDE +modules up to date and recompile them. Those modules have to be saved in a +common directory, e.g. something like + + ~/kde-src/ + | + +-> kdelibs/ + | + +-> kdebase/ + | + \-> kdenetwork/ + +In this case, the KDE source directory would be ~/kde-src/. The script will +take care of compiling them in the correct order, checks for dependencies +and resolves them as far as possible. + +Please note that, prior to first invocation of the script, the configuration +file 'F<kde-buildrc>' has to be modified to reflect the local environment, +such as paths etc. + +=head1 RETURN VALUE + +The following error codes are returned by the script. + +0 - No error seems to have occured. + +1 - The script could not change into the directory of a module. + +2 - The script could not open the file 'Makefile.in' of a module. + +3 - The configuration of a module failed. + +4 - The compilation of a module failed. + +5 - The installation of a module failed. + +6 - An invalid source directory was specified. + +7 - An invalid Qt directory was specified. + +11 - The configuration file F<kde-buildrc> couldn't be loaded. + +12 - Both CVS_CLEAN and INCREMENTAL_BUILD were set + +13 - Both BUILD_CLEAN and INCREMENTAL_BUILD were set + +=head1 EXAMPLES + + cd ~/scripts/; vi ./kde-buildrc; ./kde-build + +=head1 BUGS + +Probably. + +=head1 TODO + +Add a DIAGNOSIS section to this man page. + +=head1 AUTHOR + +Frerich Raabe <raabe@kde.org> + +=cut + +# vim:et:ts=2:sw=2 diff --git a/scripts/kde-buildrc b/scripts/kde-buildrc new file mode 100644 index 00000000..e3e31d14 --- /dev/null +++ b/scripts/kde-buildrc @@ -0,0 +1,205 @@ +################################################################################ +# Configures the kde-build script. # +# (c) 2000, 2001, 2002, 2003 by Frerich Raabe <raabe@kde.org> # +# (c) 2002, 2003 by Stephan Kulow <coolo@kde.org> # +################################################################################ + +# Where are your KDE sources? +# +KDESRCDIR="$PWD" + +# Where your KDE should be build, leave empty if built in KDESRCDIR +# +KDEBUILDDIR="" + +# Where shall I put the binaries? +# +KDEDIRS="/opt/kde" + +# Where is your Qt 3.3.x? +# +QTDIR="/usr/lib/qt3" + +# Should kppp be used to connect to the internet? +# +USE_KPPP="FALSE" + +#Set this higher if it takes a long time to load kppp on your machine +# +KPPP_LOAD_TIME="5" + +#Set this higher if it takes a long time for you to connect +# +KPPP_CONNECT_TIME="50" + +# If you would like logfiles of the compilation process, specify a directory +# here in which the logfiles will be saved. If you want to disable logfile +# generation, leave this blank. +# +KDELOGDIR="$KDESRCDIR/log" + +# Do you want the logfiles to be compressed? Set this variable to "yes" to +# make the script compress the logfiles using bzip2 (using gzip as a +# fallback is bzip2 cannot be found) and thereby save some diskspace. +# +COMPRESSLOGS="no" + +# Whether or not you want to compile and install the kdesupport module. +# +USEKDESUPPORT="yes" + +# Add modules you want to get compiled to this space-seperated list. Note that +# you don't have to mention the fundamental modules 'arts, 'kdesupport', +# 'kdelibs' and 'kdebase' here since the kde-build script will care about them +# automatically. +# See http://wiki.kdenews.org/tiki-index.php?page=KDE+CVS+Structure for a list +# of available modules including extragear-* or koffice. + +KDEMODULES="kdetoys" + +#KDEMODULES="kdeaccessibility kdeadmin kdeartwork kdebindings kdeedu kdegames kdegraphics kdemultimedia kdenetwork kdepim kdesdk kdetoys kdeutils kdeaddons kdevelop kdewebdev koffice" +#KDEMODULES="$KDEMODULES extragear-libs extragear-multimedia extragear-sysadmin extragear-office extragear-addons extragear-graphics extragear-network extragear-pim extragear-toys extragear-utils" + + +# If you only want to svn update the listed modules, set it to yes. +# +ONLYLISTEDMODULES=yes + +# Do you want a clean install? This is recommended but please note that +# you cannot use your previous KDE desktop while the compilation is +# running. Set this to "no" to install the new snapshot over the previous +# one, otherwise set it to "yes". +# +INSTALLFROMSCRATCH="no" + +# Do you plan to use this box otherwise while compiling? If so, you'd +# probably set this variable to "yes". If this is set to "no", the +# compilation process will try to eat up all the ressources, which speeds up +# the overall progress but makes it a PITA to work on this box. ;) +# +NICECOMPILE="yes" + +# Set this variable to "yes" to activate certain cheap tweaks to speed up the +# compilation process. Those tweaks mainly consist of lowering the +# optimization of the resulting binary code. +# +TWEAKCOMPILE="no" + +# For SVN users only: Do you have a SVN account? If so, set this variable to +# the correct name, otherwise leave this blank to use anonymous SVN. +# +ACCOUNT="" + +# For SVN users only: set this to "yes" in case you access svn.kde.org via +# SSH. Otherwise, set this to "no." +# +SSHACCOUNT="no" + +# In case you left the ACCOUNT value empty (and thus use anonymous SVN +# access), you can specify an anonsvn mirror here. Check +# http://developer.kde.org/source/anonsvn.html for a list of mirror servers. +# +ANONSVNROOT="svn://anonsvn.kde.org/home/kde" + +# Do you want any special path from subversion? If so, specify its path here e.g. +# /branches/KDE/3.3 or /tags/KDE/3.3.0. If you want the checked out branch, +# leave this empty. Use "/trunk" if you want the development branch for sure +# (leaving it empty will simply update whatever is there) +# +# you can specify a module specific branch in through PATH_ARTS +# +SUBDIR="/trunk/KDE/@MODULE@" +SUBDIR_KDESUPPORT=/trunk/kdesupport +for esubdir in libs multimedia sysadmin office addons graphics network pim toys utils; do + var=SUBDIR_EXTRAGEAR_`echo $esubdir | tr 'a-z' 'A-Z'` + eval "$var=/trunk/extragear/$esubdir" +done + +# SUBDIR_ARTS=/branches/arts/1.3 + +# Do you want only some subdirs from some module? Specify similiar to the +# below syntax +#CHECKOUT_PARTIAL_KDEMULTIMEDIA=juk +#CHECKOUT_PARTIAL_KDEEXTRAGEAR_2="kile konversation" + +# If there are any modules in $KDESRCDIR which you don't want to be updated, +# you can specify them in this space-seperated list, e.g. "qt-copy kde-common". +# +EXCLUDE="" + +# --- TODO: not supported anymore with svn --- +# If you would like a virgin svn copy set this field to "yes", otherwise set +# this to "no" (if set to "yes", 'make -f admin/Makefile.common cvs-clean' +# is executed for every module). +# Developers might find this pretty dangerous considering that they could have +# forgotten to 'svn add' a file... ;-) +# Users who want to stay at the bleeding edge will want to activate this in +# order to make sure there aren't any remains of a previous compile. +# +#CVS_CLEAN="no" + +# Rely on the dependencies for Makefiles and configure? +# If you dare to trust the build system, set it to "yes" ;-) +# +INCREMENTAL_BUILD="yes" + +# Flags to be passed to the 'configure' script. +# A note: --enable-debug adds minimum debug symbols while an appended +# =full gives you the full power and fills up your beloved hdd much better +# --disable-closure is actually prefered if it works for you. It will +# not create closure targets but link with some compiler flags to make +# sure the compiler will fail when undefined symbols are there - which +# is much faster if it works for you. +# +# You can define module-specific configure flags using +# CONFIGUREFLAGS_ARTS, CONFIGUREFLAGS_KDELIBS, etc. +# NOTE: These used to be appended to the general $CONFIGUREFLAGS value. +# This is no longer true, you need to use $CONFIGUREFLAGS in the _MODNAME +# version. In case the module name contains dashes ('-'), those needs to +# be replaced with underscores. +# +CONFIGUREFLAGS="--enable-debug --disable-closure" +# example: CONFIGUREFLAGS_KDEPIM="$CONFIGUREFLAGS --enable-debug=full" +# example: CONFIGUREFLAGS_KDEEXTRAGEAR_2="$CONFIGUREFLAGS --without-java" + +# Set it to the path for unsermake if you want to test it instead of +# automake. +# USE_UNSERMAKE="$KDESRCDIR/kdenonbeta/unsermake/unsermake" + +# List modules here for which unsermake should not be used. +# +NO_UNSERMAKE_MODULES="kdenonbeta kdebindings" + +# If you use an extra build directory (KDEBUILDDIR), setting this to yes will +# remove a module's build directory before configure is called. +# +BUILD_CLEAN=no + +# If you would like to pass any parameters to make add them here. If you +# do not want to add any parameters leave this empty. +# example: +# MAKE_OPTS="-j 4 -l 4" +# +MAKE_OPTS="" + +# If you use unsermake, you can define different flags for the actual +# compilation process. This is useful if you distribute the compilation +# process over several computers, but need to link on one. So you would +# define -j3 here and nothing above. +# You can also use the special "DISTCC" keyword here; if found, it will +# be replaced by the number of hosts listed in the $DISTCC_HOSTS +# environment variable, multiplied by two. Hence, 'DISTCC_HOSTS="a b c"' and +# 'MAKE_OPTS_COMPILE="-jDISTCC"' will result in 'MAKE_OPTS_COMPILE="-j6"'. +# If you set something here, the value will be used alone, otherwise +# MAKE_OPTS will be used alone. +# You can use the special "TEAMBUILDER" keyword too, it will put the +# returned value of tbcompiler -joblimit in there. +# +#MAKE_OPTS_COMPILE="" + +# If you would like to compile with a different make, please set it +# here. +# +#MAKE=make + +# vim:et:ts=2:sw=2 diff --git a/scripts/kde-devel-emacs.el b/scripts/kde-devel-emacs.el new file mode 100644 index 00000000..55955f0f --- /dev/null +++ b/scripts/kde-devel-emacs.el @@ -0,0 +1,1890 @@ +;; -*- emacs-lisp -*- + +; To use this file, add this to your .emacs, uncommented : +;(load "cc-engine.elc") +;(load "~/kde2/kdesdk/scripts/kde-devel-emacs.el") +; (setq auto-mode-alist +; (append '(("\\.h$" . c++-mode)) auto-mode-alist)) + + +; Tip: also add (gnuserv-start), to be able to use gnuclient to open new files from a shell + +; Add (setq magic-keys-mode t) to your .xemacs/init.el or ~/.emacs (before loading this file) +; to enable the magic keys in C++ mode (auto-insertion of spaces and newlines). + +; See the end of this file for the list of key bindings and for customizing them + +; This file is maintained by David Faure <faure@kde.org> + + +; Global variables used to differentiate between different emacs +; versions : +; emacs - t if GNU/Emacs is used +; xemacs - t if XEmacs is being used + +(if (string= (substring (emacs-version) 0 6) "XEmacs") + (progn + (setq emacs nil) + (setq xemacs t)) + (progn + (setq emacs t) + (setq xemacs nil))) + + +;; ------- First part, from Arnt's "c++ stuff" + +(defun agulbra-c++-tab (arg) + "Do the right thing about tabs in c++ mode" + (interactive "*P") + (cond + ((and (not (looking-at "[A-Za-z0-9]")) + (save-excursion + (forward-char -1) + (looking-at "[A-Za-z0-9:>_\\-\\&\\.(){}\\*\\+/]"))) + (dabbrev-expand arg)) + (t + (save-excursion + (beginning-of-line) + (c-indent-command))))) + +(defun agulbra-clean-out-spaces () + "Remove spaces at ends of lines" + (interactive) + (and (not buffer-read-only) + (save-excursion + (goto-char (point-min)) + (let ((count 0) + (bmp (buffer-modified-p))) + (while (re-search-forward "[ \t]+$" nil t) + (setq count (1+ count)) + (replace-match "" t t)) + (set-buffer-modified-p bmp) + (and (buffer-modified-p) + (basic-save-buffer)))))) + +; the above used to contain (untabify (point-min) (point-max)) too + +;; it seems that recursion in agulbra-clean-out-spaces trashes Gnu/Emacs stack +;; one of the functions in there has to behave differently than its XEmacs +;; counterpart does, if you're reading this in a middle of may 2002 then +;; please email me (Zack) at zackrat@att.net and bug me to finally fix this +(defun agulbra-c++-clean-out-spaces () + "Remove spaces at ends of lines, only in c++ mode" + (interactive) + (and (eq major-mode 'c++-mode) + (if xemacs + (agulbra-clean-out-spaces) + ))) + +(add-hook 'find-file-hooks 'agulbra-c++-clean-out-spaces) +(add-hook 'write-file-hooks 'agulbra-c++-clean-out-spaces) + +(defun agulbra-delete-into-nomenclature (&optional arg) + "Delete forward until the end of a nomenclature section or word. +With arg, to it arg times." + (interactive "p") + (save-excursion + (let ((b (point-marker))) + (c-forward-into-nomenclature arg) + (delete-region b (point-marker))))) + + +(setq c++-mode-hook + (lambda () + (font-lock-mode) + (c-set-style "stroustrup") + (setq c-tab-always-indent nil + insert-tab-mode nil + indent-tabs-mode nil + fume-auto-rescan-buffer-p nil + c-basic-offset 4 + c-access-key "\\<\\(signals\\|k_dcop\\|\\(public\\|protected\\|private\\)\\([ ]+slots\\)?\\)\\>:" + c-hanging-comment-ender-p nil + c-offsets-alist (append '((case-label . 0) + (access-label . -) + (label . 0) + (statement-cont . c-lineup-math) + ) c-offsets-alist)) + (cond ((string-match "^\\(.*/qt/src\\)/.*/" buffer-file-truename) + (progn + (make-local-variable 'compile-command) + (setq compile-command + (concat "make -k -j 3 -C " + (substring buffer-file-truename + (match-beginning 1) (match-end 1)) + " GNUmakefile.debug && make -k -j 3 -C " + (substring buffer-file-truename + (match-beginning 1) (match-end 1)) + " -f GNUmakefile.debug")))) + ((string-match "^\\\(.*/2x/src\\\)/.*/" buffer-file-truename) + (progn + (make-local-variable 'compile-command) + (setq compile-command + (concat "make -k -C " + (substring buffer-file-truename + (match-beginning 1) + (match-end 1))))))) + (define-key c++-mode-map "\C-m" 'newline-and-indent) + (define-key c++-mode-map "\C-i" 'agulbra-c++-tab) + (define-key c++-mode-map "\ef" 'c-forward-into-nomenclature) + (define-key c++-mode-map "\ed" 'agulbra-delete-into-nomenclature) + (define-key c++-mode-map "\eb" 'c-backward-into-nomenclature) + + ; Add (setq magic-keys-mode t) to your .emacs (before loading this file) + ; to enable the magic keys in C++ mode. + (and (boundp 'magic-keys-mode) + (progn + (define-key c++-mode-map [\(] 'insert-parens) + (define-key c++-mode-map [\)] 'insert-parens2) + (define-key c++-mode-map [,] 'insert-comma) + (define-key c++-mode-map [\{] 'insert-curly-brace) + )) +)) + +(setq c-mode-hook + (lambda () + (font-lock-mode) + (setq c-tab-always-indent nil + c-basic-offset 4 + c-offsets-alist (append '((case-label . 4) + (access-label . -) + (label . 0) + (statement-cont . c-lineup-math) + ) c-offsets-alist)))) + + +(defun agulbra-make-member () + "make a skeleton member function in the .cpp or .cc file" + (interactive) + (let ((class nil) + (function nil) + (file (buffer-file-name)) + (insertion-string nil) + (start nil)) + (save-excursion + (and (re-search-backward "^class[ \t]" nil t) + (progn + (forward-word 1) + (while (looking-at "[ \t]*Q_EXPORT") + (forward-word 2)) + (while (looking-at "[ \t]") + (forward-char 1)) + (setq start (point)) + (while (looking-at "[A-Za-z0-9_]") + (forward-char 1)) + (setq class (buffer-substring start (point)))))) + (progn + (and (looking-at "$") + (progn + (search-backward ")" nil t) + (forward-char) + (backward-sexp))) + (and (stringp class) + (re-search-backward "^[ \t]") + (progn + (while (looking-at "[ \t]") + (forward-char 1)) + (setq start (point)) + (and (search-forward "(" nil t) + (progn + (forward-char -1) + (forward-sexp))) + (and (looking-at "[ \t]+const") + (forward-word 1)) + (and (looking-at ";") + (setq function (buffer-substring start (point)))) + (re-search-forward "(" nil t)))) + (and (stringp function) + (progn ;; get rid of virtual, static, multiple spaces, default values. + (and (string-match "[ \t]*\\<virtual\\>[ \t]*" function) + (setq function (replace-match " " t t function))) + (and (string-match "^\\(virtual\\>\\)?[ \t]*" function) + (setq function (replace-match "" t t function))) + (and (string-match "^\\(static\\>\\)?[ \t]*" function) + (setq function (replace-match "" t t function))) + (while (string-match " +" function) + (setq function (replace-match " " t t function))) + (while (string-match "\t+" function) + (setq function (replace-match " " t t function))) + (while (string-match " ?=[^,)]+" function) + (setq function (replace-match " " t t function))) + (while (string-match " +," function) + (setq function (replace-match "," t t function))))) + (and (stringp function) + (stringp class) + (stringp file) + (progn + (cond ((string-match (concat "^ *" class "[ \\t]*(") function) + (progn + (setq insertion-string + (concat + (replace-match + (concat class "::" class "(") + t t function) + "\n{\n \n}\n")))) + ((string-match (concat "^ *~" class "[ \\t]*(") function) + (progn + (setq insertion-string + (concat + (replace-match + (concat class "::~" class "(") + t t function) + "\n{\n \n}\n")))) + ((string-match " *\\([a-zA-Z0-9_]+\\)[ \\t]*(" function) + (progn + (setq insertion-string + (concat + (replace-match + (concat " " class "::" "\\1(") + t nil function) + "\n{\n \n}\n")))) + (t + (error (concat "Can't parse declaration ``" + function "'' in class ``" class + "'', aborting")))) + (stringp insertion-string)) + (string-match "\\.h$" file) + (setq f (replace-match ".cpp" t t file)) + (if (file-readable-p f ) + (message "") + (progn + (string-match "\\.h$" file) + (setq f (replace-match ".cc" t t file)) + )) + (find-file f) + (progn + (goto-char (point-max)) + (insert insertion-string) + (forward-char -3) + (save-excursion + (and (string-match ".*/" file) + (setq file (replace-match "" t nil file))) + (or (re-search-backward + (concat "^#include *\"" file "\"$") nil t) + (progn + (goto-char (point-min)) + (re-search-forward "^$" nil t) + (insert "\n#include \"" file "\"\n"))))))) + (fume-rescan-buffer) +) + + +(setq compilation-error-regexp-systems-list '(gnu of comma 4bsd) + compilation-ask-about-save nil) + + +(defun c-guess-basic-syntax () + (save-excursion + (save-restriction + (beginning-of-line) + (let* ((indent-point (point)) + (case-fold-search nil) + (fullstate (c-parse-state)) + (state fullstate) + literal containing-sexp char-before-ip char-after-ip lim + syntax placeholder c-in-literal-cache inswitch-p + tmpsymbol keyword injava-inher special-brace-list + ;; narrow out any enclosing class or extern "C" block + (inclass-p (c-narrow-out-enclosing-class state indent-point)) + inenclosing-p) + ;; check for meta top-level enclosing constructs, possible + ;; extern language definitions, possibly (in C++) namespace + ;; definitions. + (save-excursion + (save-restriction + (widen) + (if (and inclass-p + (progn + (goto-char (aref inclass-p 0)) + (looking-at (concat c-extra-toplevel-key "[^_]")))) + (let ((enclosing (match-string 1))) + (cond + ((string-equal enclosing "extern") + (setq inenclosing-p 'extern)) + ((string-equal enclosing "namespace") + (setq inenclosing-p 'namespace)) + ))))) + ;; get the buffer position of the most nested opening brace, + ;; if there is one, and it hasn't been narrowed out + (save-excursion + (goto-char indent-point) + (skip-chars-forward " \t}") + (skip-chars-backward " \t") + (while (and state + (not containing-sexp)) + (setq containing-sexp (car state) + state (cdr state)) + (if (consp containing-sexp) + ;; if cdr == point, then containing sexp is the brace + ;; that opens the sexp we close + (if (= (cdr containing-sexp) (point)) + (setq containing-sexp (car containing-sexp)) + ;; otherwise, ignore this element + (setq containing-sexp nil)) + ;; ignore the bufpos if its been narrowed out by the + ;; containing class or does not contain the indent point + (if (or (<= containing-sexp (point-min)) + (>= containing-sexp indent-point)) + (setq containing-sexp nil))))) + + ;; set the limit on the farthest back we need to search + (setq lim (or containing-sexp + (if (consp (car fullstate)) + (cdr (car fullstate)) + nil) + (point-min))) + + ;; cache char before and after indent point, and move point to + ;; the most likely position to perform the majority of tests + (goto-char indent-point) + (skip-chars-forward " \t") + (setq char-after-ip (char-after)) + (c-backward-syntactic-ws lim) + (setq char-before-ip (char-before)) + (goto-char indent-point) + (skip-chars-forward " \t") + + ;; are we in a literal? + (setq literal (c-in-literal lim)) + + ;; now figure out syntactic qualities of the current line + (cond + ;; CASE 1: in a string. + ((memq literal '(string)) + (c-add-syntax 'string (c-point 'bopl))) + ;; CASE 2: in a C or C++ style comment. + ((memq literal '(c c++)) + (c-add-syntax literal (car (c-literal-limits lim)))) + ;; CASE 3: in a cpp preprocessor macro continuation. + ((and (eq literal 'pound) + (/= (save-excursion + (c-beginning-of-macro lim) + (setq placeholder (point))) + (c-point 'boi))) + (c-add-syntax 'cpp-macro-cont placeholder)) + ;; CASE 4: In-expression statement. + ((and (or c-inexpr-class-key c-inexpr-block-key c-lambda-key) + (setq placeholder (c-looking-at-inexpr-block))) + (setq tmpsymbol (assq (car placeholder) + '((inexpr-class . class-open) + (inexpr-statement . block-open)))) + (if tmpsymbol + ;; It's a statement block or an anonymous class. + (setq tmpsymbol (cdr tmpsymbol)) + ;; It's a Pike lambda. Check whether we are between the + ;; lambda keyword and the argument list or at the defun + ;; opener. + (setq tmpsymbol (if (eq char-after-ip ?{) + 'inline-open + 'lambda-intro-cont))) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-syntax tmpsymbol (point)) + (unless (eq (point) (cdr placeholder)) + (c-add-syntax (car placeholder)))) + ;; CASE 5: Line is at top level. + ((null containing-sexp) + (cond + ;; CASE 5A: we are looking at a defun, brace list, class, + ;; or inline-inclass method opening brace + ((setq special-brace-list + (or (and c-special-brace-lists + (c-looking-at-special-brace-list)) + (eq char-after-ip ?{))) + (cond + ;; CASE 5A.1: extern language or namespace construct + ((save-excursion + (goto-char indent-point) + (skip-chars-forward " \t") + (and (c-safe (progn (c-backward-sexp 2) t)) + (looking-at (concat c-extra-toplevel-key "[^_]")) + (setq keyword (match-string 1) + placeholder (point)) + (or (and (string-equal keyword "namespace") + (setq tmpsymbol 'namespace-open)) + (and (string-equal keyword "extern") + (progn + (c-forward-sexp 1) + (c-forward-syntactic-ws) + (eq (char-after) ?\")) + (setq tmpsymbol 'extern-lang-open))) + )) + (goto-char placeholder) + (c-add-syntax tmpsymbol (c-point 'boi))) + ;; CASE 5A.2: we are looking at a class opening brace + ((save-excursion + (goto-char indent-point) + (skip-chars-forward " \t{") + ;; TBD: watch out! there could be a bogus + ;; c-state-cache in place when we get here. we have + ;; to go through much chicanery to ignore the cache. + ;; But of course, there may not be! BLECH! BOGUS! + (let ((decl + (let ((c-state-cache nil)) + (c-search-uplist-for-classkey (c-parse-state)) + ))) + (and decl + (setq placeholder (aref decl 0))) + )) + (c-add-syntax 'class-open placeholder)) + ;; CASE 5A.3: brace list open + ((save-excursion + (c-beginning-of-statement-1 lim) + ;; c-b-o-s could have left us at point-min + (and (bobp) + (c-forward-syntactic-ws indent-point)) + (if (looking-at "typedef[^_]") + (progn (c-forward-sexp 1) + (c-forward-syntactic-ws indent-point))) + (setq placeholder (c-point 'boi)) + (or (consp special-brace-list) + (and (or (save-excursion + (goto-char indent-point) + (setq tmpsymbol nil) + (while (and (> (point) placeholder) + (= (c-backward-token-1 1 t) 0) + (/= (char-after) ?=)) + (if (and (not tmpsymbol) + (looking-at "new\\>[^_]")) + (setq tmpsymbol 'topmost-intro-cont))) + (eq (char-after) ?=)) + (looking-at "enum[ \t\n]+")) + (save-excursion + (while (and (< (point) indent-point) + (= (c-forward-token-1 1 t) 0) + (not (memq (char-after) '(?\; ?\())))) + (not (memq (char-after) '(?\; ?\())) + )))) + (if (and (c-major-mode-is 'java-mode) + (eq tmpsymbol 'topmost-intro-cont)) + ;; We're in Java and have found that the open brace + ;; belongs to a "new Foo[]" initialization list, + ;; which means the brace list is part of an + ;; expression and not a top level definition. We + ;; therefore treat it as any topmost continuation + ;; even though the semantically correct symbol still + ;; is brace-list-open, on the same grounds as in + ;; case 10B.2. + (progn + (c-beginning-of-statement-1 lim) + (c-forward-syntactic-ws) + (c-add-syntax 'topmost-intro-cont (c-point 'boi))) + (c-add-syntax 'brace-list-open placeholder))) + ;; CASE 5A.4: inline defun open + ((and inclass-p (not inenclosing-p)) + (c-add-syntax 'inline-open) + (c-add-class-syntax 'inclass inclass-p)) + ;; CASE 5A.5: ordinary defun open + (t + (goto-char placeholder) + (if inclass-p + (c-add-syntax 'defun-open (c-point 'boi)) + (c-add-syntax 'defun-open (c-point 'bol))) + ))) + ;; CASE 5B: first K&R arg decl or member init + ((c-just-after-func-arglist-p) + (cond + ;; CASE 5B.1: a member init + ((or (eq char-before-ip ?:) + (eq char-after-ip ?:)) + ;; this line should be indented relative to the beginning + ;; of indentation for the topmost-intro line that contains + ;; the prototype's open paren + ;; TBD: is the following redundant? + (if (eq char-before-ip ?:) + (forward-char -1)) + (c-backward-syntactic-ws lim) + ;; TBD: is the preceding redundant? + (if (eq (char-before) ?:) + (progn (forward-char -1) + (c-backward-syntactic-ws lim))) + (if (eq (char-before) ?\)) + (c-backward-sexp 1)) + (setq placeholder (point)) + (save-excursion + (and (c-safe (c-backward-sexp 1) t) + (looking-at "throw[^_]") + (c-safe (c-backward-sexp 1) t) + (setq placeholder (point)))) + (goto-char placeholder) + (c-add-syntax 'member-init-intro (c-point 'boi)) + ;; we don't need to add any class offset since this + ;; should be relative to the ctor's indentation + ) + ;; CASE 5B.2: K&R arg decl intro + (c-recognize-knr-p + (c-add-syntax 'knr-argdecl-intro (c-point 'boi)) + (if inclass-p (c-add-class-syntax 'inclass inclass-p))) + ;; CASE 5B.3: Inside a member init list. + ((c-beginning-of-member-init-list lim) + (c-forward-syntactic-ws) + (c-add-syntax 'member-init-cont (point))) + ;; CASE 5B.4: Nether region after a C++ or Java func + ;; decl, which could include a `throws' declaration. + (t + (c-beginning-of-statement-1 lim) + (c-add-syntax 'func-decl-cont (c-point 'boi)) + ))) + ;; CASE 5C: inheritance line. could be first inheritance + ;; line, or continuation of a multiple inheritance + ((or (and c-baseclass-key + (progn + (when (eq char-after-ip ?,) + (skip-chars-forward " \t") + (forward-char)) + (looking-at c-baseclass-key))) + (and (or (eq char-before-ip ?:) + ;; watch out for scope operator + (save-excursion + (and (eq char-after-ip ?:) + (c-safe (progn (forward-char 1) t)) + (not (eq (char-after) ?:)) + ))) + (save-excursion + (c-backward-syntactic-ws lim) + (if (eq char-before-ip ?:) + (progn + (forward-char -1) + (c-backward-syntactic-ws lim))) + (back-to-indentation) + (looking-at c-class-key))) + ;; for Java + (and (c-major-mode-is 'java-mode) + (let ((fence (save-excursion + (c-beginning-of-statement-1 lim) + (point))) + cont done) + (save-excursion + (while (not done) + (cond ((looking-at c-Java-special-key) + (setq injava-inher (cons cont (point)) + done t)) + ((or (not (c-safe (c-forward-sexp -1) t)) + (<= (point) fence)) + (setq done t)) + ) + (setq cont t))) + injava-inher) + (not (c-crosses-statement-barrier-p (cdr injava-inher) + (point))) + )) + (cond + ;; CASE 5C.1: non-hanging colon on an inher intro + ((eq char-after-ip ?:) + (c-backward-syntactic-ws lim) + (c-add-syntax 'inher-intro (c-point 'boi)) + ;; don't add inclass symbol since relative point already + ;; contains any class offset + ) + ;; CASE 5C.2: hanging colon on an inher intro + ((eq char-before-ip ?:) + (c-add-syntax 'inher-intro (c-point 'boi)) + (if inclass-p (c-add-class-syntax 'inclass inclass-p))) + ;; CASE agulbrahack.1: + ((and inclass-p + c-access-key + (looking-at c-access-key)) + (c-add-syntax 'access-label (c-point 'bonl)) + ) + ;; CASE 5C.3: in a Java implements/extends + (injava-inher + (let ((where (cdr injava-inher)) + (cont (car injava-inher))) + (goto-char where) + (cond ((looking-at "throws[ \t\n]") + (c-add-syntax 'func-decl-cont + (progn (c-beginning-of-statement-1 lim) + (c-point 'boi)))) + (cont (c-add-syntax 'inher-cont where)) + (t (c-add-syntax 'inher-intro + (progn (goto-char (cdr injava-inher)) + (c-beginning-of-statement-1 lim) + (point)))) + ))) + ;; CASE 5C.4: a continued inheritance line + (t + (c-beginning-of-inheritance-list lim) + (c-add-syntax 'inher-cont (point)) + ;; don't add inclass symbol since relative point already + ;; contains any class offset + ))) + ;; CASE 5D: this could be a top-level compound statement, a + ;; member init list continuation, or a template argument + ;; list continuation. + ((c-with-syntax-table (if (c-major-mode-is 'c++-mode) + c++-template-syntax-table + (syntax-table)) + (save-excursion + (while (and (= (c-backward-token-1 1 t lim) 0) + (not (looking-at "[;{<,]")))) + (eq (char-after) ?,))) + (goto-char indent-point) + (c-beginning-of-member-init-list lim) + (cond + ;; CASE 5D.1: hanging member init colon, but watch out + ;; for bogus matches on access specifiers inside classes. + ((and (save-excursion + (setq placeholder (point)) + (c-backward-token-1 1 t lim) + (and (eq (char-after) ?:) + (not (eq (char-before) ?:)))) + (save-excursion + (goto-char placeholder) + (back-to-indentation) + (or + (/= (car (save-excursion + (parse-partial-sexp (point) placeholder))) + 0) + (and + (if c-access-key (not (looking-at c-access-key)) t) + (not (looking-at c-class-key)) + (if c-bitfield-key (not (looking-at c-bitfield-key)) t)) + ))) + (goto-char placeholder) + (c-forward-syntactic-ws) + (c-add-syntax 'member-init-cont (point)) + ;; we do not need to add class offset since relative + ;; point is the member init above us + ) + ;; CASE 5D.2: non-hanging member init colon + ((progn + (c-forward-syntactic-ws indent-point) + (eq (char-after) ?:)) + (skip-chars-forward " \t:") + (c-add-syntax 'member-init-cont (point))) + ;; CASE 5D.3: perhaps a multiple inheritance line? + ((save-excursion + (c-beginning-of-statement-1 lim) + (setq placeholder (point)) + (looking-at c-inher-key)) + (goto-char placeholder) + (c-add-syntax 'inher-cont (c-point 'boi))) + ;; CASE 5D.4: perhaps a template list continuation? + ((save-excursion + (goto-char indent-point) + (skip-chars-backward "^<" lim) + ;; not sure if this is the right test, but it should + ;; be fast and mostly accurate. + (setq placeholder (point)) + (and (eq (char-before) ?<) + (not (c-in-literal lim)))) + ;; we can probably indent it just like an arglist-cont + (goto-char placeholder) + (c-beginning-of-statement-1 lim) + (c-add-syntax 'template-args-cont (c-point 'boi))) + ;; CASE 5D.5: perhaps a top-level statement-cont + (t + (c-beginning-of-statement-1 lim) + ;; skip over any access-specifiers + (and inclass-p c-access-key + (while (looking-at c-access-key) + (forward-line 1))) + ;; skip over comments, whitespace + (c-forward-syntactic-ws indent-point) + (c-add-syntax 'statement-cont (c-point 'boi))) + )) + ;; CASE 5E: we are looking at a access specifier + ((and inclass-p + c-access-key + (looking-at c-access-key)) + (c-add-syntax 'access-label (c-point 'bonl)) + (c-add-class-syntax 'inclass inclass-p)) + ;; CASE 5F: extern-lang-close or namespace-close? + ((and inenclosing-p + (eq char-after-ip ?})) + (setq tmpsymbol (if (eq inenclosing-p 'extern) + 'extern-lang-close + 'namespace-close)) + (c-add-syntax tmpsymbol (aref inclass-p 0))) + ;; CASE 5G: we are looking at the brace which closes the + ;; enclosing nested class decl + ((and inclass-p + (eq char-after-ip ?}) + (save-excursion + (save-restriction + (widen) + (forward-char 1) + (and (c-safe (progn (c-backward-sexp 1) t)) + (= (point) (aref inclass-p 1)) + )))) + (c-add-class-syntax 'class-close inclass-p)) + ;; CASE 5H: we could be looking at subsequent knr-argdecls + ((and c-recognize-knr-p + ;; here we essentially use the hack that is used in + ;; Emacs' c-mode.el to limit how far back we should + ;; look. The assumption is made that argdecls are + ;; indented at least one space and that function + ;; headers are not indented. + (let ((limit (save-excursion + (re-search-backward "^[^ \^L\t\n#]" nil 'move) + (point)))) + (save-excursion + (c-backward-syntactic-ws limit) + (setq placeholder (point)) + (while (and (memq (char-before) '(?\; ?,)) + (> (point) limit)) + (beginning-of-line) + (setq placeholder (point)) + (c-backward-syntactic-ws limit)) + (and (eq (char-before) ?\)) + (or (not c-method-key) + (progn + (c-forward-sexp -1) + (forward-char -1) + (c-backward-syntactic-ws) + (not (or (memq (char-before) '(?- ?+)) + ;; or a class category + (progn + (c-forward-sexp -2) + (looking-at c-class-key)) + ))))) + )) + (save-excursion + (c-beginning-of-statement-1) + (not (looking-at "typedef[ \t\n]+")))) + (goto-char placeholder) + (c-add-syntax 'knr-argdecl (c-point 'boi))) + ;; CASE 5I: ObjC method definition. + ((and c-method-key + (looking-at c-method-key)) + (c-add-syntax 'objc-method-intro (c-point 'boi))) + ;; CASE 5J: we are at the topmost level, make sure we skip + ;; back past any access specifiers + ((progn + (c-backward-syntactic-ws lim) + (while (and inclass-p + c-access-key + (not (bobp)) + (save-excursion + (c-safe (progn (c-backward-sexp 1) t)) + ;; agulbrahack 2 + (and (looking-at "slots:") + (c-backward-sexp 1)) + (looking-at c-access-key))) + (c-backward-sexp 1) + (c-backward-syntactic-ws lim)) + (or (bobp) + (memq (char-before) '(?\; ?\})))) + ;; real beginning-of-line could be narrowed out due to + ;; enclosure in a class block + (save-restriction + (widen) + (c-add-syntax 'topmost-intro (c-point 'bol)) + (if inclass-p + (progn + (goto-char (aref inclass-p 1)) + (or (= (point) (c-point 'boi)) + (goto-char (aref inclass-p 0))) + (cond + ((eq inenclosing-p 'extern) + (c-add-syntax 'inextern-lang (c-point 'boi))) + ((eq inenclosing-p 'namespace) + (c-add-syntax 'innamespace (c-point 'boi))) + (t (c-add-class-syntax 'inclass inclass-p))) + )) + )) + ;; CASE 5K: we are at an ObjC or Java method definition + ;; continuation line. + ((and c-method-key + (progn + (c-beginning-of-statement-1 lim) + (beginning-of-line) + (looking-at c-method-key))) + (c-add-syntax 'objc-method-args-cont (point))) + ;; CASE 5L: we are at the first argument of a template + ;; arglist that begins on the previous line. + ((eq (char-before) ?<) + (c-beginning-of-statement-1 lim) + (c-forward-syntactic-ws) + (c-add-syntax 'template-args-cont (c-point 'boi))) + ;; CASE 5M: we are at a topmost continuation line + (t + (c-beginning-of-statement-1 lim) + (c-forward-syntactic-ws) + (c-add-syntax 'topmost-intro-cont (c-point 'boi))) + )) ; end CASE 5 + ;; (CASE 6 has been removed.) + ;; CASE 7: line is an expression, not a statement. Most + ;; likely we are either in a function prototype or a function + ;; call argument list + ((not (or (and c-special-brace-lists + (save-excursion + (goto-char containing-sexp) + (c-looking-at-special-brace-list))) + (eq (char-after containing-sexp) ?{))) + (c-backward-syntactic-ws containing-sexp) + (cond + ;; CASE 7A: we are looking at the arglist closing paren + ((and (or (c-major-mode-is 'pike-mode) + ;; Don't check this in Pike since it allows a + ;; comma after the last arg. + (not (eq char-before-ip ?,))) + (memq char-after-ip '(?\) ?\]))) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (when (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (forward-char) + (skip-chars-forward " \t") + (setq placeholder (point))) + (c-add-syntax 'arglist-close placeholder)) + ;; CASE 7B: Looking at the opening brace of an + ;; in-expression block or brace list. + ((eq char-after-ip ?{) + (goto-char indent-point) + (setq placeholder (c-point 'boi)) + (goto-char containing-sexp) + (if (c-inside-bracelist-p placeholder + (cons containing-sexp state)) + (progn + (c-add-syntax 'brace-list-open (c-point 'boi)) + (c-add-syntax 'inexpr-class)) + (c-add-syntax 'block-open (c-point 'boi)) + (c-add-syntax 'inexpr-statement))) + ;; CASE 7C: we are looking at the first argument in an empty + ;; argument list. Use arglist-close if we're actually + ;; looking at a close paren or bracket. + ((memq char-before-ip '(?\( ?\[)) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (when (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (forward-char) + (skip-chars-forward " \t") + (setq placeholder (point))) + (c-add-syntax 'arglist-intro placeholder)) + ;; CASE 7D: we are inside a conditional test clause. treat + ;; these things as statements + ((save-excursion + (goto-char containing-sexp) + (and (c-safe (progn (c-forward-sexp -1) t)) + (looking-at "\\<for\\>[^_]"))) + (goto-char (1+ containing-sexp)) + (c-forward-syntactic-ws indent-point) + (c-beginning-of-statement-1 containing-sexp) + (if (eq char-before-ip ?\;) + (c-add-syntax 'statement (point)) + (c-add-syntax 'statement-cont (point)) + )) + ;; CASE 7E: maybe a continued method call. This is the case + ;; when we are inside a [] bracketed exp, and what precede + ;; the opening bracket is not an identifier. + ((and c-method-key + (eq (char-after containing-sexp) ?\[) + (save-excursion + (goto-char (1- containing-sexp)) + (c-backward-syntactic-ws (c-point 'bod)) + (if (not (looking-at c-symbol-key)) + (c-add-syntax 'objc-method-call-cont containing-sexp)) + ))) + ;; CASE 7F: we are looking at an arglist continuation line, + ;; but the preceding argument is on the same line as the + ;; opening paren. This case includes multi-line + ;; mathematical paren groupings, but we could be on a + ;; for-list continuation line + ((save-excursion + (goto-char (1+ containing-sexp)) + (skip-chars-forward " \t") + (not (eolp))) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (when (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (forward-char) + (skip-chars-forward " \t") + (setq placeholder (point))) + (c-add-syntax 'arglist-cont-nonempty placeholder)) + ;; CASE 7G: we are looking at just a normal arglist + ;; continuation line + (t (c-beginning-of-statement-1 containing-sexp) + (forward-char 1) + (c-forward-syntactic-ws indent-point) + (c-add-syntax 'arglist-cont (c-point 'boi))) + )) + ;; CASE 8: func-local multi-inheritance line + ((and c-baseclass-key + (save-excursion + (goto-char indent-point) + (skip-chars-forward " \t") + (looking-at c-baseclass-key))) + (goto-char indent-point) + (skip-chars-forward " \t") + (cond + ;; CASE 8A: non-hanging colon on an inher intro + ((eq char-after-ip ?:) + (c-backward-syntactic-ws lim) + (c-add-syntax 'inher-intro (c-point 'boi))) + ;; CASE 8B: hanging colon on an inher intro + ((eq char-before-ip ?:) + (c-add-syntax 'inher-intro (c-point 'boi))) + ;; CASE 8C: a continued inheritance line + (t + (c-beginning-of-inheritance-list lim) + (c-add-syntax 'inher-cont (point)) + ))) + ;; CASE 9: we are inside a brace-list + ((setq special-brace-list + (or (and c-special-brace-lists + (save-excursion + (goto-char containing-sexp) + (c-looking-at-special-brace-list))) + (c-inside-bracelist-p containing-sexp state))) + (cond + ;; CASE 9A: In the middle of a special brace list opener. + ((and (consp special-brace-list) + (save-excursion + (goto-char containing-sexp) + (eq (char-after) ?\()) + (eq char-after-ip (car (cdr special-brace-list)))) + (goto-char (car (car special-brace-list))) + (skip-chars-backward " \t") + (if (and (bolp) + (assoc 'statement-cont + (setq placeholder (c-guess-basic-syntax)))) + (setq syntax placeholder) + (c-beginning-of-statement-1 lim) + (c-forward-token-1 0) + (if (looking-at "typedef\\>") (c-forward-token-1 1)) + (c-add-syntax 'brace-list-open (c-point 'boi)))) + ;; CASE 9B: brace-list-close brace + ((if (consp special-brace-list) + ;; Check special brace list closer. + (progn + (goto-char (car (car special-brace-list))) + (save-excursion + (goto-char indent-point) + (back-to-indentation) + (or + ;; We were between the special close char and the `)'. + (and (eq (char-after) ?\)) + (eq (1+ (point)) (cdr (car special-brace-list)))) + ;; We were before the special close char. + (and (eq (char-after) (cdr (cdr special-brace-list))) + (= (c-forward-token-1) 0) + (eq (1+ (point)) (cdr (car special-brace-list))))))) + ;; Normal brace list check. + (and (eq char-after-ip ?}) + (c-safe (progn (forward-char 1) + (c-backward-sexp 1) + t)) + (= (point) containing-sexp))) + (c-add-syntax 'brace-list-close (c-point 'boi))) + (t + ;; Prepare for the rest of the cases below by going to the + ;; token following the opening brace + (if (consp special-brace-list) + (progn + (goto-char (car (car special-brace-list))) + (c-forward-token-1 1 nil indent-point)) + (goto-char containing-sexp)) + (forward-char) + (let ((start (point))) + (c-forward-syntactic-ws indent-point) + (goto-char (max start (c-point 'bol)))) + (skip-chars-forward " \t\n\r" indent-point) + (cond + ;; CASE 9C: we're looking at the first line in a brace-list + ((= (point) indent-point) + (goto-char containing-sexp) + (c-add-syntax 'brace-list-intro (c-point 'boi)) + ) ; end CASE 9C + ;; CASE 9D: this is just a later brace-list-entry or + ;; brace-entry-open + (t (if (or (eq char-after-ip ?{) + (and c-special-brace-lists + (save-excursion + (goto-char indent-point) + (c-forward-syntactic-ws (c-point 'eol)) + (c-looking-at-special-brace-list (point))))) + (c-add-syntax 'brace-entry-open (point)) + (c-add-syntax 'brace-list-entry (point)) + )) ; end CASE 9D + )))) ; end CASE 9 + ;; CASE 10: A continued statement + ((and (not (memq char-before-ip '(?\; ?:))) + (or (not (eq char-before-ip ?})) + (c-looking-at-inexpr-block-backward containing-sexp)) + (> (point) + (save-excursion + (c-beginning-of-statement-1 containing-sexp) + (c-forward-syntactic-ws) + (setq placeholder (point)))) + (/= placeholder containing-sexp)) + (goto-char indent-point) + (skip-chars-forward " \t") + (let ((after-cond-placeholder + (save-excursion + (goto-char placeholder) + (if (and c-conditional-key (looking-at c-conditional-key)) + (progn + (c-safe (c-skip-conditional)) + (c-forward-syntactic-ws) + (if (eq (char-after) ?\;) + (progn + (forward-char 1) + (c-forward-syntactic-ws))) + (point)) + nil)))) + (cond + ;; CASE 10A: substatement + ((and after-cond-placeholder + (>= after-cond-placeholder indent-point)) + (goto-char placeholder) + (if (eq char-after-ip ?{) + (c-add-syntax 'substatement-open (c-point 'boi)) + (c-add-syntax 'substatement (c-point 'boi)))) + ;; CASE 10B: open braces for class or brace-lists + ((setq special-brace-list + (or (and c-special-brace-lists + (c-looking-at-special-brace-list)) + (eq char-after-ip ?{))) + (cond + ;; CASE 10B.1: class-open + ((save-excursion + (goto-char indent-point) + (skip-chars-forward " \t{") + (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) + (and decl + (setq placeholder (aref decl 0))) + )) + (c-add-syntax 'class-open placeholder)) + ;; CASE 10B.2: brace-list-open + ((or (consp special-brace-list) + (save-excursion + (goto-char placeholder) + (looking-at "\\<enum\\>")) + (save-excursion + (goto-char indent-point) + (while (and (> (point) placeholder) + (= (c-backward-token-1 1 t) 0) + (/= (char-after) ?=))) + (eq (char-after) ?=))) + ;; The most semantically accurate symbol here is + ;; brace-list-open, but we report it simply as a + ;; statement-cont. The reason is that one normally + ;; adjusts brace-list-open for brace lists as + ;; top-level constructs, and brace lists inside + ;; statements is a completely different context. + (goto-char indent-point) + (c-beginning-of-closest-statement) + (c-add-syntax 'statement-cont (c-point 'boi))) + ;; CASE 10B.3: The body of a function declared inside a + ;; normal block. This can only occur in Pike. + ((and (c-major-mode-is 'pike-mode) + (progn + (goto-char indent-point) + (not (c-looking-at-bos)))) + (c-beginning-of-closest-statement) + (c-add-syntax 'defun-open (c-point 'boi))) + ;; CASE 10B.4: catch-all for unknown construct. + (t + ;; Can and should I add an extensibility hook here? + ;; Something like c-recognize-hook so support for + ;; unknown constructs could be added. It's probably a + ;; losing proposition, so I dunno. + (goto-char placeholder) + (c-add-syntax 'statement-cont (c-point 'boi)) + (c-add-syntax 'block-open)) + )) + ;; CASE 10C: iostream insertion or extraction operator + ((looking-at "<<\\|>>") + (goto-char placeholder) + (and after-cond-placeholder + (goto-char after-cond-placeholder)) + (while (and (re-search-forward "<<\\|>>" indent-point 'move) + (c-in-literal placeholder))) + ;; if we ended up at indent-point, then the first + ;; streamop is on a separate line. Indent the line like + ;; a statement-cont instead + (if (/= (point) indent-point) + (c-add-syntax 'stream-op (c-point 'boi)) + (c-backward-syntactic-ws lim) + (c-add-syntax 'statement-cont (c-point 'boi)))) + ;; CASE 10D: continued statement. find the accurate + ;; beginning of statement or substatement + (t + (c-beginning-of-statement-1 after-cond-placeholder) + ;; KLUDGE ALERT! c-beginning-of-statement-1 can leave + ;; us before the lim we're passing in. It should be + ;; fixed, but I'm worried about side-effects at this + ;; late date. Fix for v5. + (goto-char (or (and after-cond-placeholder + (max after-cond-placeholder (point))) + (point))) + (c-add-syntax 'statement-cont (point))) + ))) + ;; CASE 11: an else clause? + ((looking-at "\\<else\\>[^_]") + (c-backward-to-start-of-if containing-sexp) + (c-add-syntax 'else-clause (c-point 'boi))) + ;; CASE 12: Statement. But what kind? Lets see if its a + ;; while closure of a do/while construct + ((progn + (goto-char indent-point) + (skip-chars-forward " \t") + (and (looking-at "while\\b[^_]") + (save-excursion + (c-backward-to-start-of-do containing-sexp) + (setq placeholder (point)) + (looking-at "do\\b[^_]")) + )) + (goto-char placeholder) + (c-add-syntax 'do-while-closure (c-point 'boi))) + ;; CASE 13: A catch or finally clause? This case is simpler + ;; than if-else and do-while, because a block is required + ;; after every try, catch and finally. + ((save-excursion + (and (cond ((c-major-mode-is 'c++-mode) + (looking-at "\\<catch\\>[^_]")) + ((c-major-mode-is 'java-mode) + (looking-at "\\<\\(catch\\|finally\\)\\>[^_]"))) + (c-safe (c-backward-sexp) t) + (eq (char-after) ?{) + (c-safe (c-backward-sexp) t) + (if (eq (char-after) ?\() + (c-safe (c-backward-sexp) t) + t) + (looking-at "\\<\\(try\\|catch\\)\\>[^_]") + (setq placeholder (c-point 'boi)))) + (c-add-syntax 'catch-clause placeholder)) + ;; CASE 14: A case or default label + ((looking-at c-switch-label-key) + (goto-char containing-sexp) + ;; check for hanging braces + (if (/= (point) (c-point 'boi)) + (c-forward-sexp -1)) + (c-add-syntax 'case-label (c-point 'boi))) + ;; CASE 15: any other label + ((looking-at c-label-key) + (goto-char containing-sexp) + ;; check for hanging braces + (if (/= (point) (c-point 'boi)) + (c-forward-sexp -1)) + (c-add-syntax 'label (c-point 'boi))) + ;; CASE 16: block close brace, possibly closing the defun or + ;; the class + ((eq char-after-ip ?}) + (let* ((lim (c-safe-position containing-sexp fullstate)) + (relpos (save-excursion + (goto-char containing-sexp) + (if (/= (point) (c-point 'boi)) + (c-beginning-of-statement-1 lim)) + (c-point 'boi)))) + (cond + ;; CASE 16A: closing a lambda defun or an in-expression + ;; block? + ((save-excursion + (goto-char containing-sexp) + (setq placeholder (c-looking-at-inexpr-block))) + (setq tmpsymbol (if (eq (car placeholder) 'inlambda) + 'inline-close + 'block-close)) + (goto-char containing-sexp) + (back-to-indentation) + (if (= containing-sexp (point)) + (c-add-syntax tmpsymbol (point)) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-syntax tmpsymbol (point)) + (if (/= (point) (cdr placeholder)) + (c-add-syntax (car placeholder))))) + ;; CASE 16B: does this close an inline or a function in + ;; an extern block or namespace? + ((progn + (goto-char containing-sexp) + (setq placeholder (c-search-uplist-for-classkey state))) + (goto-char (aref placeholder 0)) + (if (looking-at (concat c-extra-toplevel-key "[^_]")) + (c-add-syntax 'defun-close relpos) + (c-add-syntax 'inline-close relpos))) + ;; CASE 16C: if there an enclosing brace that hasn't + ;; been narrowed out by a class, then this is a + ;; block-close + ((and (not inenclosing-p) + (c-most-enclosing-brace state) + (or (not (c-major-mode-is 'pike-mode)) + ;; In Pike it can be a defun-close of a + ;; function declared in a statement block. Let + ;; it through to be handled below. + (or (c-looking-at-bos) + (progn + (c-beginning-of-statement-1) + (looking-at c-conditional-key))))) + (c-add-syntax 'block-close relpos)) + ;; CASE 16D: find out whether we're closing a top-level + ;; class or a defun + (t + (save-restriction + (narrow-to-region (point-min) indent-point) + (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) + (if decl + (c-add-class-syntax 'class-close decl) + (c-add-syntax 'defun-close relpos))))) + ))) + ;; CASE 17: statement catchall + (t + ;; we know its a statement, but we need to find out if it is + ;; the first statement in a block + (goto-char containing-sexp) + (forward-char 1) + (c-forward-syntactic-ws indent-point) + ;; now skip forward past any case/default clauses we might find. + (while (or (c-skip-case-statement-forward fullstate indent-point) + (and (looking-at c-switch-label-key) + (not inswitch-p))) + (setq inswitch-p t)) + ;; we want to ignore non-case labels when skipping forward + (while (and (looking-at c-label-key) + (goto-char (match-end 0))) + (c-forward-syntactic-ws indent-point)) + (cond + ;; CASE 17A: we are inside a case/default clause inside a + ;; switch statement. find out if we are at the statement + ;; just after the case/default label. + ((and inswitch-p + (progn + (goto-char indent-point) + (c-beginning-of-statement-1 containing-sexp) + (setq placeholder (point)) + (beginning-of-line) + (when (re-search-forward c-switch-label-key + (max placeholder (c-point 'eol)) t) + (setq placeholder (match-beginning 0))))) + (goto-char indent-point) + (skip-chars-forward " \t") + (if (eq (char-after) ?{) + (c-add-syntax 'statement-case-open placeholder) + (c-add-syntax 'statement-case-intro placeholder))) + ;; CASE 17B: continued statement + ((eq char-before-ip ?,) + (goto-char indent-point) + (c-beginning-of-closest-statement) + (c-add-syntax 'statement-cont (c-point 'boi))) + ;; CASE 17C: a question/colon construct? But make sure + ;; what came before was not a label, and what comes after + ;; is not a globally scoped function call! + ((or (and (memq char-before-ip '(?: ??)) + (save-excursion + (goto-char indent-point) + (c-backward-syntactic-ws lim) + (back-to-indentation) + (not (looking-at c-label-key)))) + (and (memq char-after-ip '(?: ??)) + (save-excursion + (goto-char indent-point) + (skip-chars-forward " \t") + ;; watch out for scope operator + (not (looking-at "::"))))) + (goto-char indent-point) + (c-beginning-of-closest-statement) + (c-add-syntax 'statement-cont (c-point 'boi))) + ;; CASE 17D: any old statement + ((< (point) indent-point) + (let ((safepos (c-most-enclosing-brace fullstate)) + relpos done) + (goto-char indent-point) + (c-beginning-of-statement-1 safepos) + ;; It is possible we're on the brace that opens a nested + ;; function. + (if (and (eq (char-after) ?{) + (save-excursion + (c-backward-syntactic-ws safepos) + (not (eq (char-before) ?\;)))) + (c-beginning-of-statement-1 safepos)) + (if (and inswitch-p + (looking-at c-switch-label-key)) + (progn + (goto-char (match-end 0)) + (c-forward-syntactic-ws))) + (setq relpos (c-point 'boi)) + (while (and (not done) + (<= safepos (point)) + (/= relpos (point))) + (c-beginning-of-statement-1 safepos) + (if (= relpos (c-point 'boi)) + (setq done t)) + (setq relpos (c-point 'boi))) + (c-add-syntax 'statement relpos) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open)))) + ;; CASE 17E: first statement in an in-expression block + ((setq placeholder + (save-excursion + (goto-char containing-sexp) + (c-looking-at-inexpr-block))) + (goto-char containing-sexp) + (back-to-indentation) + (let ((block-intro (if (eq (car placeholder) 'inlambda) + 'defun-block-intro + 'statement-block-intro))) + (if (= containing-sexp (point)) + (c-add-syntax block-intro (point)) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-syntax block-intro (point)) + (if (/= (point) (cdr placeholder)) + (c-add-syntax (car placeholder))))) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + ;; CASE 17F: first statement in an inline, or first + ;; statement in a top-level defun. we can tell this is it + ;; if there are no enclosing braces that haven't been + ;; narrowed out by a class (i.e. don't use bod here!) + ((save-excursion + (save-restriction + (widen) + (goto-char containing-sexp) + (c-narrow-out-enclosing-class state containing-sexp) + (not (c-most-enclosing-brace state)))) + (goto-char containing-sexp) + ;; if not at boi, then defun-opening braces are hung on + ;; right side, so we need a different relpos + (if (/= (point) (c-point 'boi)) + (progn + (c-backward-syntactic-ws) + (c-safe (c-forward-sexp (if (eq (char-before) ?\)) + -1 -2))) + ;; looking at a Java throws clause following a + ;; method's parameter list + (c-beginning-of-statement-1) + )) + (c-add-syntax 'defun-block-intro (c-point 'boi))) + ;; CASE 17G: First statement in a function declared inside + ;; a normal block. This can only occur in Pike. + ((and (c-major-mode-is 'pike-mode) + (progn + (goto-char containing-sexp) + (and (not (c-looking-at-bos)) + (progn + (c-beginning-of-statement-1) + (not (looking-at c-conditional-key)))))) + (c-add-syntax 'defun-block-intro (c-point 'boi))) + ;; CASE 17H: first statement in a block + (t (goto-char containing-sexp) + (if (/= (point) (c-point 'boi)) + (c-beginning-of-statement-1 + (if (= (point) lim) + (c-safe-position (point) state) lim))) + (c-add-syntax 'statement-block-intro (c-point 'boi)) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + )) + ) + ;; now we need to look at any modifiers + (goto-char indent-point) + (skip-chars-forward " \t") + (cond + ;; are we looking at a comment only line? + ((and (looking-at c-comment-start-regexp) + (/= (c-forward-token-1 0 nil (c-point 'eol)) 0)) + (c-add-syntax 'comment-intro)) + ;; we might want to give additional offset to friends (in C++). + ((and (c-major-mode-is 'c++-mode) + (looking-at c-C++-friend-key)) + (c-add-syntax 'friend)) + ;; Start of a preprocessor directive? + ((and (eq literal 'pound) + (= (save-excursion + (c-beginning-of-macro lim) + (setq placeholder (point))) + (c-point 'boi)) + (not (and (c-major-mode-is 'pike-mode) + (eq (char-after (1+ placeholder)) ?\")))) + (c-add-syntax 'cpp-macro))) + ;; return the syntax + syntax)))) + + +(defun agulbra-switch-cpp-h () + "Switch to the corresponding .cpp, .C, .cc or .h file." + (interactive) + (let ((n (buffer-file-name)) + (c nil)) + (cond ((and (string-match "\\.h$" n) + (progn + (setq c (replace-match ".cpp" t t n)) + (file-readable-p c))) + (find-file c)) + ((and (string-match "\\.h$" n) + (progn + (setq c (replace-match ".cc" t t n)) + (file-readable-p c))) + (find-file c)) + ((and (string-match "\\.h$" n) + (progn + (setq c (replace-match ".C" t t n)) + (file-readable-p c))) + (find-file c)) + ((string-match "\\.h$" n) + (find-file (replace-match ".cpp" t t n))) + ((string-match "\\.h$" n) + (find-file (replace-match ".cpp" t t n))) + ;((string-match "_[a-z]+[0-9]*.cpp$" n) + ; (find-file (replace-match ".h" t t n))) + ((string-match "\\.cpp$" n) + (find-file (replace-match ".h" t t n))) + ((string-match "\\.cc$" n) + (find-file (replace-match ".h" t t n))) + ((string-match "\\.c$" n) + (find-file (replace-match ".h" t t n))) + (t + (error "%s is neither .h, .cc, .C or .cpp" n))))) + +;; ----- Second part, contrinuted by Klaralvdalens Datakonsult +(defvar kdab-qt-documentation + "http://doc.trolltech.com/3.0/XXX.html" + "URL for Qt documentation. XXX must be in the string. + Example: file:/packages/kde-src/qt-copy/doc/html/XXX.html") + + +;; special case for include files +;; Please notify blackie@klaralvdalens-datakonsult.se with any modification to this variable! +(defvar kdab-special-includes + '( + (qlayout.h QHBoxLayout QVBoxLayout QGridLayout QBoxLayout) + (qlistview.h QListViewItem QCheckListItem QListViewItemIterator) + (qiconview.h QIconViewItem QIconDragItem QIconDrag) + (qdragobject.h QTextDrag QStoredDrag QUriDag QColorDrag QImageDrag QDragManager) + (qmime.h QMimeSource QMimeSourceFactory QWindowsMime) + (qptrlist.h QPtrListIterator) + (qevent.h QTimerEvent QMouseEvent QWheelEvent QTabletEvent QKeyEvent + QFocusEvent QPaintEvent QMoveEvent QResizeEvent QCloseEvent + QShowEvent QHideEvent QContextMenuEvent QIMEvent QDropEvent + QDragMoveEvent QDragEnterEvent QDragResponseEvent QDragLeaveEvent + QChildEvent QCustomEvent) + (qdatetime.h QTime QDateTime QDate) + + ; Qt/Embedded + (qcopchannel_qws.h QCopChannel) + (qdirectpainter_qws.h QDirectPainter) + (qfontfactorybdf_qws.h QFontFactoryBDF) + (qfontfactoryttf_qws.h QFontFactoryFT) + (qfontmanager_qws.h QGlyphMetrics QGlyph QRenderedFont QDiskFont QFontManager QFontFactory) + (qgfx_qws.h QScreenCursor QPoolEntry QScreen QGfx) + (qgfxlinuxfb_qws.h QLinuxFbScreen) + (qgfxmatroxdefs_qws.h QQnxFbGfx QQnxScreen) + (qgfxraster_qws.h QGfxRasterBase QGfxRaster) + (qgfxvnc_qws.h QRfbRect QRfbPixelFormat QRfbServerInit QRfbSetEncodings + QRfbFrameBufferUpdateRequest QRfbKeyEvent QRfbPointerEvent QRfbClientCutText QVNCServer) + (qkeyboard_qws.h QWSKeyboardHandler) + (qlock_qws.h QLock QLockHolder) + (qmemorymanager_qws.h QMemoryManagerPixmap QMemoryManager) + (qsoundqss_qws.h QWSSoundServer QWSSoundClient QWSSoundServerClient QWSSoundServerSocket) + (qwindowsystem_qws.h QWSInternalWindowInfo QWSScreenSaver QWSWindow QWSSoundServer + QWSServer QWSServer KeyboardFilter QWSClient) + (qwsbeosdecoration_qws.h QWSBeOSDecoration) + (qwscursor_qws.h QWSCursor) + (qwsdecoration_qws.h QWSDecoration) + (qwsdefaultdecoration_qws.h QWSDefaultDecoration) + (qwsdisplay_qws.h QWSWindowInfo QWSDisplay) + (qwshydrodecoration_qws.h QWSHydroDecoration) + (qwskde2decoration_qws.h QWSKDE2Decoration) + (qwskdedecoration_qws.h QWSKDEDecoration) + (qwsmanager_qws.h QWSManager QWSButton) + (qwsmouse_qws.h QWSPointerCalibrationData QWSMouseHandler QCalibratedMouseHandler + QAutoMouseHandlerPrivate QWSMouseHandlerPrivate QVrTPanelHandlerPrivate + QTPanelHandlerPrivate QYopyTPanelHandlerPrivate QCustomTPanelHandlerPrivate + QVFbMouseHandlerPrivate) + (qwsproperty_qws.h QWSPropertyManager) + (qwsregionmanager_qws.h QWSRegionManager) + (qwssocket_qws.h QWSSocket QWSServerSocket) + (qwswindowsdecoration_qws.h QWSWindowsDecoration) + + ; KDE + (kdebug.h kdDebug kdWarning kdError kdFatal kdBacktrace) + + ) "List of special include files which do not follow the normal scheme") + +;; Lookup class `cls' in kdab-special-includes and return the associate include file name +(defun kdab-map-special (cls) + (let ((list kdab-special-includes) + (found nil)) + (while (and list (not found)) + (let* ( (elm (car list)) + (include-file (car elm)) + (classes (cdr elm))) + ( while (and classes (not found)) + (if (string= (downcase cls) (downcase (symbol-name (car classes)))) + (setq found include-file) + (setq classes (cdr classes))))) + (setq list (cdr list))) + (if found + (symbol-name found) + nil) ; return value + )) + + +(defun kdab-word-under-point () + (save-excursion + (let* ((start (if (= (preceding-char) ?\ ) + (point) + (progn (backward-word 1) (point)))) + (end (progn (forward-word 1) (point)))) + (buffer-substring start end)))) + + +;-------------------------------------------------------------------------------- +; Insert include file. +; Place point anywhere on a class, and invoke this function. A result of +; this is that an include line is added (if it does not already exists) for +; the given class. +;-------------------------------------------------------------------------------- +(defun kdab-insert-header () + (interactive "") + (save-excursion + (let* ((word (downcase (kdab-word-under-point))) + (header (cond + ((kdab-map-special word) (kdab-map-special word)) + ((string-match "^qdom" word) "qdom.h") + ((string-match "^qxml" word) "qxml.h") + (t (concat word ".h"))))) + (beginning-of-buffer) + (if (not (re-search-forward (concat "#include *<" header ">") nil t)) + (progn + ; No include existsed + (goto-char (point-max)) ; Using end-of-buffer makes point move, dispete save-excursion + (if (not (re-search-backward "^#include *[\"<][^\">]+\.h *[\">]" nil t)) + (beginning-of-buffer) + (progn (end-of-line) (forward-char 1))) + (if (file-exists-p header) + (progn + ; See this as a local file. + (insert "#include \"" header "\"\n") + (message (concat "inserted " "#include \"" header "\""))) + (progn + (insert "#include <" header ">\n") + (message (concat "inserted " "#include <" header ">"))))) + (message (concat "header file \"" header "\" is already included")))))) + + + + +;-------------------------------------------------------------------------------- +; Start konqueror with documentation for the class under point. +; set `kdab-qt-documentation' to specify the replacement for the documentation +;-------------------------------------------------------------------------------- +(defun kdab-lookup-qt-documentation () + (interactive "") + (save-excursion + (let* ((word (downcase (kdab-word-under-point))) + (url (if (not (string-match "XXX" kdab-qt-documentation)) + (error "didn't find three X's in kdab-qt-documentation") + (replace-match word t t kdab-qt-documentation)))) + (start-process "qt documentation" nil "kfmclient" "openURL" url) + (message (concat "Loading " url))))) + + +;; ----- Third part, contributed by various KDE developers + +;;; func-menu is a package that scans your source file for function definitions +;;; and makes a menubar entry that lets you jump to any particular function +;;; definition by selecting it from the menu. The following code turns this on +;;; for all of the recognized languages. Scanning the buffer takes some time, +;;; but not much. + +(if xemacs + (progn + (require 'func-menu) + (add-hook 'find-file-hooks 'fume-add-menubar-entry) ) + (progn + (require 'imenu))) + ;(add-hook 'find-file-hooks 'imenu)) ) + +;; Switch between the declaration of a class member in .cc/.cpp/.C, and its definition in the .h file +;; Written by David and Reggie after much hair tearing +(defun switch-to-function-def () + (interactive) + (let ((n (buffer-file-name)) + (class "") + (fn "")) + (if (or (string-match "\\.cc$" n) + (string-match "\\.cpp$" n) + (string-match "\\.C$" n)) + (let ((a (fume-function-before-point))) + (and (string-match "^\\(.*\\)::\\(.*\\)$" a) + (progn + (setq class (match-string 1 a)) + (setq fn (match-string 2 a)) + (agulbra-switch-cpp-h) + (goto-char 0) + (re-search-forward class nil t) + (re-search-forward (concat "[ \t]+" fn "[ \t]*(") nil t))))) + (if (string-match "\\.h$" n) + (progn + (save-excursion + (forward-line 0) + (re-search-forward "[ \t]+\\([^ \t(]+\\)[ \t]*(" nil t) + (setq fn (match-string 1)) + (re-search-backward "^class \\([a-zA-Z0-9_]+\\)[ \t]*\\([a-zA-Z0-9_]*\\)" nil t) + (setq class (match-string 1)) + (setq save (match-string 2)) + (and (string-match "Q_EXPORT" class) + (setq class save)) + (message (concat class "::" fn)) + ) + (agulbra-switch-cpp-h) + (goto-char 0) + (re-search-forward (concat "^[^()]*" class "::" fn "[ \t]*(") nil t) + (message c-syntactic-context) + ) +))) + +; Adds the current file to Makefile.am. +; Written by David. +(defun add-file-to-makefile-am () + "add the current file to the _SOURCES tag in the Makefile.am" + (interactive) + (let ((file (buffer-name)) + (makefile "Makefile.am")) + (if (file-readable-p makefile ) + (message "") + (error "Makefile.am not found!") + ) + (find-file makefile) + (goto-char (point-min)) + (if (re-search-forward "_SOURCES" nil t) + (progn + (end-of-line) + ; check if line ends with '\' [had to read make-mode.el to find this one!] + (while (= (char-before) ?\\) + (end-of-line 2)) ; moves to end of next line + (insert " ") + (insert file) + ) + (error "_SOURCES not found") + ) + ) + ) + +; Inserts a kdDebug statement showing the name of the current method. +; You need to create the empty line first. +(defun insert-kdDebug () + (interactive) + (insert "kdDebug() << \"") + (insert (fume-function-before-point)) + (insert "\" << endl;") + ) + +; Creates the ifndef/define/endif statements necessary for a header file +(defun header-protection () + (interactive) + (let ((f (buffer-file-name))) + (if (string-match "^.*/" f) + (setq f (replace-match "" t t f))) + (while (string-match "\\." f) + (setq f (replace-match "_" t t f))) + (save-excursion + (goto-char (point-min)) + (insert "#ifndef " (upcase f) "\n#define " (upcase f) "\n\n") + (goto-char (point-max)) + (insert "\n#endif\n") + ) + ) + ) + + +; Makes '(' insert '(' or ' ( ' where appropiate +(defun insert-parens (arg) (interactive "*P") + (if (not (c-in-literal)) + (let ((n nil)) + (save-excursion + (setq n (or (progn (forward-char -2) (looking-at "if")) + (progn (forward-char -1) (looking-at "for")) + (progn (forward-char -1) (looking-at "case")) + (progn (forward-char -1) (looking-at "while")) + ) + ) + ) + (cond + (n (progn + (insert " ") + (self-insert-command (prefix-numeric-value arg)) + ;(insert " ") + )) + (t ;else + (self-insert-command (prefix-numeric-value arg)) + ;(insert " ") + ))) + (self-insert-command (prefix-numeric-value arg))) + ) + +(defun insert-parens2 (arg) (interactive "*P") + (if (not (c-in-literal)) + (let ((remv nil) (nospac nil)) + (forward-char -2) + (setq remv (looking-at "( ")) ; () -> we'll have to remove that space + (forward-char 1) + (setq nospac (or (looking-at " ") (looking-at "(")) ) ; no space to be added + (forward-char 1) + (cond + (remv (progn + (delete-backward-char 1) + (self-insert-command (prefix-numeric-value arg)))) ; the () case + (nospac (self-insert-command (prefix-numeric-value arg))) ; no space to be added + (t ;else + (if abbrev-mode ; XEmacs + (expand-abbrev)) + ;(insert " ") + (self-insert-command (prefix-numeric-value arg)) + ))) ; normal case, prepend a space + ;;(blink-matching-open) ; show the matching parens + (self-insert-command (prefix-numeric-value arg))) + ) + +; Makes ',' insert ', ' +(defun insert-comma (arg) + (interactive "*P") + (let* ((ch (char-after)) + (spacep (not (or (eq ch ? ) + (c-in-literal) + arg)))) + (self-insert-command (prefix-numeric-value arg)) + (if spacep + (insert " ")))) + +(defun insert-curly-brace (arg) (interactive "*P") + (if (not (c-in-literal)) + (let ((n nil) (o nil)) + (save-excursion + (forward-char -2) + (setq o (looking-at "()")) + (forward-char 1) + (setq n (looking-at ")")) + ) + (cond + (n (progn + (insert " ") + (self-insert-command (prefix-numeric-value arg)) + (newline-and-indent) + (save-excursion + (insert "\n}") + (c-indent-line) + ))) + (o (progn + (newline) + (self-insert-command (prefix-numeric-value arg)) + (newline-and-indent))) + (t (progn ;else + (self-insert-command (prefix-numeric-value arg)) + (save-excursion + (beginning-of-line) + (c-indent-command)))) + )) + (self-insert-command (prefix-numeric-value arg)) + ) +) + +;; have PelDel mode work +(put 'insert-parens 'pending-delete t) +(put 'insert-parens2 'pending-delete t) +(put 'insert-comma 'pending-delete t) +(put 'insert-curly-brace 'pending-delete t) +(put 'newline-and-indent 'pending-delete t) + +; A wheel mouse that doesn't beep, unlike mwheel-install +(defun scroll-me-up () (interactive) (scroll-up 4)) +(defun scroll-me-down () (interactive) (scroll-down 4)) +(defun scroll-me-up-a-bit () (interactive) (scroll-up 1)) +(defun scroll-me-down-a-bit () (interactive) (scroll-down 1)) +(define-key global-map [(button4)] 'scroll-me-down) +(define-key global-map [(button5)] 'scroll-me-up) +(define-key global-map [(shift button4)] 'scroll-me-down-a-bit) +(define-key global-map [(shift button5)] 'scroll-me-up-a-bit) + +; Compilation +(defun makeclean () (interactive) (compile "make clean")) +(defun make () (interactive) (compile "make")) +(defun makeinstall () (interactive) (compile "make install")) +(defun makeinstallexec () (interactive) (compile "make install-exec")) +(defun makethisfile () (interactive) + (let ((f (buffer-name))) + (if (string-match "\.cpp$" f) (setq f (replace-match "\.lo" t t f))) + (if (string-match "\.cc$" f) (setq f (replace-match "\.lo" t t f))) + (compile (concat "make " f )))) + +;; Indentation: 4 characters, no tabs. +(setq c-basic-offset 4) +(setq insert-tab-mode nil) +(setq-default require-final-newline t) +(setq-default next-line-add-newlines nil) + +;; pc-like textmarking +(load "pc-select") +(if xemacs + (pc-select-mode) + (pc-selection-mode)) + +; Move in other window +(defun scroll-other-up () (interactive) (scroll-other-window-down 1)) ; hehe :) +(define-key global-map [(meta up)] 'scroll-other-up) +(defun scroll-other-down () (interactive) (scroll-other-window 1)) +(define-key global-map [(meta down)] 'scroll-other-down) + +;; Some example bindings, feel free to customize :) +(define-key global-map [(f2)] 'grep) +;; FIXME: remember to get these two working on Gnu/Emacs (Zack) +(define-key global-map [(f3)] 'fume-list-functions) +(define-key global-map [(shift f3)] 'fume-prompt-function-goto) +(define-key global-map [(shift button3)] 'mouse-function-menu) +(define-key global-map [(shift f4)] 'makeclean) +(define-key global-map [(f4)] 'make) +(define-key global-map [(f5)] 'makeinstall) +(define-key global-map [(shift f5)] 'makeinstallexec) +(define-key global-map [(shift f6)] 'makethisfile) +(define-key global-map [(f6)] 'agulbra-switch-cpp-h) +(define-key global-map [(f7)] 'switch-to-function-def) +;; imenu does that interactively +(if xemacs + (define-key global-map [(f8)] 'function-menu)) +;(define-key global-map [(f9)] 'agulbra-make-member) ;; uncomment this for a killer feature +(define-key global-map [(f10)] 'kdab-insert-header) +(define-key global-map [(shift f10)] 'kdab-lookup-qt-documentation) +(define-key global-map [(control meta d)] 'insert-kdDebug) + +; Standard Qt/KDE shortcuts: Ctrl+Backspace, Ctrl+Delete +(define-key global-map [(control backspace)] 'backward-kill-word) +(define-key global-map [(control delete)] 'kill-word) + +; Standard Qt/KDE shortcuts: Control Pageup and Pagedown +(define-key global-map [(control prior)] 'beginning-of-buffer) +(define-key global-map [(control next)] 'end-of-buffer) + +; currently no binding for header-protection and add-file-to-makefile-am, +; you need to call them from M-x + +; ----------------------------------------------------------------- +; The above list defines the following bindings: +; +; F2 : offer a grep command +; +; F3/Shift-F3/F8/Shift-RMB : different ways to see the list of methods in the current buffer +; +; F4 : make +; Shift-F4 : make clean +; F5 : make install +; Shift-F5 : make install-exec +; +; Shift-F6 : compile this file [assumes libtool is being used] +; F6 : Switch from .cpp/.cc to .h and vice-versa +; F7 : The same, but try to find the current method in the other file +; F9 (if enabled) : Create a member method in the .cpp, the cursor being on the definition in the .h +; F10: Place point on a class name, and the respective (Qt) include file will be inserted. +; This works with all Qt classes but can easily be extended to KDE classes. +; Shift-F10: Place point on a class name, and press Shift-F10, and konqueror will load +; Qt documentation. Customize the location of the Qt documentation with the +; variable kdab-qt-documentation. XXX will be replace with the class name. +; Example (setq kdab-qt-location "file:/packages/kde-src/qt-copy/doc/html/XXX.html") +; +; Ctrl+Meta+D : insert a kdDebug statement with the name of the current method +; [the new hide-all-windows shortcut conflicts with that, you may have to +; change it, or use Ctrl+Meta+Shift+D (!!)] +; +; Meta Up/Down : scroll the other window (when window is split) + +; Other very useful keybindings to know about: +; C-x r m to set a named bookmark in the buffer +; C-x r b to jump to a named bookmark in the buffer + +(setq-default initial-scratch-message + "File kde-devel-emacs.el is deprecated! +Please use KDE-Emacs from kdesdk/scripts/kde-emacs.") diff --git a/scripts/kde-devel-gdb b/scripts/kde-devel-gdb new file mode 100644 index 00000000..bf69d233 --- /dev/null +++ b/scripts/kde-devel-gdb @@ -0,0 +1,299 @@ +# This file defines handy gdb macros for printing out Qt types +# To use it, add this line to your ~/.gdbinit : +# source /path/to/kde/sources/kdesdk/scripts/kde-devel-gdb + +# Please don't use tabs in this file. When pasting a +# macro definition to gdb, tabs are interpreted as completion. + +# Disable printing of static members. Qt has too many, it clutters the output +set print static-members off + +define printqstring + printqstringdata $arg0.d +end +document printqstring + Prints the contents of a QString +end +define printq4string + printq4stringdata $arg0.d +end +document printq4string + Prints the contents of a Qt QString +end + +define printqstringdata + set $i=0 + set $d = (QStringData *)$arg0 + while $i < $d->len + printf "%c", (char)($d->unicode[$i++].ucs & 0xff) + end + printf "\n" +end +document printqstringdata + Prints the contents of a QStringData + This is useful when the output of another command (e.g. printqmap) + shows {d = 0xdeadbeef} for a QString, i.e. the qstringdata address + instead of the QString object itself. + printqstring $s and printqstringdata $s.d are equivalent. +end + +define printq4stringdata + set $i=0 + set $d = $arg0 + while $i < $d->size + printf "%c", (char)($d->data[$i++] & 0xff) + end + printf "\n" +end +document printq4stringdata + Prints the contents of a Qt4 QString::Data + This is useful when the output of another command (e.g. printqmap) + shows {d = 0xdeadbeef} for a QString, i.e. the qstringdata address + instead of the QString object itself. + printq4string $s and printq4stringdata $s.d are equivalent. +end + +define printqstring_utf8 + set $i=0 + set $s = $arg0 + while $i < $s.d->len + set $uc = (unsigned short) $s.d->unicode[$i++].ucs + if ( $uc < 0x80 ) + printf "%c", (unsigned char)($uc & 0x7f) + else + if ( $uc < 0x0800 ) + printf "%c", (unsigned char)(0xc0 | ($uc >> 6)) + else + printf "%c", (unsigned char)(0xe0 | ($uc >> 12) + printf "%c", (unsigned char)(0x80 | (($uc > 6) &0x3f) + end + printf "%c", (unsigned char)(0x80 | ((uchar) $uc & 0x3f)) + end + end + printf "\n" +end +document printqstring_utf8 + Prints the contents of a QString encoded in utf8. + Nice if you run your debug session in a utf8 enabled terminal. +end + +define printqcstring + print $arg0.shd.data + print $arg0.shd.len +end +document printqcstring + Prints the contents of a QCString (char * data, then length) +end + +define printq4bytearray + print $arg0->d->data +end +document printq4bytearray + Prints the contents of a Qt4 QByteArray (when it contains a string) +end + +define printqfont + print *($arg0).d + printqstring ($arg0).d->request.family + print ($arg0).d->request.pointSize +end +document printqfont + Prints the main attributes from a QFont, in particular the requested + family and point size +end + +define printqcolor + printf "(%d,%d,%d)\n", ($arg0).red(), ($arg0).green(), ($arg0).blue() +end +document printqcolor + Prints a QColor as (R,G,B). + Usage: 'printqcolor <QColor col> +end + +define printqmemarray + # Maybe we could find it out the type by parsing "whatis $arg0"? + set $arr = $arg0 + set $sz = sizeof($arg1) + set $len = $arr->shd->len / $sz + output $len + printf " items in the array\n" + set $i = 0 + while $i < $len + # print "%s[%d] = %s\n", $arr, $i, *($arg1 *)(($arr->vec)[$i]) + print *($arg1 *)(($arr->shd->data) + ($i * $sz)) + set $i++ + end +end +document printqmemarray + Prints the contents of a QMemArray. Pass the type as second argument. +end + +define printqptrvector + # Maybe we could find it out the type by parsing "whatis $arg0"? + set $arr = $arg0 + set $len = $arr->len + output $len + printf " items in the vector\n" + set $i = 0 + while $i < $len + # print "%s[%d] = %s\n", $arr, $i, *($arg1 *)(($arr->vec)[$i]) + print *($arg1 *)(($arr->vec)[$i]) + set $i++ + end +end +document printqptrvector + Prints the contents of a QPtrVector. Pass the type as second argument. +end + +define printqptrvectoritem + set $arr = $arg0 + set $i = $arg2 + print ($arg1 *)(($arr->vec)[$i]) + print *($arg1 *)(($arr->vec)[$i]) +end +document printqptrvectoritem + Print one item of a QPtrVector + Usage: printqptrvectoritem vector type index +end + +define printqmap + set $map = $arg0 + set $len = $map.sh->node_count + output $len + printf " items in the map\n" + set $header = $map.sh->header + # How to parse the key and value types from whatis? + set $it = (QMapNode<$arg1,$arg2> *)($header->left) + while $it != $header + printf " key=" + output $it->key + printf " value=" + output $it->data + printf "\n" + _qmapiterator_inc $it + set $it = (QMapNode<$arg1,$arg2> *)($ret) + end +end +document printqmap + Prints the full contents of a QMap + Usage: 'printqmap map keytype valuetype' +end + + +define _qmapiterator_inc + set $ret = $arg0 + if $ret->right != 0 + set $ret = $ret->right + while $ret->left != 0 + set $ret = $ret->left + end + else + set $y = $ret->parent + while $ret == $y->right + set $ret = $y + set $y = $y->parent + end + if $ret->right != $y + set $ret = $y + end + end +end +document _qmapiterator_inc + Increment a qmap iterator (internal method, used by printqmap) +end + +define printqptrlist + set $list = $arg0 + set $len = $list.numNodes + output $len + printf " items in the list\n" + set $it = $list.firstNode + while $it != 0 + output $it->data + printf "\n" + set $it = $it->next + end +end +document printqptrlist + Prints the contents of a QPtrList. + Usage: printqptrlist mylist +end + +define printqvaluelist + set $list = $arg0 + set $len = $list.sh->nodes + output $len + printf " items in the list\n" + set $it = $list.sh->node->next + set $end = $list.sh->node + while $it != $end + output $it->data + printf "\n" + set $it = $it->next + end +end +document printqvaluelist + Prints the contents of a QValueList. + Usage: printqvaluelist mylist +end + +define printqstringlist + set $list = $arg0 + set $len = $list.sh->nodes + output $len + printf " items in the list\n" + set $it = $list.sh->node->next + set $end = $list.sh->node + while $it != $end + printqstring $it->data + set $it = $it->next + end +end +document printqstringlist + Prints the contents of a QStringList. + Usage: printqstringlist mylist +end + +# Bad implementation, requires a running process. +# Needs to be refined, i.e. figuring out the right void* pointers casts. +# Simon says: each Node contains the d pointer of the QString. +define printq4stringlist + # This is ugly, but we need to avoid conflicts with printq4string's own vars... + set $q4sl_i = 0 + set $q4sl_d = & $arg0 + set $q4sl_sz = $q4sl_d->size() + while $q4sl_i < $q4sl_sz + output $q4sl_i + printf " " + printq4string $q4sl_d->at($q4sl_i++) + end +end +document printq4stringlist + Prints the contents of a Qt4 QStringList. + Usage: printq4stringlist mylist +end + +define printqdatetime + printqdate ($arg0).d + printqtime ($arg0).t +end +document printqdatetime + Prints a QDateTime + Usage: printqdatetime myqdt +end +define printqdate + printf "(Y:%d M:%d D:%d)\n", ($arg0).year(), ($arg0).month(), ($arg0).day() +end +document printqdate + Prints a QDate + Usage: printqdate mydate +end +define printqtime + printf "(H:%d M:%d S:%d)\n", ($arg0).hour(), ($arg0).minute(), ($arg0).second() +end +document printqtime + Prints a QTime + Usage: printqtime mytime +end + + diff --git a/scripts/kde-devel-vim.vim b/scripts/kde-devel-vim.vim new file mode 100644 index 00000000..bcb02b4c --- /dev/null +++ b/scripts/kde-devel-vim.vim @@ -0,0 +1,428 @@ +" To use this file, add this line to your ~/.vimrc:, w/o the dquote +" source /path/to/kde/sources/kdesdk/scripts/kde-devel-vim.vim +" +" For CreateChangeLogEntry() : If you don't want to re-enter your +" Name/Email in each vim session then make sure to have the viminfo +" option enabled in your ~/.vimrc, with the '!' flag, enabling persistent +" storage of global variables. Something along the line of +" set viminfo=%,!,'50,\"100,:100,n~/.viminfo +" should do the trick. + +" Don't include these in filename completions +set suffixes+=.lo,.o,.moc,.la,.closure,.loT + +" Search for headers here +set path=.,/usr/include,/usr/local/include, +if $QTDIR != '' + let &path = &path . $QTDIR . '/include/,' +endif +if $KDEDIR != '' + let &path = &path . $KDEDIR . '/include/,' + let &path = &path . $KDEDIR . '/include/arts/,' +endif +if $KDEDIRS != '' + let &path = &path . substitute( $KDEDIRS, '\(:\|$\)', '/include,', 'g' ) + let &path = &path . substitute( $KDEDIRS, '\(:\|$\)', '/include/arts,', 'g' ) +endif +set path+=, + +" Use makeobj to build +set mp=makeobj + +" If TagList is Loaded then get a funny statusline +" Only works if kde-devel-vim.vim is loaded after taglist. +" Droping this script in ~/.vim/plugin works fine +if exists('loaded_taglist') + let Tlist_Process_File_Always=1 + set statusline=%<%f:[\ %{Tlist_Get_Tag_Prototype_By_Line()}\ ]\ %h%m%r%=%-14.(%l,%c%V%)\ %P +endif + +" Insert tab character in whitespace-only lines, complete otherwise +inoremap <Tab> <C-R>=SmartTab()<CR> + +if !exists("DisableSmartParens") +" Insert a space after ( or [ and before ] or ) unless preceded by a matching +" paren/bracket or space or inside a string or comment. Comments are only +" recognized as such if they start on the current line :-( +inoremap ( <C-R>=SmartParens( '(' )<CR> +inoremap [ <C-R>=SmartParens( '[' )<CR> +inoremap ] <C-R>=SmartParens( ']', '[' )<CR> +inoremap ) <C-R>=SmartParens( ')', '(' )<CR> +endif + +" Insert an #include statement for the current/last symbol +inoremap <F5> <C-O>:call AddHeader()<CR> + +" Insert a forward declaration for the current/last symbol +" FIXME: not implemented yet +" inoremap <S-F5> <C-O>:call AddForward()<CR> + +" Switch between header and implementation files on ,h +nmap <silent> ,h :call SwitchHeaderImpl()<CR> + +" Comment selected lines on ,c in visual mode +vmap ,c :s,^,//X ,<CR>:noh<CR> +" Uncomment selected lines on ,u in visual mode +vmap ,u :s,^//X ,,<CR> + +" Insert an include guard based on the file name on ,i +nmap ,i :call IncludeGuard()<CR>o + +" Insert simple debug statements into each method +nmap ,d :call InsertMethodTracer()<CR> + +" Expand #i to #include <.h> or #include ".h". The latter is chosen +" if the character typed after #i is a dquote +" If the character is > #include <> is inserted (standard C++ headers w/o .h) +iab #i <C-R>=SmartInclude()<CR> + +" Insert a stripped down CVS diff +iab DIFF <Esc>:call RunDiff()<CR> + +" mark 'misplaced' tab characters +set listchars=tab:·\ ,trail:· +set list + +set incsearch + +function! SmartTab() + let col = col('.') - 1 + if !col || getline('.')[col-1] !~ '\k' + return "\<Tab>" + else + return "\<C-P>" + endif +endfunction + +function! SmartParens( char, ... ) + if ! ( &syntax =~ '^\(c\|cpp\|java\)$' ) + return a:char + endif + let s = strpart( getline( '.' ), 0, col( '.' ) - 1 ) + if s =~ '//' + return a:char + endif + let s = substitute( s, '/\*\([^*]\|\*\@!/\)*\*/', '', 'g' ) + let s = substitute( s, "'[^']*'", '', 'g' ) + let s = substitute( s, '"\(\\"\|[^"]\)*"', '', 'g' ) + if s =~ "\\([\"']\\|/\\*\\)" + return a:char + endif + if a:0 > 0 + if strpart( getline( '.' ), col( '.' ) - 3, 2 ) == a:1 . ' ' + return "\<BS>" . a:char + endif + if strpart( getline( '.' ), col( '.' ) - 2, 1 ) == ' ' + return a:char + endif + return ' ' . a:char + endif + if a:char == '(' + if strpart( getline( '.' ), col( '.' ) - 3, 2 ) == 'if' || + \strpart( getline( '.' ), col( '.' ) - 4, 3 ) == 'for' || + \strpart( getline( '.' ), col( '.' ) - 6, 5 ) == 'while' || + \strpart( getline( '.' ), col( '.' ) - 7, 6 ) == 'switch' + return ' ( ' + endif + endif + return a:char . ' ' +endfunction + +function! SwitchHeaderImpl() + let headers = '\.\([hH]\|hpp\|hxx\)$' + let impl = '\.\([cC]\|cpp\|cc\|cxx\)$' + let fn = expand( '%' ) + if fn =~ headers + let list = glob( substitute( fn, headers, '.*', '' ) ) + elseif fn =~ impl + let list = glob( substitute( fn, impl, '.*', '' ) ) + endif + while strlen( list ) > 0 + let file = substitute( list, "\n.*", '', '' ) + let list = substitute( list, "[^\n]*", '', '' ) + let list = substitute( list, "^\n", '', '' ) + if ( fn =~ headers && file =~ impl ) || ( fn =~ impl && file =~ headers ) + execute( "edit " . file ) + return + endif + endwhile + echohl ErrorMsg + echo "File switch failed!" + echohl None +endfunction + +function! IncludeGuard() + let guard = toupper( substitute( expand( '%' ), '\([^.]*\)\.h', '\1_h', '' ) ) + call append( '^', '#define ' . guard ) + + + call append( '^', '#ifndef ' . guard ) + call append( '$', '#endif // ' . guard ) + + +endfunction + +function! SmartInclude() + let next = nr2char( getchar( 0 ) ) + if next == '"' + return "#include \".h\"\<Left>\<Left>\<Left>" + endif + if next == '>' + return "#include <>\<Left>" + endif + return "#include <.h>\<Left>\<Left>\<Left>" +endfunction + +function! MapIdentHeader( ident ) + " Qt stuff + if a:ident =~ 'Q.*Layout' + return '<qlayout.h>' + elseif a:ident == 'QListViewItem' || + \a:ident == 'QCheckListItem' || + \a:ident == 'QListViewItemIterator' + return '<qlistview.h>' + elseif a:ident == 'QIconViewItem' || + \a:ident == 'QIconDragItem' || + \a:ident == 'QIconDrag' + return '<qiconview.h>' + elseif a:ident =~ 'Q.*Drag' || + \a:ident == 'QDragManager' + return '<qdragobject.h>' + elseif a:ident == 'QMimeSource' || + \a:ident == 'QMimeSourceFactory' || + \a:ident == 'QWindowsMime' + return '<qmime.h>' + elseif a:ident == 'QPtrListIterator' + return '<qptrlist.h>' + elseif a:ident =~ 'Q.*Event' + return '<qevent.h>' + elseif a:ident == 'QTime' || + \a:ident == 'QDate' + return '<qdatetime.h>' + elseif a:ident == 'QTimeEdit' || + \a:ident == 'QDateTimeEditBase' || + \a:ident == 'QDateEdit' + return '<qdatetimeedit.h>' + elseif a:ident == 'QByteArray' + return '<qcstring.h>' + elseif a:ident == 'QWidgetListIt' + return '<qwidgetlist.h>' + elseif a:ident == 'QTab' + return '<qtabbar.h>' + elseif a:ident == 'QColorGroup' + return '<qpalette.h>' + elseif a:ident == 'QActionGroup' + return '<qaction.h>' + elseif a:ident =~ 'Q.*Validator' + return '<qvalidator.h>' + elseif a:ident =~ 'QListBox.*' + return '<qlistbox.h>' + elseif a:ident == 'QChar' || + \a:ident == 'QCharRef' || + \a:ident == 'QConstString' + return '<qstring.h>' + elseif a:ident =~ 'QCanvas.*' + return '<qcanvas.h>' + elseif a:ident =~ 'QGL.*' + return '<qgl.h>' + elseif a:ident == 'QTableSelection' || + \a:ident == 'QTableItem' || + \a:ident == 'QComboTableItem' || + \a:ident == 'QCheckTableItem' + return '<qtable.h>' + elseif a:ident == 'qApp' + return '<qapplication.h>' + + " KDE stuff + elseif a:ident == 'K\(Double\|Int\)\(NumInput\|SpinBox\)' + return '<knuminput.h>' + elseif a:ident == 'KConfigGroup' + return '<kconfigbase.h>' + elseif a:ident == 'KListViewItem' + return '<klistview.h>' + elseif a:ident =~ 'kd\(Debug\|Warning\|Error\|Fatal\|Backtrace\)' + return '<kdebug.h>' + elseif a:ident == 'kapp' + return '<kapplication.h>' + elseif a:ident == 'i18n' || + \a:ident == 'I18N_NOOP' + return '<klocale.h>' + elseif a:ident == 'locate' || + \a:ident == 'locateLocal' + return '<kstandarddirs.h>' + + " aRts stuff + elseif a:ident =~ '\arts_\(debug\|info\|warning\|fatal\)' + return '<debug.h>' + + " Standard Library stuff + elseif a:ident =~ '\(std::\)\?\(cout\|cerr\|endl\)' + return '<iostream>' + elseif a:ident =~ '\(std::\)\?is\(alnum\|alpha\|ascii\|blank\|graph\|lower\|print\|punct\|space\|upper\|xdigit\)' + return '<cctype>' + endif + + let header = tolower( substitute( a:ident, '::', '/', 'g' ) ) . '.h' + let check = header + while 1 + if filereadable( check ) + return '"' . check . '"' + endif + let slash = match( check, '/' ) + if slash == -1 + return '<' . header . '>' + endif + let check = strpart( check, slash + 1 ) + endwhile +endfunction + +" This is a rather dirty hack, but seems to work somehow :-) (malte) +function! AddHeader() + let s = getline( '.' ) + let i = col( '.' ) - 1 + while i > 0 && strpart( s, i, 1 ) !~ '[A-Za-z0-9_:]' + let i = i - 1 + endwhile + while i > 0 && strpart( s, i, 1 ) =~ '[A-Za-z0-9_:]' + let i = i - 1 + endwhile + let start = match( s, '[A-Za-z0-9_]\+\(::[A-Za-z0-9_]\+\)*', i ) + let end = matchend( s, '[A-Za-z0-9_]\+\(::[A-Za-z0-9_]\+\)*', i ) + if end > col( '.' ) + let end = matchend( s, '[A-Za-z0-9_]\+', i ) + endif + let ident = strpart( s, start, end - start ) + let include = '#include ' . MapIdentHeader( ident ) + + let line = 1 + let incomment = 0 + let appendpos = 0 + let codestart = 0 + while line <= line( '$' ) + let s = getline( line ) + if incomment == 1 + let end = matchend( s, '\*/' ) + if end == -1 + let line = line + 1 + continue + else + let s = strpart( s, end ) + let incomment = 0 + endif + endif + let s = substitute( s, '//.*', '', '' ) + let s = substitute( s, '/\*\([^*]\|\*\@!/\)*\*/', '', 'g' ) + if s =~ '/\*' + let incomment = 1 + elseif s =~ '^' . include + break + elseif s =~ '^#include' && s !~ '\.moc"' + let appendpos = line + elseif codestart == 0 && s !~ '^$' + let codestart = line + endif + let line = line + 1 + endwhile + if line == line( '$' ) + 1 + if appendpos == 0 + call append( codestart - 1, include ) + call append( codestart, '' ) + else + call append( appendpos, include ) + endif + endif +endfunction + +function! RunDiff() + echo 'Diffing....' + read! cvs diff -bB -I \\\#include | egrep -v '(^Index:|^=+$|^RCS file:|^retrieving revision|^diff -u|^[+-]{3})' +endfunction + +function! CreateChangeLogEntry() + let currentBuffer = expand( "%" ) + + if exists( "g:EMAIL" ) + let mail = g:EMAIL + elseif exists( "$EMAIL" ) + let mail = $EMAIL + else + let mail = inputdialog( "Enter Name/Email for Changelog entry: " ) + if mail == "" + echo "Aborted ChangeLog edit..." + return + endif + let g:EMAIL = mail + endif + + if bufname( "ChangeLog" ) != "" && bufwinnr( bufname( "ChangeLog" ) ) != -1 + execute bufwinnr( bufname( "ChangeLog" ) ) . " wincmd w" + else + execute "split ChangeLog" + endif + + let lastEntry = getline( nextnonblank( 1 ) ) + let newEntry = strftime("%Y-%m-%d") . " " . mail + + if lastEntry != newEntry + call append( 0, "" ) + call append( 0, "" ) + call append( 0, newEntry ) + endif + + " like emacs, prepend the current buffer name to the entry. but unlike + " emacs I have no idea how to figure out the current function name :( + " (Simon) + if currentBuffer != "" + let newLine = "\t* " . currentBuffer . ": " + else + let newLine = "\t* " + endif + + call append( 2, newLine ) + + execute "normal 3G$" +endfunction + +function! AddQtSyntax() + if expand( "<amatch>" ) == "cpp" + syn keyword qtKeywords signals slots emit foreach + syn keyword qtMacros Q_OBJECT Q_WIDGET Q_PROPERTY Q_ENUMS Q_OVERRIDE Q_CLASSINFO Q_SETS SIGNAL SLOT + syn keyword qtCast qt_cast qobject_cast qvariant_cast qstyleoption_cast + syn keyword qtTypedef uchar uint ushort ulong Q_INT8 Q_UINT8 Q_INT16 Q_UINT16 Q_INT32 Q_UINT32 Q_LONG Q_ULONG Q_INT64 Q_UINT64 Q_LLONG Q_ULLONG pchar puchar pcchar qint8 quint8 qint16 quint16 qint32 quint32 qint64 quint64 qlonglong qulonglong + syn keyword kdeKeywords k_dcop k_dcop_signals + syn keyword kdeMacros K_DCOP ASYNC + syn keyword cRepeat foreach + syn keyword cRepeat forever + + hi def link qtKeywords Statement + hi def link qtMacros Type + hi def link qtCast Statement + hi def link qtTypedef Type + hi def link kdeKeywords Statement + hi def link kdeMacros Type + endif +endfunction + +function! InsertMethodTracer() + :normal [[kf(yBjokdDebug() << ""()" << endl; +endfunction + +function! UpdateMocFiles() + if &syntax == "cpp" + let i = 1 + while i < 80 + let s = getline( i ) + if s =~ '^#include ".*\.moc"' + let s = substitute( s, '.*"\(.*\)\.moc"', '\1.h', '' ) + if stridx( &complete, s ) == -1 + let &complete = &complete . ',k' . s + endif + break + endif + let i = i + 1 + endwhile + endif +endfunction + +autocmd Syntax * call AddQtSyntax() +autocmd CursorHold * call UpdateMocFiles() + +" vim: sw=4 sts=4 et diff --git a/scripts/kde-emacs/HACKING b/scripts/kde-emacs/HACKING new file mode 100644 index 00000000..d3a87f22 --- /dev/null +++ b/scripts/kde-emacs/HACKING @@ -0,0 +1,7 @@ +Rules are simple: +1) Make sure that your functions work both on GNU/Emacs and XEmacs. +2) Put general variables in kde-emacs-vars.el, file related variables +inside the related file. +3) Export general functions to kde-emacs-general.el. +4) Always provide documentation for both variables and functions that +you're adding. diff --git a/scripts/kde-emacs/dirvars.el b/scripts/kde-emacs/dirvars.el new file mode 100644 index 00000000..5fba18e7 --- /dev/null +++ b/scripts/kde-emacs/dirvars.el @@ -0,0 +1,200 @@ +;;; -*- local-enable-local-variables: nil -*- +;;; dirvars.el --- Local variables that apply to an entire directory + +;; Copyright (C) 2002 Matt Armstrong + +;; Author: Matt Armstrong <matt@lickey.com> +;; Location: http://www.lickey.com/env/elisp/dirvars.el +;; Keywords: files +;; Version: 1.2 +;; Obscure: matt@squeaker.lickey.com|elisp/dirvars.el|20021213043855|48166 + +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Emacs allows you to specify local variable values for use when +;; editing a file either in the first line or in a local variables +;; list. +;; +;; This file provides similar functionality, but for an entire +;; directory tree. +;; +;; You simply place an .emacs-dirvars file in the root of your +;; project's tree, and you can then set emacs variables like you would +;; in a Local Variables: section at the end of a file. E.g. the +;; contents of a typical dirvars file might look like this: +;; +;; ;; -*- emacs-lisp -*- +;; ;; +;; ;; This file is processed by the dirvars emacs package. Each variable +;; ;; setting below is performed when this dirvars file is loaded. +;; ;; +;; indent-tabs-mode: nil +;; tab-width: 8 +;; show-trailing-whitespace: t +;; indicate-empty-lines: t +;; +;; Much of this code is stolen and modified from the standard Emacs +;; files.el +;; +;; This code refuses to set any symbol that meets any of these +;; criteria (this criteria is stolen from files.el): +;; +;; - the symbol is in the ignored-local-variables list +;; - the symbol has the risky-local-variable property. +;; - the symbol name ends in -hook(s), -function(s), -form(s), +;; -program, -command, or -predicate. + +;;; Todo: + +;; Implement the following changes to keep in line with elisp coding +;; conventions: When a package provides a modification of ordinary +;; Emacs behavior, it is good to include a command to enable and +;; disable the feature, Provide a command named `WHATEVER-mode' which +;; turns the feature on or off, and make it autoload (*note +;; Autoload::). Design the package so that simply loading it has no +;; visible effect--that should not enable the feature.(2) Users will +;; request the feature by invoking the command. +;; +;; Support customize? + +;;; Code: + +(defvar dirvars-enable-flag t + "*Control use of directory variables in files you visit. +The meaningful values are nil and non-nil.") + +(defun dirvars-find-upwards (file-name) + "Find a file in the current directory or one of its parents. + +Returns the fully qualified file name, or nil if it isn't found. + +The FILE-NAME specifies the file name to search for." + ;; Chase links in the source file and search in the dir where it + ;; points. + (setq dir-name (or (and buffer-file-name + (file-name-directory (file-chase-links + buffer-file-name))) + default-directory)) + ;; Chase links before visiting the file. This makes it easier to + ;; use a single file for several related directories. + (setq dir-name (file-chase-links dir-name)) + (setq dir-name (expand-file-name dir-name)) + ;; Move up in the dir hierarchy till we find a change log file. + (let ((file1 (concat dir-name file-name)) + parent-dir) + (while (and (not (file-exists-p file1)) + (progn (setq parent-dir + (file-name-directory + (directory-file-name + (file-name-directory file1)))) + ;; Give up if we are already at the root dir. + (not (string= (file-name-directory file1) + parent-dir)))) + ;; Move up to the parent dir and try again. + (setq file1 (expand-file-name file-name parent-dir))) + ;; If we found the file in a parent dir, use that. Otherwise, + ;; return nil + (if (or (get-file-buffer file1) (file-exists-p file1)) + file1 + nil))) + +(defun dirvars-eat-comment () + (while (looking-at "[ \t\n]*;") + (let ((begin (point))) + (skip-chars-forward " \t\n") + (if (looking-at ";") + (progn + (end-of-line) + (delete-region begin (point))))))) + +(defun dirvars-hack-local-variables (dirvars-file) + (save-excursion + (let ((original-buffer (current-buffer)) + (temp-buffer (get-buffer-create "*dirvars-temp*")) + (enable-local-variables (and ;local-enable-local-variables -- doesn't exist! + enable-local-variables + dirvars-enable-flag)) + (continue t) + (parse-sexp-ignore-comments t) + (lisp-mode-hook nil) + beg) + (set-buffer temp-buffer) + (erase-buffer) + (lisp-mode) + (insert-file dirvars-file) + (goto-char (point-min)) + (catch 'done + (while continue + (if (null (scan-sexps (point) 1)) + (throw 'done nil)) + (goto-char (scan-sexps (point) 1)) + (goto-char (scan-sexps (point) -1)) + (if (eobp) + (throw 'done nil)) + (setq beg (point)) + (skip-chars-forward "^:\n") + (if (not (looking-at ":")) + (error (format "Missing colon in directory variables entry at %d" + (point)))) + (skip-chars-backward " \t") + (let* ((str (buffer-substring beg (point))) + (var (read str)) + val) + ;; Read the variable value. + (skip-chars-forward "^:") + (forward-char 1) + (setq val (read (current-buffer))) + (save-excursion + (set-buffer original-buffer) + (dirvars-hack-one-local-variable dirvars-file + var val)))))))) + +(defun dirvars-hack-one-local-variable (dirvars-file var val) + "\"Set\" one variable in a local variables spec. +A few variable names are treated specially." + (cond ((memq var ignored-local-variables) + nil) + ;; Trap risky variables and such. This is the same logic + ;; that files.el uses. + ((or (get var 'risky-local-variable) + (and + (string-match "-hooks?$\\|-functions?$\\|-forms?$\\|-program$\\|-command$\\|-predicate$" + (symbol-name var)) + (not (get var 'safe-local-variable)))) + (message (format "Ignoring %s in %s" + (symbol-name var) dirvars-file))) + ;;check whether the var should be evaluated + ((eq var 'evaluate) + (eval val)) + ;; Ordinary variable, really set it. + (t (make-local-variable var) + (set var val)))) + +(defun dirvars-hack-local-variables-before () + (let ((dirvars-file (dirvars-find-upwards ".emacs-dirvars"))) + (if dirvars-file + (dirvars-hack-local-variables dirvars-file)))) + +(defadvice hack-local-variables + (before dirvars-hack-local-variables-before) + "Process dirvars before a file's local variables are processed." + (dirvars-hack-local-variables-before)) +(ad-activate 'hack-local-variables) + +(provide 'dirvars) +;;; dirvars.el ends here diff --git a/scripts/kde-emacs/kde-emacs-bindings.el b/scripts/kde-emacs/kde-emacs-bindings.el new file mode 100644 index 00000000..84202dfb --- /dev/null +++ b/scripts/kde-emacs/kde-emacs-bindings.el @@ -0,0 +1,185 @@ +;; kde-emacs-bindings.el +;; +;; Copyright (C) 2002 KDE Development Team +;; +;; This library is free software; you can redistribute it and/or +;; modify it under the terms of the GNU Lesser General Public +;; License as published by the Free Software Foundation; either +;; version 2.1 of the License, or (at your option) any later version. +;; +;; This library is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public +;; License along with this library; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +;; 02110-1301 USA + +; currently no binding for header-protection and add-file-to-makefile-am, +; you need to call them from M-x + +; ----------------------------------------------------------------- +; The list below defines the following bindings: +; +; F2 : offer a grep command (use C-u F2 if you need to specify options, like -i or -w) +; Shift-F2 : offer a grep command to search in directories below the current too.. +; +; F3/Shift-F3/F8/Shift-RMB : different ways to see the list of methods in the current buffer +; +; F4 : make +; Shift-F4 : make clean +; F5 : make install +; Shift-F5 : make install-exec +; +; Shift-F6 : compile this file [assumes libtool is being used] +; F6 : Switch from .cpp/.cc to .h and vice-versa +; F7 : The same, but try to find the current method in the other file +; F9 : Create a member method in the .cpp, the cursor being on the definition in the .h +; F10: Place point on a class name, and the respective (Qt) include file will be inserted. +; This works with all Qt classes but can easily be extended to KDE classes. +; Shift-F10: Place point on a class name, and "class Blah" will be inserted near the top. +; Meta-F10: Place point on a class name, and press Meta-F10, and konqueror will load +; Qt documentation. Customize the location of the Qt documentation with the +; variable kdab-qt-documentation. XXX will be replace with the class name. +; Example (setq kdab-qt-location "file:/packages/kde-src/qt-copy/doc/html/XXX.html") +; +; M-n: jump to the next error (after compiling) or grep matches +; +; Ctrl+Meta+D : insert a kdDebug statement with the name of the current method +; [the new hide-all-windows shortcut conflicts with that, you may have to +; change it, or use Ctrl+Meta+Shift+D (!!)] +; +; Meta Up/Down : scroll the other window (when window is split) + +; Other very useful keybindings to know about: +; C-x r m to set a named bookmark in the buffer +; C-x r b to jump to a named bookmark in the buffer +; To save bookmarks to a file type: +; M-x bookmark-write +; and to load bookmarks from a file write: +; M-x bookmark-load + +(require 'kde-emacs-core) +(require 'kde-emacs-general) +(require 'kde-emacs-utils) +(require 'klaralv) +(require 'kde-emacs-utils) +(when (featurep 'semantic) + (require 'kde-emacs-semantic) + (require 'kde-emacs-doc)) + +;; Wheelmouse support +(define-key global-map [(button4)] 'scroll-me-down) +(define-key global-map [(button5)] 'scroll-me-up) +(define-key global-map [(shift button4)] 'scroll-me-down-a-bit) +(define-key global-map [(shift button5)] 'scroll-me-up-a-bit) + +;; Some example bindings, feel free to customize :) +(define-key global-map [(meta up)] 'scroll-other-up) +(define-key global-map [(meta down)] 'scroll-other-down) +(define-key global-map [(control j)] 'goto-line) +(global-set-key [(control %)] 'match-paren) ;;for all buffers :) + +(if (featurep 'igrep) + (progn + (setq igrep-find-prune-clause + (format "-type d %s -name CVS -o -name .libs -o -name .deps %s" + (shell-quote-argument "(") + (shell-quote-argument ")"))) + (setq igrep-find-file-clause + (format "-type f %s -name %s %s -name %s %s -name %s %s -name %s" ; -type l + (shell-quote-argument "!") + (shell-quote-argument "*~") ; Emacs backup + (shell-quote-argument "!") + (shell-quote-argument "*,v") ; RCS file + (shell-quote-argument "!") + (shell-quote-argument "s.*") ; SCCS file + (shell-quote-argument "!") + (shell-quote-argument "*.o") ; compiled object + (shell-quote-argument "!") + (shell-quote-argument ".#*") ; Emacs temp file + ) + ) + (define-key global-map [(f2)] 'igrep) + (define-key global-map [(shift f2)] 'igrep-find) + (define-key global-map [(f12)] 'igrep-find) ; on the console, shift f2 gives f12 for some reason.. + ;(setq igrep-files-default 'ignore) ; too hard to use *.cc *.h with it, because of the full path + ) + (define-key global-map [(f2)] 'grep)) +(define-key global-map [(shift backspace)] 'kde-delete-backward-ws) + +;; FIXME: remember to get these working on Gnu/Emacs (Zack) +(when (eq kde-emacs-type 'xemacs) + (define-key c++-mode-map [(f8)] 'function-menu) + (define-key c++-mode-map [(f3)] 'fume-prompt-function-goto) + (define-key c++-mode-map [(shift f3)] 'fume-list-functions) + ) + +(define-key global-map [(shift button3)] 'mouse-function-menu) +(define-key global-map [(shift f4)] 'makeclean) +(define-key global-map [(f4)] 'make) +(define-key global-map [(f5)] 'makeinstall) +(define-key global-map [(shift f5)] 'makeinstallexec) +(define-key global-map [(shift f6)] 'makethisfile) +(if kde-emacs-newline-semicolon + (define-key c++-mode-map "\;" 'insert-semicolon)) +(define-key c++-mode-map [(f6)] 'kde-switch-cpp-h) +(define-key c-mode-map [(f6)] 'kde-switch-cpp-h) +(define-key c++-mode-map [(f7)] 'switch-to-function-def) +(define-key c++-mode-map [(f9)] 'agulbra-make-member) +(define-key c-mode-map [(f9)] 'agulbra-make-member) +(define-key global-map [(meta n)] 'next-error) + +; kde-emacs-headers: +(define-key c++-mode-map [(f10)] 'kdab-insert-header) +(define-key c++-mode-map [(shift f10)] 'kdab-insert-forward-decl) +(define-key c++-mode-map [(meta f10)] 'kdab-lookup-qt-documentation) +(define-key c++-mode-map [(control meta d)] 'insert-kdDebug) + +; Standard Qt/KDE shortcuts: Ctrl+Backspace, Ctrl+Delete +(define-key global-map [(control backspace)] 'backward-kill-word) +(define-key global-map [(control delete)] 'kill-word) + +; Standard Qt/KDE shortcuts: Control Pageup and Pagedown +(define-key global-map [(control prior)] 'beginning-of-buffer) +(define-key global-map [(control next)] 'end-of-buffer) + +; kde-emacs-semantic : +; no binding for kde-license-insert; call it via M-x +(when (featurep 'semantic) + (define-key c++-mode-map [(control c)(control k)(d)] 'kde-doc-function-insert) + (define-key c++-mode-map [(control c)(control k)(m)] 'kde-doc-multiline-insert) + (define-key c++-mode-map [(control c)(control k)(o)] 'kde-doc-oneliner-insert) + (define-key c++-mode-map [(control c)(control k)(e)] 'kde-function-expand-at-point) + (define-key c++-mode-map [(control c)(control k)(s)] 'kde-create-skeletons)) + +(modify-frame-parameters (selected-frame) '((menu-bar-lines . 2))) +(define-key c++-mode-map [menu-bar KDE] + (cons "KDE" c++-mode-map)) +(when (featurep 'semantic) + (define-key c++-mode-map [menu-bar KDE kde-doc-function-insert] + '("kde-doc-function-insert" . kde-doc-function-insert)) + (define-key c++-mode-map [menu-bar KDE kde-function-expand-at-point] + '("kde-function-expand-at-point" . kde-function-expand-at-point)) + (define-key c++-mode-map [menu-bar KDE kde-create-skeletons] + '("kde-create-skeletons" . kde-create-skeletons)) + (define-key c++-mode-map [menu-bar KDE kde-doc-multiline-insert] + '("kde-doc-multiline-insert" . kde-doc-multiline-insert))) +(define-key c++-mode-map [menu-bar KDE makeclean] + '("make clean" . makeclean)) +(define-key c++-mode-map [menu-bar KDE make] + '("make" . make)) +(define-key c++-mode-map [menu-bar KDE makeinstall] + '("make install" . makeinstall)) +(define-key c++-mode-map [menu-bar KDE makethisfile] + '("make this file" . makethisfile)) +(define-key c++-mode-map [menu-bar KDE kdeswitchcpph] + '("Switch to .h/.cpp file" . kde-switch-cpp-h)) +(define-key c++-mode-map [menu-bar KDE insert-kdDebug] + '("Insert kdDebug" . insert-kdDebug)) + + +(provide 'kde-emacs-bindings) + diff --git a/scripts/kde-emacs/kde-emacs-compat.el b/scripts/kde-emacs/kde-emacs-compat.el new file mode 100644 index 00000000..1ff1fe7a --- /dev/null +++ b/scripts/kde-emacs/kde-emacs-compat.el @@ -0,0 +1,77 @@ +;; kde-emacs-compat.el - contains compatibility functions +;; +;; Copyright (C) 2003 Zack Rusin <zack@kde.org> +;; 2003 KDE Developlment team +;; 2003 XEmacs developers +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License +;; as published by the Free Software Foundation; either version 2 +;; of the License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +;; 02110-1301, USA. + +(require 'kde-emacs-vars) + +;;GNU/Emacs does not have this one +(if (not (fboundp 'replace-in-string)) + (defun replace-in-string (str regexp newtext &optional literal) + "Replace all matches in STR for REGEXP with NEWTEXT string, + and returns the new string. +Optional LITERAL non-nil means do a literal replacement. +Otherwise treat `\\' in NEWTEXT as special: + `\\&' in NEWTEXT means substitute original matched text. + `\\N' means substitute what matched the Nth `\\(...\\)'. + If Nth parens didn't match, substitute nothing. + `\\\\' means insert one `\\'. + `\\u' means upcase the next character. + `\\l' means downcase the next character. + `\\U' means begin upcasing all following characters. + `\\L' means begin downcasing all following characters. + `\\E' means terminate the effect of any `\\U' or `\\L'." + (if (> (length str) 50) + (with-temp-buffer + (insert str) + (goto-char 1) + (while (re-search-forward regexp nil t) + (replace-match newtext t literal)) + (buffer-string)) + (let ((start 0) newstr) + (while (string-match regexp str start) + (setq newstr (replace-match newtext t literal str) + start (+ (match-end 0) (- (length newstr) (length str))) + str newstr)) + str))) + + ) + +(if (not (fboundp 'read-shell-command)) + (progn + (defvar read-shell-command-map + (let ((map (make-sparse-keymap 'read-shell-command-map))) + (if (eq kde-emacs-type 'xemacs) + (set-keymap-parents map (list minibuffer-local-map)) + (set-keymap-parent map minibuffer-local-map)) + (define-key map "\t" 'comint-dynamic-complete) + (define-key map "\M-\t" 'comint-dynamic-complete) + (define-key map "\M-?" 'comint-dynamic-list-completions) + map) + "Minibuffer keymap used by `shell-command' and related commands.") + (defun read-shell-command (prompt &optional initial-input history default-value) + "Just like read-string, but uses read-shell-command-map: +\\{read-shell-command-map}" + (let ((minibuffer-completion-table nil)) + (read-from-minibuffer prompt initial-input read-shell-command-map + nil (or history 'shell-command-history) + nil default-value))) + )) + +(provide 'kde-emacs-compat) diff --git a/scripts/kde-emacs/kde-emacs-core.el b/scripts/kde-emacs/kde-emacs-core.el new file mode 100644 index 00000000..a954dfa0 --- /dev/null +++ b/scripts/kde-emacs/kde-emacs-core.el @@ -0,0 +1,3823 @@ +;; kde-emacs-core.el - core functionality,e.g. syntax & c++-mode-hook +;; +;; Copyright (C) 2002 KDE Development Team <www.kde.org> +;; +;; This library is free software; you can redistribute it and/or +;; modify it under the terms of the GNU Lesser General Public +;; License as published by the Free Software Foundation; either +;; version 2.1 of the License, or (at your option) any later version. +;; +;; This library is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public +;; License along with this library; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +;; 02110-1301 USA + +(require 'kde-emacs-vars) +;*---------------------------------------------------------------------*/ +;* Variables ... */ +;*---------------------------------------------------------------------*/ + +(defcustom kde-tab-behavior 'default + "Specifies the current tab behavior. default will expand try to complete +the symbol at point if at the end of something that looks like an indentifier else +it will indent the current line if the pointer is at the beginning of the line it will +be moved the the start of the indention. abbrev-indent behaves like default, but the +cursor isn't moved to the beginning of the indention with tab is pressed when the cursor +is at the beginning of the line. indent simply indents the line without trying to +complete the symbol" + :group 'kde-devel + :version "0.1" + :type `(choice (const default) (const abbrev-indent) (const indent))) + +;*---------------------------------------------------------------------*/ +;* Functions ... */ +;*---------------------------------------------------------------------*/ + + +;; ------- First part, from Arnt's "c++ stuff" - slightly modified for our needs :) + +(defun agulbra-c++-tab (arg) + "Do the right thing about tabs in c++ mode. +Try to finish the symbol, or indent the line." + (interactive "*P") + (cond + ((and (not (looking-at "[A-Za-z0-9]")) + (save-excursion + (forward-char -1) + (looking-at "[A-Za-z0-9:>_\\-\\&\\.(){}\\*\\+/]"))) + (dabbrev-expand arg)) + (t + (if (eq kde-tab-behavior 'default) + (c-indent-command) + (save-excursion + (beginning-of-line) + (c-indent-command)))))) + +(defun agulbra-clean-out-spaces () + "Remove spaces at ends of lines." + (interactive) + (and (not buffer-read-only) + (save-excursion + (goto-char (point-min)) + (let ((count 0) + (bmp (buffer-modified-p))) + (while (re-search-forward "[ \t]+$" nil t) + (setq count (1+ count)) + (replace-match "" t t)) + (set-buffer-modified-p bmp) + nil + )))) + +; the above used to contain (untabify (point-min) (point-max)) too + +(defun agulbra-c++-clean-out-spaces () + "Remove spaces at ends of lines, only in c++ mode." + (interactive) + (if (eq major-mode 'c++-mode) + (agulbra-clean-out-spaces) + ) + ) + +(defun agulbra-delete-into-nomenclature (&optional arg) + "Delete forward until the end of a nomenclature section or word. +With arg, do it arg times." + (interactive "p") + (save-excursion + (let ((b (point-marker))) + (c-forward-into-nomenclature arg) + (delete-region b (point-marker))))) + + +(if (not (fboundp 'font-lock-add-keywords)) + (defun font-lock-add-keywords (mode keywords &optional append) + "XEmacs doesn't have font-lock-add-keywords so we provide it." + (font-lock-set-defaults) + (if (eq append 'set) + (setq font-lock-keywords keywords) + ; NOTE: write this function for XEmacs - Zack + ;(font-lock-remove-keywords nil keywords) ;to avoid duplicates + (let ((old (if (eq (car-safe font-lock-keywords) t) + (cdr font-lock-keywords) + font-lock-keywords))) + (setq font-lock-keywords (if append + (append old keywords) + (append keywords old)))))) + ) + +(c-add-style "kde-c" '("stroustrup" + (c-basic-offset . 4) + (c-offsets-alist + (case-label . 4) + (access-label . -) + (label . 0) + (statement-cont . c-lineup-math) + ))) + +; ( we use Backquote ( '`' ) instead of "'" because we want +; kde-access-labels to be evaluated... ) +(c-add-style "kde-c++" `("kde-c" + ;;FIXME: 1) fume functions not available on GNU/Emacs + ;; 2) insert-tab-mode no longer present (free variable) + ;; 3) c-hangin-commment-under-p no longer present (free variable) + (if (not (eq kde-tab-behavior 'indent)) + (c-tab-always-indent . nil)) + ; (insert-tab-mode nil) + (indent-tabs-mode . nil) + (if (eq kde-emacs-type 'xemacs) + (fume-auto-rescan-buffer-p nil)) + (c-access-key . ,kde-access-labels) + (c-opt-access-key . ,kde-access-labels) + ; (c-hanging-comment-under-p nil) + (c-offsets-alist . ((case-label . 0) + (inline-open . 0))) + )) + +;; KDE C++ mode +;; Not a "(setq c++-mode-hook ..." because this way we would +;; prune all other hooks! +(defun kde-c++-mode-hook () + (font-lock-mode) + (c-set-style kde-c++-style) + (define-key c++-mode-map "\C-m" 'c-context-line-break) + (when (or + (eq kde-tab-behavior 'default) + (eq kde-tab-behavior 'abbrev-indent)) + (define-key c++-mode-map "\C-i" 'agulbra-c++-tab)) + (define-key c++-mode-map "\ef" 'c-forward-into-nomenclature) + (define-key c++-mode-map "\ed" 'agulbra-delete-into-nomenclature) + (define-key c++-mode-map "\eb" 'c-backward-into-nomenclature) + ;; fontify "public|protected|private slots" with one and the same face :) + ;; NOTE: write face-at-point function to fontify those just like other + ;; access specifiers + (font-lock-add-keywords nil '(("\\<\\(\\(public\\|protected\\|private\\) slots\\)\\>" + . font-lock-reference-face))) + ;; Add (setq magic-keys-mode nil) to your .emacs (before loading this file) + ;; to disable the magic keys in C++ mode. + (and (boundp 'magic-keys-mode) magic-keys-mode + (progn + (define-key c++-mode-map "\(" 'insert-parens) + (define-key c++-mode-map "\)" 'insert-parens2) + (define-key c++-mode-map "\," 'insert-comma) + (define-key c++-mode-map "\{" 'insert-curly-brace) + )) + ) + +(defun kde-c-mode-hook () + (font-lock-mode) + (c-set-style kde-c-style)) + +;; NOTE : This is a completely new c-guess-basic-syntax, it's faster, +;; better, meaner, harder, covers more cases, more c++ syntax, +;; and is in general cooler ;) You have to have the new cc-mode +;; to use it ( 5.30 at least, check it with "M-x c-version") +;; If you don't have 5.30 comment out the following c-guess-basic-syntax +;; and uncomment the one underneath. +(cond + ((string-match "^5\\.30\\." c-version) + (defun c-guess-basic-syntax () + "Return the syntactic context of the current line. +This function does not do any hidden buffer changes." + (save-excursion + (save-restriction + (beginning-of-line) + (c-save-buffer-state + ((indent-point (point)) + (case-fold-search nil) + (paren-state (c-parse-state)) + literal containing-sexp char-before-ip char-after-ip lim + c-syntactic-context placeholder c-in-literal-cache step-type + tmpsymbol keyword injava-inher special-brace-list + ;; narrow out any enclosing class or extern "C" block + (inclass-p (c-narrow-out-enclosing-class paren-state + indent-point)) + ;; `c-state-cache' is shadowed here so that we don't + ;; throw it away due to the narrowing that might be done + ;; by the function above. That means we must not do any + ;; changes during the execution of this function, since + ;; `c-invalidate-state-cache' then would change this local + ;; variable and leave a bogus value in the global one. + (c-state-cache (if inclass-p + (c-whack-state-before (point-min) paren-state) + paren-state)) + (c-state-cache-start (point-min)) + inenclosing-p macro-start in-macro-expr + ;; There's always at most one syntactic element which got + ;; a relpos. It's stored in syntactic-relpos. + syntactic-relpos + (c-stmt-delim-chars c-stmt-delim-chars)) + ;; Check for meta top-level enclosing constructs such as + ;; extern language definitions. + (save-excursion + (save-restriction + (widen) + (when (and inclass-p + (progn + (goto-char (aref inclass-p 0)) + (looking-at c-other-decl-block-key))) + (setq inenclosing-p (match-string 1)) + (if (string-equal inenclosing-p "extern") + ;; Compatibility with legacy choice of name for the + ;; extern-lang syntactic symbols. + (setq inenclosing-p "extern-lang"))))) + + ;; Init some position variables: + ;; + ;; containing-sexp is the open paren of the closest + ;; surrounding sexp or nil if there is none that hasn't been + ;; narrowed out. + ;; + ;; lim is the position after the closest preceding brace sexp + ;; (nested sexps are ignored), or the position after + ;; containing-sexp if there is none, or (point-min) if + ;; containing-sexp is nil. + ;; + ;; c-state-cache is the state from c-parse-state at + ;; indent-point, without any parens outside the region + ;; narrowed by c-narrow-out-enclosing-class. + ;; + ;; paren-state is the state from c-parse-state outside + ;; containing-sexp, or at indent-point if containing-sexp is + ;; nil. paren-state is not limited to the narrowed region, as + ;; opposed to c-state-cache. + (if c-state-cache + (progn + (setq containing-sexp (car paren-state) + paren-state (cdr paren-state)) + (if (consp containing-sexp) + (progn + (setq lim (cdr containing-sexp)) + (if (cdr c-state-cache) + ;; Ignore balanced paren. The next entry + ;; can't be another one. + (setq containing-sexp (car (cdr c-state-cache)) + paren-state (cdr paren-state)) + ;; If there is no surrounding open paren then + ;; put the last balanced pair back on paren-state. + (setq paren-state (cons containing-sexp paren-state) + containing-sexp nil))) + (setq lim (1+ containing-sexp)))) + (setq lim (point-min))) + + ;; If we're in a parenthesis list then ',' delimits the + ;; "statements" rather than being an operator (with the + ;; exception of the "for" clause). This difference is + ;; typically only noticeable when statements are used in macro + ;; arglists. + (when (and containing-sexp + (eq (char-after containing-sexp) ?\()) + (setq c-stmt-delim-chars c-stmt-delim-chars-with-comma)) + + ;; cache char before and after indent point, and move point to + ;; the most likely position to perform the majority of tests + (goto-char indent-point) + (c-backward-syntactic-ws lim) + (setq char-before-ip (char-before)) + (goto-char indent-point) + (skip-chars-forward " \t") + (setq char-after-ip (char-after)) + + ;; are we in a literal? + (setq literal (c-in-literal lim)) + + ;; now figure out syntactic qualities of the current line + (cond + ;; CASE 1: in a string. + ((eq literal 'string) + (c-add-syntax 'string (c-point 'bopl))) + ;; CASE 2: in a C or C++ style comment. + ((and (memq literal '(c c++)) + ;; This is a kludge for XEmacs where we use + ;; `buffer-syntactic-context', which doesn't correctly + ;; recognize "\*/" to end a block comment. + ;; `parse-partial-sexp' which is used by + ;; `c-literal-limits' will however do that in most + ;; versions, which results in that we get nil from + ;; `c-literal-limits' even when `c-in-literal' claims + ;; we're inside a comment. + (setq placeholder (c-literal-limits lim))) + (c-add-syntax literal (car placeholder))) + ;; CASE 3: in a cpp preprocessor macro continuation. + ((and (save-excursion + (when (c-beginning-of-macro) + (setq macro-start (point)))) + (/= macro-start (c-point 'boi)) + (progn + (setq tmpsymbol 'cpp-macro-cont) + (or (not c-syntactic-indentation-in-macros) + (save-excursion + (goto-char macro-start) + ;; If at the beginning of the body of a #define + ;; directive then analyze as cpp-define-intro + ;; only. Go on with the syntactic analysis + ;; otherwise. in-macro-expr is set if we're in a + ;; cpp expression, i.e. before the #define body + ;; or anywhere in a non-#define directive. + (if (c-forward-to-cpp-define-body) + (let ((indent-boi (c-point 'boi indent-point))) + (setq in-macro-expr (> (point) indent-boi) + tmpsymbol 'cpp-define-intro) + (= (point) indent-boi)) + (setq in-macro-expr t) + nil))))) + (c-add-syntax tmpsymbol macro-start) + (setq macro-start nil)) + ;; CASE 11: an else clause? + ((looking-at "else\\>[^_]") + (c-beginning-of-statement-1 containing-sexp) + (c-add-stmt-syntax 'else-clause nil t nil + containing-sexp paren-state)) + ;; CASE 12: while closure of a do/while construct? + ((and (looking-at "while\\>[^_]") + (save-excursion + (prog1 (eq (c-beginning-of-statement-1 containing-sexp) + 'beginning) + (setq placeholder (point))))) + (goto-char placeholder) + (c-add-stmt-syntax 'do-while-closure nil t nil + containing-sexp paren-state)) + ;; CASE 13: A catch or finally clause? This case is simpler + ;; than if-else and do-while, because a block is required + ;; after every try, catch and finally. + ((save-excursion + (and (cond ((c-major-mode-is 'c++-mode) + (looking-at "catch\\>[^_]")) + ((c-major-mode-is 'java-mode) + (looking-at "\\(catch\\|finally\\)\\>[^_]"))) + (and (c-safe (c-backward-syntactic-ws) + (c-backward-sexp) + t) + (eq (char-after) ?{) + (c-safe (c-backward-syntactic-ws) + (c-backward-sexp) + t) + (if (eq (char-after) ?\() + (c-safe (c-backward-sexp) t) + t)) + (looking-at "\\(try\\|catch\\)\\>[^_]") + (setq placeholder (point)))) + (goto-char placeholder) + (c-add-stmt-syntax 'catch-clause nil t nil + containing-sexp paren-state)) + ;; CASE 18: A substatement we can recognize by keyword. + ((save-excursion + (and c-opt-block-stmt-key + (if (c-mode-is-new-awk-p) + (c-awk-prev-line-incomplete-p containing-sexp) ; ACM 2002/3/29 + (not (eq char-before-ip ?\;))) + (not (memq char-after-ip '(?\) ?\] ?,))) + (or (not (eq char-before-ip ?})) + (c-looking-at-inexpr-block-backward c-state-cache)) + (> (point) + (progn + ;; Ought to cache the result from the + ;; c-beginning-of-statement-1 calls here. + (setq placeholder (point)) + (while (eq (setq step-type + (c-beginning-of-statement-1 lim)) + 'label)) + (if (eq step-type 'previous) + (goto-char placeholder) + (setq placeholder (point)) + (if (and (eq step-type 'same) + (not (looking-at c-opt-block-stmt-key))) + ;; Step up to the containing statement if we + ;; stayed in the same one. + (let (step) + (while (eq + (setq step + (c-beginning-of-statement-1 lim)) + 'label)) + (if (eq step 'up) + (setq placeholder (point)) + ;; There was no containing statement afterall. + (goto-char placeholder))))) + placeholder)) + (if (looking-at c-block-stmt-2-key) + ;; Require a parenthesis after these keywords. + ;; Necessary to catch e.g. synchronized in Java, + ;; which can be used both as statement and + ;; modifier. + (and (zerop (c-forward-token-2 1 nil)) + (eq (char-after) ?\()) + (looking-at c-opt-block-stmt-key)))) + (if (eq step-type 'up) + ;; CASE 18A: Simple substatement. + (progn + (goto-char placeholder) + (cond + ((eq char-after-ip ?{) + (c-add-stmt-syntax 'substatement-open nil nil nil + containing-sexp paren-state)) + ((save-excursion + (goto-char indent-point) + (back-to-indentation) + (looking-at c-label-key)) + (c-add-stmt-syntax 'substatement-label nil nil nil + containing-sexp paren-state)) + (t + (c-add-stmt-syntax 'substatement nil nil nil + containing-sexp paren-state)))) + ;; CASE 18B: Some other substatement. This is shared + ;; with case 10. + (c-guess-continued-construct indent-point + char-after-ip + placeholder + lim + paren-state))) + ;; CASE 4: In-expression statement. C.f. cases 7B, 16A and + ;; 17E. + ((and (or c-opt-inexpr-class-key + c-opt-inexpr-block-key + c-opt-lambda-key) + (setq placeholder (c-looking-at-inexpr-block + (c-safe-position containing-sexp paren-state) + containing-sexp))) + (setq tmpsymbol (assq (car placeholder) + '((inexpr-class . class-open) + (inexpr-statement . block-open)))) + (if tmpsymbol + ;; It's a statement block or an anonymous class. + (setq tmpsymbol (cdr tmpsymbol)) + ;; It's a Pike lambda. Check whether we are between the + ;; lambda keyword and the argument list or at the defun + ;; opener. + (setq tmpsymbol (if (eq char-after-ip ?{) + 'inline-open + 'lambda-intro-cont))) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-stmt-syntax tmpsymbol nil t nil + (c-most-enclosing-brace c-state-cache (point)) + (c-whack-state-after (point) paren-state)) + (unless (eq (point) (cdr placeholder)) + (c-add-syntax (car placeholder)))) + ;; CASE 5: Line is at top level. + ((null containing-sexp) + (cond + ;; CASE 5A: we are looking at a defun, brace list, class, + ;; or inline-inclass method opening brace + ((setq special-brace-list + (or (and c-special-brace-lists + (c-looking-at-special-brace-list)) + (eq char-after-ip ?{))) + (cond + ;; CASE 5A.1: Non-class declaration block open. + ((save-excursion + (goto-char indent-point) + (skip-chars-forward " \t") + (and (c-safe (c-backward-sexp 2) t) + (looking-at c-other-decl-block-key) + (setq keyword (match-string 1) + placeholder (point)) + (if (string-equal keyword "extern") + ;; Special case for extern-lang-open. The + ;; check for a following string is disabled + ;; since it doesn't disambiguate anything. + (and ;;(progn + ;; (c-forward-sexp 1) + ;; (c-forward-syntactic-ws) + ;; (eq (char-after) ?\")) + (setq tmpsymbol 'extern-lang-open)) + (setq tmpsymbol (intern (concat keyword "-open")))) + )) + (goto-char placeholder) + (c-add-syntax tmpsymbol (c-point 'boi))) + ;; CASE 5A.2: we are looking at a class opening brace + ((save-excursion + (goto-char indent-point) + (skip-chars-forward " \t{") + (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) + (and decl + (setq placeholder (aref decl 0))) + )) + (c-add-syntax 'class-open placeholder)) + ;; CASE 5A.3: brace list open + ((save-excursion + (c-beginning-of-decl-1 lim) + (while (looking-at c-specifier-key) + (goto-char (match-end 1)) + (c-forward-syntactic-ws indent-point)) + (setq placeholder (c-point 'boi)) + (or (consp special-brace-list) + (and (or (save-excursion + (goto-char indent-point) + (setq tmpsymbol nil) + (while (and (> (point) placeholder) + (zerop (c-backward-token-2 1 t)) + (/= (char-after) ?=)) + (and c-opt-inexpr-brace-list-key + (not tmpsymbol) + (looking-at c-opt-inexpr-brace-list-key) + (setq tmpsymbol 'topmost-intro-cont))) + (eq (char-after) ?=)) + (looking-at c-brace-list-key)) + (save-excursion + (while (and (< (point) indent-point) + (zerop (c-forward-token-2 1 t)) + (not (memq (char-after) '(?\; ?\())))) + (not (memq (char-after) '(?\; ?\())) + )))) + (if (and (not c-auto-newline-analysis) + (c-major-mode-is 'java-mode) + (eq tmpsymbol 'topmost-intro-cont)) + ;; We're in Java and have found that the open brace + ;; belongs to a "new Foo[]" initialization list, + ;; which means the brace list is part of an + ;; expression and not a top level definition. We + ;; therefore treat it as any topmost continuation + ;; even though the semantically correct symbol still + ;; is brace-list-open, on the same grounds as in + ;; case B.2. + (progn + (c-beginning-of-statement-1 lim) + (c-add-syntax 'topmost-intro-cont (c-point 'boi))) + (c-add-syntax 'brace-list-open placeholder))) + ;; CASE 5A.4: inline defun open + ((and inclass-p (not inenclosing-p)) + (c-add-syntax 'inline-open) + (c-add-class-syntax 'inclass inclass-p paren-state)) + ;; CASE 5A.5: ordinary defun open + (t + (goto-char placeholder) + (if (or inclass-p macro-start) + (c-add-syntax 'defun-open (c-point 'boi)) + ;; Bogus to use bol here, but it's the legacy. + (c-add-syntax 'defun-open (c-point 'bol))) + ))) + ;; CASE 5B: first K&R arg decl or member init + ((c-just-after-func-arglist-p lim) + (cond + ;; CASE 5B.1: a member init + ((or (eq char-before-ip ?:) + (eq char-after-ip ?:)) + ;; this line should be indented relative to the beginning + ;; of indentation for the topmost-intro line that contains + ;; the prototype's open paren + ;; TBD: is the following redundant? + (if (eq char-before-ip ?:) + (forward-char -1)) + (c-backward-syntactic-ws lim) + ;; TBD: is the preceding redundant? + (if (eq (char-before) ?:) + (progn (forward-char -1) + (c-backward-syntactic-ws lim))) + (if (eq (char-before) ?\)) + (c-backward-sexp 1)) + (setq placeholder (point)) + (save-excursion + (and (c-safe (c-backward-sexp 1) t) + (looking-at "throw[^_]") + (c-safe (c-backward-sexp 1) t) + (setq placeholder (point)))) + (goto-char placeholder) + (c-add-syntax 'member-init-intro (c-point 'boi)) + ;; we don't need to add any class offset since this + ;; should be relative to the ctor's indentation + ) + ;; CASE 5B.2: K&R arg decl intro + (c-recognize-knr-p + (c-beginning-of-statement-1 lim) + (c-add-syntax 'knr-argdecl-intro (c-point 'boi)) + (if inclass-p + (c-add-class-syntax 'inclass inclass-p paren-state))) + ;; CASE 5B.3: Inside a member init list. + ((c-beginning-of-member-init-list lim) + (c-forward-syntactic-ws) + (c-add-syntax 'member-init-cont (point))) + ;; CASE 5B.4: Nether region after a C++ or Java func + ;; decl, which could include a `throws' declaration. + (t + (c-beginning-of-statement-1 lim) + (c-add-syntax 'func-decl-cont (c-point 'boi)) + ))) + ;; CASE 5C: inheritance line. could be first inheritance + ;; line, or continuation of a multiple inheritance + ((or (and (c-major-mode-is 'c++-mode) + (progn + (when (eq char-after-ip ?,) + (skip-chars-forward " \t") + (forward-char)) + (looking-at c-opt-postfix-decl-spec-key))) + (and (or (eq char-before-ip ?:) + ;; watch out for scope operator + (save-excursion + (and (eq char-after-ip ?:) + (c-safe (forward-char 1) t) + (not (eq (char-after) ?:)) + ))) + (save-excursion + (c-backward-syntactic-ws lim) + (if (eq char-before-ip ?:) + (progn + (forward-char -1) + (c-backward-syntactic-ws lim))) + (back-to-indentation) + (looking-at c-class-key))) + ;; for Java + (and (c-major-mode-is 'java-mode) + (let ((fence (save-excursion + (c-beginning-of-statement-1 lim) + (point))) + cont done) + (save-excursion + (while (not done) + (cond ((looking-at c-opt-postfix-decl-spec-key) + (setq injava-inher (cons cont (point)) + done t)) + ((or (not (c-safe (c-forward-sexp -1) t)) + (<= (point) fence)) + (setq done t)) + ) + (setq cont t))) + injava-inher) + (not (c-crosses-statement-barrier-p (cdr injava-inher) + (point))) + )) + (cond + ;; CASE 5C.1: non-hanging colon on an inher intro + ((eq char-after-ip ?:) + (c-beginning-of-statement-1 lim) + (c-add-syntax 'inher-intro (c-point 'boi)) + ;; don't add inclass symbol since relative point already + ;; contains any class offset + ) + ;; CASE 5C.2: hanging colon on an inher intro + ((eq char-before-ip ?:) + (c-beginning-of-statement-1 lim) + (c-add-syntax 'inher-intro (c-point 'boi)) + (if inclass-p + (c-add-class-syntax 'inclass inclass-p paren-state))) + ;; CASE kde hack: + ((and inclass-p + c-access-key + (looking-at c-access-key)) + (c-add-syntax 'access-label (c-point 'bonl)) + (c-add-class-syntax 'inclass inclass-p paren-state) + ) + ;; CASE 5C.3: in a Java implements/extends + (injava-inher + (let ((where (cdr injava-inher)) + (cont (car injava-inher))) + (goto-char where) + (cond ((looking-at "throws\\>[^_]") + (c-add-syntax 'func-decl-cont + (progn (c-beginning-of-statement-1 lim) + (c-point 'boi)))) + (cont (c-add-syntax 'inher-cont where)) + (t (c-add-syntax 'inher-intro + (progn (goto-char (cdr injava-inher)) + (c-beginning-of-statement-1 lim) + (point)))) + ))) + ;; CASE 5C.4: a continued inheritance line + (t + (c-beginning-of-inheritance-list lim) + (c-add-syntax 'inher-cont (point)) + ;; don't add inclass symbol since relative point already + ;; contains any class offset + ))) + ;; CASE 5D: this could be a top-level initialization, a + ;; member init list continuation, or a template argument + ;; list continuation. + ((c-with-syntax-table (if (c-major-mode-is 'c++-mode) + c++-template-syntax-table + (syntax-table)) + (save-excursion + ;; Note: We use the fact that lim is always after any + ;; preceding brace sexp. + (while (and (zerop (c-backward-token-2 1 t lim)) + (not (looking-at "[;<,=]")))) + (or (memq (char-after) '(?, ?=)) + (and (c-major-mode-is 'c++-mode) + (zerop (c-backward-token-2 1 nil lim)) + (eq (char-after) ?<))))) + (goto-char indent-point) + (setq placeholder + (c-beginning-of-member-init-list lim)) + (cond + ;; CASE 5D.1: hanging member init colon, but watch out + ;; for bogus matches on access specifiers inside classes. + ((and placeholder + (save-excursion + (setq placeholder (point)) + (c-backward-token-2 1 t lim) + (and (eq (char-after) ?:) + (not (eq (char-before) ?:)))) + (save-excursion + (goto-char placeholder) + (back-to-indentation) + (or + (/= (car (save-excursion + (parse-partial-sexp (point) placeholder))) + 0) + (and + (if c-opt-access-key + (not (looking-at c-opt-access-key)) t) + (not (looking-at c-class-key)) + (if c-opt-bitfield-key + (not (looking-at c-opt-bitfield-key)) t)) + ))) + (goto-char placeholder) + (c-forward-syntactic-ws) + (c-add-syntax 'member-init-cont (point)) + ;; we do not need to add class offset since relative + ;; point is the member init above us + ) + ;; CASE 5D.2: non-hanging member init colon + ((progn + (c-forward-syntactic-ws indent-point) + (eq (char-after) ?:)) + (skip-chars-forward " \t:") + (c-add-syntax 'member-init-cont (point))) + ;; CASE 5D.3: perhaps a template list continuation? + ((and (c-major-mode-is 'c++-mode) + (save-excursion + (save-restriction + (c-with-syntax-table c++-template-syntax-table + (goto-char indent-point) + (setq placeholder (c-up-list-backward (point))) + (and placeholder + (eq (char-after placeholder) ?<)))))) + ;; we can probably indent it just like an arglist-cont + (goto-char placeholder) + (c-beginning-of-statement-1 lim t) + (c-add-syntax 'template-args-cont (c-point 'boi))) + ;; CASE 5D.4: perhaps a multiple inheritance line? + ((and (c-major-mode-is 'c++-mode) + (save-excursion + (c-beginning-of-statement-1 lim) + (setq placeholder (point)) + (if (looking-at "static\\>[^_]") + (c-forward-token-2 1 nil indent-point)) + (and (looking-at c-class-key) + (zerop (c-forward-token-2 2 nil indent-point)) + (if (eq (char-after) ?<) + (c-with-syntax-table c++-template-syntax-table + (zerop (c-forward-token-2 1 t indent-point))) + t) + (eq (char-after) ?:)))) + (goto-char placeholder) + (c-add-syntax 'inher-cont (c-point 'boi))) + ;; CASE 5D.5: Continuation of the "expression part" of a + ;; top level construct. + (t + (while (and (eq (car (c-beginning-of-decl-1 containing-sexp)) + 'same) + (save-excursion + (c-backward-syntactic-ws) + (eq (char-before) ?})))) + (c-add-stmt-syntax + (if (eq char-before-ip ?,) + ;; A preceding comma at the top level means that a + ;; new variable declaration starts here. Use + ;; topmost-intro-cont for it, for consistency with + ;; the first variable declaration. C.f. case 5N. + 'topmost-intro-cont + 'statement-cont) + nil nil nil containing-sexp paren-state)) + )) + ;; CASE 5E: we are looking at a access specifier + ((and inclass-p + c-opt-access-key + (looking-at c-opt-access-key)) + (setq placeholder (c-add-class-syntax 'inclass inclass-p + paren-state)) + ;; Append access-label with the same anchor point as inclass gets. + (c-append-syntax 'access-label placeholder)) + ;; CASE 5F: Close of a non-class declaration level block. + ((and inenclosing-p + (eq char-after-ip ?})) + (c-add-syntax (intern (concat inenclosing-p "-close")) + (aref inclass-p 0))) + ;; CASE 5G: we are looking at the brace which closes the + ;; enclosing nested class decl + ((and inclass-p + (eq char-after-ip ?}) + (save-excursion + (save-restriction + (widen) + (forward-char 1) + (and (c-safe (c-backward-sexp 1) t) + (= (point) (aref inclass-p 1)) + )))) + (c-add-class-syntax 'class-close inclass-p paren-state)) + ;; CASE 5H: we could be looking at subsequent knr-argdecls + ((and c-recognize-knr-p + (not (eq char-before-ip ?})) + (save-excursion + (setq placeholder (cdr (c-beginning-of-decl-1 lim))) + (and placeholder + ;; Do an extra check to avoid tripping up on + ;; statements that occur in invalid contexts + ;; (e.g. in macro bodies where we don't really + ;; know the context of what we're looking at). + (not (and c-opt-block-stmt-key + (looking-at c-opt-block-stmt-key))))) + (< placeholder indent-point)) + (goto-char placeholder) + (c-add-syntax 'knr-argdecl (point))) + ;; CASE 5I: ObjC method definition. + ((and c-opt-method-key + (looking-at c-opt-method-key)) + (c-beginning-of-statement-1 lim) + (c-add-syntax 'objc-method-intro (c-point 'boi))) + ;; CASE 5P: AWK pattern or function or continuation + ;; thereof. + ((c-mode-is-new-awk-p) + (setq placeholder (point)) + (c-add-stmt-syntax + (if (and (eq (c-beginning-of-statement-1) 'same) + (/= (point) placeholder)) + 'topmost-intro-cont + 'topmost-intro) + nil nil nil + containing-sexp paren-state)) + ;; CASE 5N: At a variable declaration that follows a class + ;; definition or some other block declaration that doesn't + ;; end at the closing '}'. C.f. case 5D.5. + ((progn + (c-backward-syntactic-ws lim) + (and (eq (char-before) ?}) + (save-excursion + (let ((start (point))) + (if paren-state + ;; Speed up the backward search a bit. + (goto-char (car (car paren-state)))) + (c-beginning-of-decl-1 containing-sexp) + (setq placeholder (point)) + (if (= start (point)) + ;; The '}' is unbalanced. + nil + (c-end-of-decl-1) + (>= (point) indent-point)))))) + (goto-char placeholder) + (c-add-stmt-syntax 'topmost-intro-cont nil nil nil + containing-sexp paren-state)) + ;; CASE 5J: we are at the topmost level, make + ;; sure we skip back past any access specifiers + ((progn + (while (and inclass-p + c-opt-access-key + (not (bobp)) + (save-excursion + (c-safe (progn (c-backward-sexp 1) t)) + (and (looking-at "slots:") + (c-backward-sexp 1)) + (looking-at c-opt-access-key))) + (c-backward-sexp 1) + (c-backward-syntactic-ws lim)) + (or (bobp) + (if (c-mode-is-new-awk-p) + (not (c-awk-prev-line-incomplete-p)) + (memq (char-before) '(?\; ?}))) + (and (c-major-mode-is 'objc-mode) + (progn + (c-beginning-of-statement-1 lim) + (eq (char-after) ?@))))) + ;; real beginning-of-line could be narrowed out due to + ;; enclosure in a class block + (save-restriction + (widen) + (c-add-syntax 'topmost-intro (c-point 'bol)) + ;; Using bol instead of boi above is highly bogus, and + ;; it makes our lives hard to remain compatible. :P + (if inclass-p + (progn + (goto-char (aref inclass-p 1)) + (or (= (point) (c-point 'boi)) + (goto-char (aref inclass-p 0))) + (if inenclosing-p + (c-add-syntax (intern (concat "in" inenclosing-p)) + (c-point 'boi)) + (c-add-class-syntax 'inclass inclass-p paren-state)) + )) + (when (and c-syntactic-indentation-in-macros + macro-start + (/= macro-start (c-point 'boi indent-point))) + (c-add-syntax 'cpp-define-intro) + (setq macro-start nil)) + )) + ;; CASE 5K: we are at an ObjC method definition + ;; continuation line. + ((and c-opt-method-key + (progn + (c-beginning-of-statement-1 lim) + (beginning-of-line) + (looking-at c-opt-method-key))) + (c-add-syntax 'objc-method-args-cont (point))) + ;; CASE 5L: we are at the first argument of a template + ;; arglist that begins on the previous line. + ((eq (char-before) ?<) + (c-beginning-of-statement-1 (c-safe-position (point) paren-state)) + (c-add-syntax 'template-args-cont (c-point 'boi))) + ;; CASE 5M: we are at a topmost continuation line + (t + (c-beginning-of-statement-1 (c-safe-position (point) paren-state)) + (c-add-syntax 'topmost-intro-cont (c-point 'boi))) + )) + ;; (CASE 6 has been removed.) + ;; CASE 7: line is an expression, not a statement. Most + ;; likely we are either in a function prototype or a function + ;; call argument list + ((not (or (and c-special-brace-lists + (save-excursion + (goto-char containing-sexp) + (c-looking-at-special-brace-list))) + (eq (char-after containing-sexp) ?{))) + (cond + ;; CASE 7A: we are looking at the arglist closing paren. + ;; C.f. case 7F. + ((memq char-after-ip '(?\) ?\])) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (if (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (progn + (forward-char) + (skip-chars-forward " \t")) + (goto-char placeholder)) + (c-add-stmt-syntax 'arglist-close (list containing-sexp) t nil + (c-most-enclosing-brace paren-state (point)) + (c-whack-state-after (point) paren-state))) + ;; CASE 7B: Looking at the opening brace of an + ;; in-expression block or brace list. C.f. cases 4, 16A + ;; and 17E. + ((and (eq char-after-ip ?{) + (progn + (setq placeholder (c-inside-bracelist-p (point) + c-state-cache)) + (if placeholder + (setq tmpsymbol '(brace-list-open . inexpr-class)) + (setq tmpsymbol '(block-open . inexpr-statement) + placeholder + (cdr-safe (c-looking-at-inexpr-block + (c-safe-position containing-sexp + paren-state) + containing-sexp))) + ;; placeholder is nil if it's a block directly in + ;; a function arglist. That makes us skip out of + ;; this case. + ))) + (goto-char placeholder) + (back-to-indentation) + (c-add-stmt-syntax (car tmpsymbol) nil t nil + (c-most-enclosing-brace paren-state (point)) + (c-whack-state-after (point) paren-state)) + (if (/= (point) placeholder) + (c-add-syntax (cdr tmpsymbol)))) + ;; CASE 7C: we are looking at the first argument in an empty + ;; argument list. Use arglist-close if we're actually + ;; looking at a close paren or bracket. + ((memq char-before-ip '(?\( ?\[)) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (when (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (forward-char) + (skip-chars-forward " \t") + (setq placeholder (point))) + (c-add-syntax 'arglist-intro placeholder)) + ;; CASE 7D: we are inside a conditional test clause. treat + ;; these things as statements + ((progn + (goto-char containing-sexp) + (and (c-safe (c-forward-sexp -1) t) + (looking-at "\\<for\\>[^_]"))) + (goto-char (1+ containing-sexp)) + (c-forward-syntactic-ws indent-point) + (if (eq char-before-ip ?\;) + (c-add-syntax 'statement (point)) + (c-add-syntax 'statement-cont (point)) + )) + ;; CASE 7E: maybe a continued ObjC method call. This is the + ;; case when we are inside a [] bracketed exp, and what + ;; precede the opening bracket is not an identifier. + ((and c-opt-method-key + (eq (char-after containing-sexp) ?\[) + (progn + (goto-char (1- containing-sexp)) + (c-backward-syntactic-ws (c-point 'bod)) + (if (not (looking-at c-symbol-key)) + (c-add-syntax 'objc-method-call-cont containing-sexp)) + ))) + ;; CASE 7F: we are looking at an arglist continuation line, + ;; but the preceding argument is on the same line as the + ;; opening paren. This case includes multi-line + ;; mathematical paren groupings, but we could be on a + ;; for-list continuation line. C.f. case 7A. + ((progn + (goto-char (1+ containing-sexp)) + (skip-chars-forward " \t") + (and (not (eolp)) + (not (looking-at "\\\\$")))) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (if (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (progn + (forward-char) + (skip-chars-forward " \t")) + (goto-char placeholder)) + (c-add-stmt-syntax 'arglist-cont-nonempty (list containing-sexp) + t nil + (c-most-enclosing-brace c-state-cache (point)) + (c-whack-state-after (point) paren-state))) + ;; CASE 7G: we are looking at just a normal arglist + ;; continuation line + (t (c-forward-syntactic-ws indent-point) + (c-add-syntax 'arglist-cont (c-point 'boi))) + )) + ;; CASE 8: func-local multi-inheritance line + ((and (c-major-mode-is 'c++-mode) + (save-excursion + (goto-char indent-point) + (skip-chars-forward " \t") + (looking-at c-opt-postfix-decl-spec-key))) + (goto-char indent-point) + (skip-chars-forward " \t") + (cond + ;; CASE 8A: non-hanging colon on an inher intro + ((eq char-after-ip ?:) + (c-backward-syntactic-ws lim) + (c-add-syntax 'inher-intro (c-point 'boi))) + ;; CASE 8B: hanging colon on an inher intro + ((eq char-before-ip ?:) + (c-add-syntax 'inher-intro (c-point 'boi))) + ;; CASE 8C: a continued inheritance line + (t + (c-beginning-of-inheritance-list lim) + (c-add-syntax 'inher-cont (point)) + ))) + ;; CASE 9: we are inside a brace-list + ((and (not (c-mode-is-new-awk-p)) ; Maybe this isn't needed (ACM, 2002/3/29) + (setq special-brace-list + (or (and c-special-brace-lists + (save-excursion + (goto-char containing-sexp) + (c-looking-at-special-brace-list))) + (c-inside-bracelist-p containing-sexp paren-state)))) + (cond + ;; CASE 9A: In the middle of a special brace list opener. + ((and (consp special-brace-list) + (save-excursion + (goto-char containing-sexp) + (eq (char-after) ?\()) + (eq char-after-ip (car (cdr special-brace-list)))) + (goto-char (car (car special-brace-list))) + (skip-chars-backward " \t") + (if (and (bolp) + (assoc 'statement-cont + (setq placeholder (c-guess-basic-syntax)))) + (setq c-syntactic-context placeholder) + (c-beginning-of-statement-1 + (c-safe-position (1- containing-sexp) paren-state)) + (c-forward-token-2 0) + (while (looking-at c-specifier-key) + (goto-char (match-end 1)) + (c-forward-syntactic-ws)) + (c-add-syntax 'brace-list-open (c-point 'boi)))) + ;; CASE 9B: brace-list-close brace + ((if (consp special-brace-list) + ;; Check special brace list closer. + (progn + (goto-char (car (car special-brace-list))) + (save-excursion + (goto-char indent-point) + (back-to-indentation) + (or + ;; We were between the special close char and the `)'. + (and (eq (char-after) ?\)) + (eq (1+ (point)) (cdr (car special-brace-list)))) + ;; We were before the special close char. + (and (eq (char-after) (cdr (cdr special-brace-list))) + (zerop (c-forward-token-2)) + (eq (1+ (point)) (cdr (car special-brace-list))))))) + ;; Normal brace list check. + (and (eq char-after-ip ?}) + (c-safe (goto-char (c-up-list-backward (point))) t) + (= (point) containing-sexp))) + (if (eq (point) (c-point 'boi)) + (c-add-syntax 'brace-list-close (point)) + (setq lim (c-most-enclosing-brace c-state-cache (point))) + (c-beginning-of-statement-1 lim) + (c-add-stmt-syntax 'brace-list-close nil t t lim + (c-whack-state-after (point) paren-state)))) + (t + ;; Prepare for the rest of the cases below by going to the + ;; token following the opening brace + (if (consp special-brace-list) + (progn + (goto-char (car (car special-brace-list))) + (c-forward-token-2 1 nil indent-point)) + (goto-char containing-sexp)) + (forward-char) + (let ((start (point))) + (c-forward-syntactic-ws indent-point) + (goto-char (max start (c-point 'bol)))) + (c-skip-ws-forward indent-point) + (cond + ;; CASE 9C: we're looking at the first line in a brace-list + ((= (point) indent-point) + (if (consp special-brace-list) + (goto-char (car (car special-brace-list))) + (goto-char containing-sexp)) + (if (eq (point) (c-point 'boi)) + (c-add-syntax 'brace-list-intro (point)) + (setq lim (c-most-enclosing-brace c-state-cache (point))) + (c-beginning-of-statement-1 lim) + (c-add-stmt-syntax 'brace-list-intro nil t t lim + (c-whack-state-after (point) paren-state)))) + ;; CASE 9D: this is just a later brace-list-entry or + ;; brace-entry-open + (t (if (or (eq char-after-ip ?{) + (and c-special-brace-lists + (save-excursion + (goto-char indent-point) + (c-forward-syntactic-ws (c-point 'eol)) + (c-looking-at-special-brace-list (point))))) + (c-add-syntax 'brace-entry-open (point)) + (c-add-syntax 'brace-list-entry (point)) + )) + )))) + ;; CASE 10: A continued statement or top level construct. + ((and (if (c-mode-is-new-awk-p) + (c-awk-prev-line-incomplete-p containing-sexp) ; ACM 2002/3/29 + (and (not (memq char-before-ip '(?\; ?:))) + (or (not (eq char-before-ip ?})) + (c-looking-at-inexpr-block-backward c-state-cache)))) + (> (point) + (save-excursion + (c-beginning-of-statement-1 containing-sexp) + (setq placeholder (point)))) + (/= placeholder containing-sexp)) + ;; This is shared with case 18. + (c-guess-continued-construct indent-point + char-after-ip + placeholder + containing-sexp + paren-state)) + ;; CASE 14: A case or default label + ((looking-at c-label-kwds-regexp) + (goto-char containing-sexp) + (setq lim (c-most-enclosing-brace c-state-cache containing-sexp)) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax 'case-label nil t nil + lim paren-state)) + ;; CASE 15: any other label + ((looking-at c-label-key) + (goto-char containing-sexp) + (setq lim (c-most-enclosing-brace c-state-cache containing-sexp)) + (save-excursion + (setq tmpsymbol + (if (and (eq (c-beginning-of-statement-1 lim) 'up) + (looking-at "switch\\>[^_]")) + ;; If the surrounding statement is a switch then + ;; let's analyze all labels as switch labels, so + ;; that they get lined up consistently. + 'case-label + 'label))) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax tmpsymbol nil t nil + lim paren-state)) + ;; CASE 16: block close brace, possibly closing the defun or + ;; the class + ((eq char-after-ip ?}) + ;; From here on we have the next containing sexp in lim. + (setq lim (c-most-enclosing-brace paren-state)) + (goto-char containing-sexp) + (cond + ;; CASE 16E: Closing a statement block? This catches + ;; cases where it's preceded by a statement keyword, + ;; which works even when used in an "invalid" context, + ;; e.g. a macro argument. + ((c-after-conditional) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax 'block-close nil t nil + lim paren-state)) + ;; CASE 16A: closing a lambda defun or an in-expression + ;; block? C.f. cases 4, 7B and 17E. + ((setq placeholder (c-looking-at-inexpr-block + (c-safe-position containing-sexp paren-state) + nil)) + (setq tmpsymbol (if (eq (car placeholder) 'inlambda) + 'inline-close + 'block-close)) + (goto-char containing-sexp) + (back-to-indentation) + (if (= containing-sexp (point)) + (c-add-syntax tmpsymbol (point)) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-stmt-syntax tmpsymbol nil t nil + (c-most-enclosing-brace paren-state (point)) + (c-whack-state-after (point) paren-state)) + (if (/= (point) (cdr placeholder)) + (c-add-syntax (car placeholder))))) + ;; CASE 16B: does this close an inline or a function in + ;; a non-class declaration level block? + ((setq placeholder (c-search-uplist-for-classkey paren-state)) + (c-backward-to-decl-anchor lim) + (back-to-indentation) + (if (save-excursion + (goto-char (aref placeholder 0)) + (looking-at c-other-decl-block-key)) + (c-add-syntax 'defun-close (point)) + (c-add-syntax 'inline-close (point)))) + ;; CASE 16F: Can be a defun-close of a function declared + ;; in a statement block, e.g. in Pike or when using gcc + ;; extensions. Might also trigger it with some macros + ;; followed by blocks, and this gives sane indentation + ;; then too. Let it through to be handled below. + ;; C.f. cases B.3 and 17G. + ((and (not inenclosing-p) + lim + (save-excursion + (and (not (c-looking-at-bos)) + (eq (c-beginning-of-statement-1 lim nil nil t) 'same) + (setq placeholder (point))))) + (back-to-indentation) + (if (/= (point) containing-sexp) + (goto-char placeholder)) + (c-add-stmt-syntax 'defun-close nil t nil + lim paren-state)) + ;; CASE 16C: if there an enclosing brace that hasn't + ;; been narrowed out by a class, then this is a + ;; block-close. C.f. case 17H. + ((and (not inenclosing-p) lim) + ;; If the block is preceded by a case/switch label on + ;; the same line, we anchor at the first preceding label + ;; at boi. The default handling in c-add-stmt-syntax is + ;; really fixes it better, but we do like this to keep + ;; the indentation compatible with version 5.28 and + ;; earlier. + (while (and (/= (setq placeholder (point)) (c-point 'boi)) + (eq (c-beginning-of-statement-1 lim) 'label))) + (goto-char placeholder) + (if (looking-at c-label-kwds-regexp) + (c-add-syntax 'block-close (point)) + (goto-char containing-sexp) + ;; c-backward-to-block-anchor not necessary here; those + ;; situations are handled in case 16E above. + (c-add-stmt-syntax 'block-close nil t nil + lim paren-state))) + ;; CASE 16D: find out whether we're closing a top-level + ;; class or a defun + (t + (save-restriction + (narrow-to-region (point-min) indent-point) + (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) + (if decl + (c-add-class-syntax 'class-close decl paren-state) + (goto-char containing-sexp) + (c-backward-to-decl-anchor lim) + (back-to-indentation) + (c-add-syntax 'defun-close (point))))) + ))) + ;; CASE 17: Statement or defun catchall. + (t + (goto-char indent-point) + ;; Back up statements until we find one that starts at boi. + (while (let* ((prev-point (point)) + (last-step-type (c-beginning-of-statement-1 + containing-sexp))) + (if (= (point) prev-point) + (progn + (setq step-type (or step-type last-step-type)) + nil) + (setq step-type last-step-type) + (/= (point) (c-point 'boi))))) + (cond + ;; CASE 17B: continued statement + ((and (eq step-type 'same) + (/= (point) indent-point)) + (c-add-stmt-syntax 'statement-cont nil nil nil + containing-sexp paren-state)) + ;; CASE 17A: After a case/default label? + ((progn + (while (and (eq step-type 'label) + (not (looking-at c-label-kwds-regexp))) + (setq step-type + (c-beginning-of-statement-1 containing-sexp))) + (eq step-type 'label)) + (c-add-stmt-syntax (if (eq char-after-ip ?{) + 'statement-case-open + 'statement-case-intro) + nil t nil containing-sexp paren-state)) + ;; CASE 17D: any old statement + ((progn + (while (eq step-type 'label) + (setq step-type + (c-beginning-of-statement-1 containing-sexp))) + (eq step-type 'previous)) + (c-add-stmt-syntax 'statement nil t nil + containing-sexp paren-state) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + ;; CASE 17I: Inside a substatement block. + ((progn + ;; The following tests are all based on containing-sexp. + (goto-char containing-sexp) + ;; From here on we have the next containing sexp in lim. + (setq lim (c-most-enclosing-brace paren-state containing-sexp)) + (c-after-conditional)) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax 'statement-block-intro nil t nil + lim paren-state) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + ;; CASE 17E: first statement in an in-expression block. + ;; C.f. cases 4, 7B and 16A. + ((setq placeholder (c-looking-at-inexpr-block + (c-safe-position containing-sexp paren-state) + nil)) + (setq tmpsymbol (if (eq (car placeholder) 'inlambda) + 'defun-block-intro + 'statement-block-intro)) + (back-to-indentation) + (if (= containing-sexp (point)) + (c-add-syntax tmpsymbol (point)) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-stmt-syntax tmpsymbol nil t nil + (c-most-enclosing-brace c-state-cache (point)) + (c-whack-state-after (point) paren-state)) + (if (/= (point) (cdr placeholder)) + (c-add-syntax (car placeholder)))) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + ;; CASE 17F: first statement in an inline, or first + ;; statement in a top-level defun. we can tell this is it + ;; if there are no enclosing braces that haven't been + ;; narrowed out by a class (i.e. don't use bod here). + ((save-excursion + (save-restriction + (widen) + (c-narrow-out-enclosing-class paren-state containing-sexp) + (not (c-most-enclosing-brace paren-state)))) + (c-backward-to-decl-anchor lim) + (back-to-indentation) + (c-add-syntax 'defun-block-intro (point))) + ;; CASE 17G: First statement in a function declared inside + ;; a normal block. This can occur in Pike and with + ;; e.g. the gcc extensions. Might also trigger it with + ;; some macros followed by blocks, and this gives sane + ;; indentation then too. C.f. cases B.3 and 16F. + ((save-excursion + (and (not (c-looking-at-bos)) + (eq (c-beginning-of-statement-1 lim nil nil t) 'same) + (setq placeholder (point)))) + (back-to-indentation) + (if (/= (point) containing-sexp) + (goto-char placeholder)) + (c-add-stmt-syntax 'defun-block-intro nil t nil + lim paren-state)) + ;; CASE 17H: First statement in a block. C.f. case 16C. + (t + ;; If the block is preceded by a case/switch label on the + ;; same line, we anchor at the first preceding label at + ;; boi. The default handling in c-add-stmt-syntax is + ;; really fixes it better, but we do like this to keep the + ;; indentation compatible with version 5.28 and earlier. + (while (and (/= (setq placeholder (point)) (c-point 'boi)) + (eq (c-beginning-of-statement-1 lim) 'label))) + (goto-char placeholder) + (if (looking-at c-label-kwds-regexp) + (c-add-syntax 'statement-block-intro (point)) + (goto-char containing-sexp) + ;; c-backward-to-block-anchor not necessary here; those + ;; situations are handled in case 17I above. + (c-add-stmt-syntax 'statement-block-intro nil t nil + lim paren-state)) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + )) + ) + ;; now we need to look at any modifiers + (goto-char indent-point) + (skip-chars-forward " \t") + ;; are we looking at a comment only line? + (when (and (looking-at c-comment-start-regexp) + (/= (c-forward-token-2 0 nil (c-point 'eol)) 0)) + (c-append-syntax 'comment-intro)) + ;; we might want to give additional offset to friends (in C++). + (when (and c-opt-friend-key + (looking-at c-opt-friend-key)) + (c-append-syntax 'friend)) + + ;; Set syntactic-relpos. + (let ((p c-syntactic-context)) + (while (and p + (if (integerp (car-safe (cdr-safe (car p)))) + (progn + (setq syntactic-relpos (car (cdr (car p)))) + nil) + t)) + (setq p (cdr p)))) + + ;; Start of or a continuation of a preprocessor directive? + (if (and macro-start + (eq macro-start (c-point 'boi)) + (not (and (c-major-mode-is 'pike-mode) + (eq (char-after (1+ macro-start)) ?\")))) + (c-append-syntax 'cpp-macro) + (when (and c-syntactic-indentation-in-macros macro-start) + (if in-macro-expr + (when (or + (< syntactic-relpos macro-start) + (not (or + (assq 'arglist-intro c-syntactic-context) + (assq 'arglist-cont c-syntactic-context) + (assq 'arglist-cont-nonempty c-syntactic-context) + (assq 'arglist-close c-syntactic-context)))) + ;; If inside a cpp expression, i.e. anywhere in a + ;; cpp directive except a #define body, we only let + ;; through the syntactic analysis that is internal + ;; in the expression. That means the arglist + ;; elements, if they are anchored inside the cpp + ;; expression. + (setq c-syntactic-context nil) + (c-add-syntax 'cpp-macro-cont macro-start)) + (when (and (eq macro-start syntactic-relpos) + (not (assq 'cpp-define-intro c-syntactic-context)) + (save-excursion + (goto-char macro-start) + (or (not (c-forward-to-cpp-define-body)) + (<= (point) (c-point 'boi indent-point))))) + ;; Inside a #define body and the syntactic analysis is + ;; anchored on the start of the #define. In this case + ;; we add cpp-define-intro to get the extra + ;; indentation of the #define body. + (c-add-syntax 'cpp-define-intro))))) + ;; return the syntax + c-syntactic-context))))) + ((>= (string-to-number c-version) 5.29) + (defun c-guess-basic-syntax () + "Return the syntactic context of the current line." + (save-excursion + (save-restriction + (beginning-of-line) + (let* ((indent-point (point)) + (case-fold-search nil) + (paren-state (c-parse-state)) + literal containing-sexp char-before-ip char-after-ip lim + syntax placeholder c-in-literal-cache step-type + tmpsymbol keyword injava-inher special-brace-list + ;; narrow out any enclosing class or extern "C" block + (inclass-p (c-narrow-out-enclosing-class paren-state + indent-point)) + ;; c-state-cache is shadowed here. That means we must + ;; not do any changes during the execution of this + ;; function, since c-check-state-cache then would change + ;; this local variable and leave a bogus value in the + ;; global one. + (c-state-cache (if inclass-p + (c-whack-state-before (point-min) paren-state) + paren-state)) + (c-state-cache-start (point-min)) + inenclosing-p macro-start in-macro-expr + ;; There's always at most one syntactic element which got + ;; a relpos. It's stored in syntactic-relpos. + syntactic-relpos + (c-stmt-delim-chars c-stmt-delim-chars)) + ;; check for meta top-level enclosing constructs, possible + ;; extern language definitions, possibly (in C++) namespace + ;; definitions. + (save-excursion + (save-restriction + (widen) + (if (and inclass-p + (progn + (goto-char (aref inclass-p 0)) + (looking-at c-other-decl-block-key))) + (let ((enclosing (match-string 1))) + (cond + ((string-equal enclosing "extern") + (setq inenclosing-p 'extern)) + ((string-equal enclosing "namespace") + (setq inenclosing-p 'namespace)) + ))))) + + ;; Init some position variables: + ;; + ;; containing-sexp is the open paren of the closest + ;; surrounding sexp or nil if there is none that hasn't been + ;; narrowed out. + ;; + ;; lim is the position after the closest preceding brace sexp + ;; (nested sexps are ignored), or the position after + ;; containing-sexp if there is none, or (point-min) if + ;; containing-sexp is nil. + ;; + ;; c-state-cache is the state from c-parse-state at + ;; indent-point, without any parens outside the region + ;; narrowed by c-narrow-out-enclosing-class. + ;; + ;; paren-state is the state from c-parse-state outside + ;; containing-sexp, or at indent-point if containing-sexp is + ;; nil. paren-state is not limited to the narrowed region, as + ;; opposed to c-state-cache. + (if c-state-cache + (progn + (setq containing-sexp (car paren-state) + paren-state (cdr paren-state)) + (if (consp containing-sexp) + (progn + (setq lim (cdr containing-sexp)) + (if (cdr c-state-cache) + ;; Ignore balanced paren. The next entry + ;; can't be another one. + (setq containing-sexp (car (cdr c-state-cache)) + paren-state (cdr paren-state)) + ;; If there is no surrounding open paren then + ;; put the last balanced pair back on paren-state. + (setq paren-state (cons containing-sexp paren-state) + containing-sexp nil))) + (setq lim (1+ containing-sexp)))) + (setq lim (point-min))) + + ;; If we're in a parenthesis list then ',' delimits the + ;; "statements" rather than being an operator (with the + ;; exception of the "for" clause). This difference is + ;; typically only noticeable when statements are used in macro + ;; arglists. + (when (and containing-sexp + (eq (char-after containing-sexp) ?\()) + (setq c-stmt-delim-chars c-stmt-delim-chars-with-comma)) + + ;; cache char before and after indent point, and move point to + ;; the most likely position to perform the majority of tests + (goto-char indent-point) + (c-backward-syntactic-ws lim) + (setq char-before-ip (char-before)) + (goto-char indent-point) + (skip-chars-forward " \t") + (setq char-after-ip (char-after)) + + ;; are we in a literal? + (setq literal (c-in-literal lim)) + + ;; now figure out syntactic qualities of the current line + (cond + ;; CASE 1: in a string. + ((eq literal 'string) + (c-add-syntax 'string (c-point 'bopl))) + ;; CASE 2: in a C or C++ style comment. + ((memq literal '(c c++)) + (c-add-syntax literal (car (c-literal-limits lim)))) + ;; CASE 3: in a cpp preprocessor macro continuation. + ((and (save-excursion + (when (c-beginning-of-macro) + (setq macro-start (point)))) + (/= macro-start (c-point 'boi)) + (progn + (setq tmpsymbol 'cpp-macro-cont) + (or (not c-syntactic-indentation-in-macros) + (save-excursion + (goto-char macro-start) + ;; If at the beginning of the body of a #define + ;; directive then analyze as cpp-define-intro + ;; only. Go on with the syntactic analysis + ;; otherwise. in-macro-expr is set if we're in a + ;; cpp expression, i.e. before the #define body + ;; or anywhere in a non-#define directive. + (if (c-forward-to-cpp-define-body) + (let ((indent-boi (c-point 'boi indent-point))) + (setq in-macro-expr (> (point) indent-boi) + tmpsymbol 'cpp-define-intro) + (= (point) indent-boi)) + (setq in-macro-expr t) + nil))))) + (c-add-syntax tmpsymbol macro-start) + (setq macro-start nil)) + ;; CASE 11: an else clause? + ((looking-at "else\\>[^_]") + (c-beginning-of-statement-1 containing-sexp) + (c-add-stmt-syntax 'else-clause t containing-sexp paren-state)) + ;; CASE 12: while closure of a do/while construct? + ((and (looking-at "while\\>[^_]") + (save-excursion + (prog1 (eq (c-beginning-of-statement-1 containing-sexp) + 'beginning) + (setq placeholder (point))))) + (goto-char placeholder) + (c-add-stmt-syntax 'do-while-closure t containing-sexp paren-state)) + ;; CASE 13: A catch or finally clause? This case is simpler + ;; than if-else and do-while, because a block is required + ;; after every try, catch and finally. + ((save-excursion + (and (cond ((c-major-mode-is 'c++-mode) + (looking-at "catch\\>[^_]")) + ((c-major-mode-is 'java-mode) + (looking-at "\\(catch\\|finally\\)\\>[^_]"))) + (and (c-safe (c-backward-syntactic-ws) + (c-backward-sexp) + t) + (eq (char-after) ?{) + (c-safe (c-backward-syntactic-ws) + (c-backward-sexp) + t) + (if (eq (char-after) ?\() + (c-safe (c-backward-sexp) t) + t)) + (looking-at "\\(try\\|catch\\)\\>[^_]") + (setq placeholder (point)))) + (goto-char placeholder) + (c-add-stmt-syntax 'catch-clause t containing-sexp paren-state)) + ;; CASE 18: A substatement we can recognize by keyword. + ((save-excursion + (and c-opt-block-stmt-key + (not (eq char-before-ip ?\;)) + (not (memq char-after-ip '(?\) ?\] ?,))) + (or (not (eq char-before-ip ?})) + (c-looking-at-inexpr-block-backward c-state-cache)) + (> (point) + (progn + ;; Ought to cache the result from the + ;; c-beginning-of-statement-1 calls here. + (setq placeholder (point)) + (while (eq (setq step-type + (c-beginning-of-statement-1 lim)) + 'label)) + (if (eq step-type 'previous) + (goto-char placeholder) + (setq placeholder (point)) + (if (and (eq step-type 'same) + (not (looking-at c-opt-block-stmt-key))) + ;; Step up to the containing statement if we + ;; stayed in the same one. + (let (step) + (while (eq + (setq step + (c-beginning-of-statement-1 lim)) + 'label)) + (if (eq step 'up) + (setq placeholder (point)) + ;; There was no containing statement afterall. + (goto-char placeholder))))) + placeholder)) + (if (looking-at c-block-stmt-2-key) + ;; Require a parenthesis after these keywords. + ;; Necessary to catch e.g. synchronized in Java, + ;; which can be used both as statement and + ;; modifier. + (and (= (c-forward-token-1 1 nil) 0) + (eq (char-after) ?\()) + (looking-at c-opt-block-stmt-key)))) + (if (eq step-type 'up) + ;; CASE 18A: Simple substatement. + (progn + (goto-char placeholder) + (cond + ((eq char-after-ip ?{) + (c-add-stmt-syntax 'substatement-open nil + containing-sexp paren-state)) + ((save-excursion + (goto-char indent-point) + (back-to-indentation) + (looking-at c-label-key)) + (c-add-stmt-syntax 'substatement-label nil + containing-sexp paren-state)) + (t + (c-add-stmt-syntax 'substatement nil + containing-sexp paren-state)))) + ;; CASE 18B: Some other substatement. This is shared + ;; with case 10. + (c-guess-continued-construct indent-point + char-after-ip + placeholder + lim + paren-state))) + ;; CASE 4: In-expression statement. C.f. cases 7B, 16A and + ;; 17E. + ((and (or c-opt-inexpr-class-key + c-opt-inexpr-block-key + c-opt-lambda-key) + (setq placeholder (c-looking-at-inexpr-block + (c-safe-position containing-sexp paren-state) + containing-sexp))) + (setq tmpsymbol (assq (car placeholder) + '((inexpr-class . class-open) + (inexpr-statement . block-open)))) + (if tmpsymbol + ;; It's a statement block or an anonymous class. + (setq tmpsymbol (cdr tmpsymbol)) + ;; It's a Pike lambda. Check whether we are between the + ;; lambda keyword and the argument list or at the defun + ;; opener. + (setq tmpsymbol (if (eq char-after-ip ?{) + 'inline-open + 'lambda-intro-cont))) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-stmt-syntax tmpsymbol t + (c-most-enclosing-brace c-state-cache (point)) + (c-whack-state-after (point) paren-state)) + (unless (eq (point) (cdr placeholder)) + (c-add-syntax (car placeholder)))) + ;; CASE 5: Line is at top level. + ((null containing-sexp) + (cond + ;; CASE 5A: we are looking at a defun, brace list, class, + ;; or inline-inclass method opening brace + ((setq special-brace-list + (or (and c-special-brace-lists + (c-looking-at-special-brace-list)) + (eq char-after-ip ?{))) + (cond + ;; CASE 5A.1: extern language or namespace construct + ((save-excursion + (goto-char indent-point) + (skip-chars-forward " \t") + (and (c-safe (progn (c-backward-sexp 2) t)) + (looking-at c-other-decl-block-key) + (setq keyword (match-string 1) + placeholder (point)) + (or (and (string-equal keyword "namespace") + (setq tmpsymbol 'namespace-open)) + (and (string-equal keyword "extern") + (progn + (c-forward-sexp 1) + (c-forward-syntactic-ws) + (eq (char-after) ?\")) + (setq tmpsymbol 'extern-lang-open))) + )) + (goto-char placeholder) + (c-add-syntax tmpsymbol (c-point 'boi))) + ;; CASE 5A.2: we are looking at a class opening brace + ((save-excursion + (goto-char indent-point) + (skip-chars-forward " \t{") + (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) + (and decl + (setq placeholder (aref decl 0))) + )) + (c-add-syntax 'class-open placeholder)) + ;; CASE 5A.3: brace list open + ((save-excursion + (c-beginning-of-decl-1 lim) + (if (looking-at "typedef\\>[^_]") + (progn (c-forward-sexp 1) + (c-forward-syntactic-ws indent-point))) + (setq placeholder (c-point 'boi)) + (or (consp special-brace-list) + (and (or (save-excursion + (goto-char indent-point) + (setq tmpsymbol nil) + (while (and (> (point) placeholder) + (= (c-backward-token-1 1 t) 0) + (/= (char-after) ?=)) + (if (and (not tmpsymbol) + (looking-at "new\\>[^_]")) + (setq tmpsymbol 'topmost-intro-cont))) + (eq (char-after) ?=)) + (looking-at "enum\\>[^_]")) + (save-excursion + (while (and (< (point) indent-point) + (= (c-forward-token-1 1 t) 0) + (not (memq (char-after) '(?\; ?\())))) + (not (memq (char-after) '(?\; ?\())) + )))) + (if (and (c-major-mode-is 'java-mode) + (eq tmpsymbol 'topmost-intro-cont)) + ;; We're in Java and have found that the open brace + ;; belongs to a "new Foo[]" initialization list, + ;; which means the brace list is part of an + ;; expression and not a top level definition. We + ;; therefore treat it as any topmost continuation + ;; even though the semantically correct symbol still + ;; is brace-list-open, on the same grounds as in + ;; case 10B.2. + (progn + (c-beginning-of-statement-1 lim) + (c-add-syntax 'topmost-intro-cont (c-point 'boi))) + (c-add-syntax 'brace-list-open placeholder))) + ;; CASE 5A.4: inline defun open + ((and inclass-p (not inenclosing-p)) + (c-add-syntax 'inline-open) + (c-add-class-syntax 'inclass inclass-p paren-state)) + ;; CASE 5A.5: ordinary defun open + (t + (goto-char placeholder) + (if (or inclass-p macro-start) + (c-add-syntax 'defun-open (c-point 'boi)) + ;; Bogus to use bol here, but it's the legacy. + (c-add-syntax 'defun-open (c-point 'bol))) + ))) + ;; CASE 5B: first K&R arg decl or member init + ((c-just-after-func-arglist-p nil lim) + (cond + ;; CASE 5B.1: a member init + ((or (eq char-before-ip ?:) + (eq char-after-ip ?:)) + ;; this line should be indented relative to the beginning + ;; of indentation for the topmost-intro line that contains + ;; the prototype's open paren + ;; TBD: is the following redundant? + (if (eq char-before-ip ?:) + (forward-char -1)) + (c-backward-syntactic-ws lim) + ;; TBD: is the preceding redundant? + (if (eq (char-before) ?:) + (progn (forward-char -1) + (c-backward-syntactic-ws lim))) + (if (eq (char-before) ?\)) + (c-backward-sexp 1)) + (setq placeholder (point)) + (save-excursion + (and (c-safe (c-backward-sexp 1) t) + (looking-at "throw[^_]") + (c-safe (c-backward-sexp 1) t) + (setq placeholder (point)))) + (goto-char placeholder) + (c-add-syntax 'member-init-intro (c-point 'boi)) + ;; we don't need to add any class offset since this + ;; should be relative to the ctor's indentation + ) + ;; CASE 5B.2: K&R arg decl intro + (c-recognize-knr-p + (c-beginning-of-statement-1 lim) + (c-add-syntax 'knr-argdecl-intro (c-point 'boi)) + (if inclass-p + (c-add-class-syntax 'inclass inclass-p paren-state))) + ;; CASE 5B.3: Inside a member init list. + ((c-beginning-of-member-init-list lim) + (c-forward-syntactic-ws) + (c-add-syntax 'member-init-cont (point))) + ;; CASE 5B.4: Nether region after a C++ or Java func + ;; decl, which could include a `throws' declaration. + (t + (c-beginning-of-statement-1 lim) + (c-add-syntax 'func-decl-cont (c-point 'boi)) + ))) + ;; CASE 5C: inheritance line. could be first inheritance + ;; line, or continuation of a multiple inheritance + ((or (and (c-major-mode-is 'c++-mode) + (progn + (when (eq char-after-ip ?,) + (skip-chars-forward " \t") + (forward-char)) + (looking-at c-opt-decl-spec-key))) + (and (or (eq char-before-ip ?:) + ;; watch out for scope operator + (save-excursion + (and (eq char-after-ip ?:) + (c-safe (progn (forward-char 1) t)) + (not (eq (char-after) ?:)) + ))) + (save-excursion + (c-backward-syntactic-ws lim) + (if (eq char-before-ip ?:) + (progn + (forward-char -1) + (c-backward-syntactic-ws lim))) + (back-to-indentation) + (looking-at c-class-key))) + ;; for Java + (and (c-major-mode-is 'java-mode) + (let ((fence (save-excursion + (c-beginning-of-statement-1 lim) + (point))) + cont done) + (save-excursion + (while (not done) + (cond ((looking-at c-opt-decl-spec-key) + (setq injava-inher (cons cont (point)) + done t)) + ((or (not (c-safe (c-forward-sexp -1) t)) + (<= (point) fence)) + (setq done t)) + ) + (setq cont t))) + injava-inher) + (not (c-crosses-statement-barrier-p (cdr injava-inher) + (point))) + )) + (cond + ;; CASE 5C.1: non-hanging colon on an inher intro + ((eq char-after-ip ?:) + (c-beginning-of-statement-1 lim) + (c-add-syntax 'inher-intro (c-point 'boi)) + ;; don't add inclass symbol since relative point already + ;; contains any class offset + ) + ;; CASE 5C.2: hanging colon on an inher intro + ((eq char-before-ip ?:) + (c-beginning-of-statement-1 lim) + (c-add-syntax 'inher-intro (c-point 'boi)) + (if inclass-p + (c-add-class-syntax 'inclass inclass-p paren-state))) + ;; KDE Hack Start: + ((and inclass-p + c-access-key + (looking-at c-access-key)) + (c-add-syntax 'access-label (c-point 'bonl)) + (setq placeholder (c-add-class-syntax 'inclass inclass-p + paren-state))) + ;;(nconc syntax (list (cons 'access-label placeholder)))) + ;; KDE Hack End. + ;; CASE 5C.3: in a Java implements/extends + (injava-inher + (let ((where (cdr injava-inher)) + (cont (car injava-inher))) + (goto-char where) + (cond ((looking-at "throws\\>[^_]") + (c-add-syntax 'func-decl-cont + (progn (c-beginning-of-statement-1 lim) + (c-point 'boi)))) + (cont (c-add-syntax 'inher-cont where)) + (t (c-add-syntax 'inher-intro + (progn (goto-char (cdr injava-inher)) + (c-beginning-of-statement-1 lim) + (point)))) + ))) + ;; CASE 5C.4: a continued inheritance line + (t + (c-beginning-of-inheritance-list lim) + (c-add-syntax 'inher-cont (point)) + ;; don't add inclass symbol since relative point already + ;; contains any class offset + ))) + ;; CASE 5D: this could be a top-level initialization, a + ;; member init list continuation, or a template argument + ;; list continuation. + ((c-with-syntax-table (if (c-major-mode-is 'c++-mode) + c++-template-syntax-table + (syntax-table)) + (save-excursion + ;; Note: We use the fact that lim is always after any + ;; preceding brace sexp. + (while (and (= (c-backward-token-1 1 t lim) 0) + (not (looking-at "[;<,=]")))) + (or (memq (char-after) '(?, ?=)) + (and (c-major-mode-is 'c++-mode) + (= (c-backward-token-1 1 nil lim) 0) + (eq (char-after) ?<))))) + (goto-char indent-point) + (c-beginning-of-member-init-list lim) + (cond + ;; CASE 5D.1: hanging member init colon, but watch out + ;; for bogus matches on access specifiers inside classes. + ((and (save-excursion + (setq placeholder (point)) + (c-backward-token-1 1 t lim) + (and (eq (char-after) ?:) + (not (eq (char-before) ?:)))) + (save-excursion + (goto-char placeholder) + (back-to-indentation) + (or + (/= (car (save-excursion + (parse-partial-sexp (point) placeholder))) + 0) + (and + (if c-opt-access-key + (not (looking-at c-opt-access-key)) t) + (not (looking-at c-class-key)) + (if c-opt-bitfield-key + (not (looking-at c-opt-bitfield-key)) t)) + ))) + (goto-char placeholder) + (c-forward-syntactic-ws) + (c-add-syntax 'member-init-cont (point)) + ;; we do not need to add class offset since relative + ;; point is the member init above us + ) + ;; CASE 5D.2: non-hanging member init colon + ((progn + (c-forward-syntactic-ws indent-point) + (eq (char-after) ?:)) + (skip-chars-forward " \t:") + (c-add-syntax 'member-init-cont (point))) + ;; CASE 5D.3: perhaps a template list continuation? + ((and (c-major-mode-is 'c++-mode) + (save-excursion + (save-restriction + (c-with-syntax-table c++-template-syntax-table + (goto-char indent-point) + (setq placeholder (c-up-list-backward (point))) + (and placeholder + (eq (char-after placeholder) ?<)))))) + ;; we can probably indent it just like an arglist-cont + (goto-char placeholder) + (c-beginning-of-statement-1 lim t) + (c-add-syntax 'template-args-cont (c-point 'boi))) + ;; CASE 5D.4: perhaps a multiple inheritance line? + ((and (c-major-mode-is 'c++-mode) + (save-excursion + (c-beginning-of-statement-1 lim) + (setq placeholder (point)) + (if (looking-at "static\\>[^_]") + (c-forward-token-1 1 nil indent-point)) + (and (looking-at c-class-key) + (= (c-forward-token-1 2 nil indent-point) 0) + (if (eq (char-after) ?<) + (c-with-syntax-table c++-template-syntax-table + (= (c-forward-token-1 1 t indent-point) 0)) + t) + (eq (char-after) ?:)))) + (goto-char placeholder) + (c-add-syntax 'inher-cont (c-point 'boi))) + ;; CASE 5D.5: Continuation of the "expression part" of a + ;; top level construct. + (t + (while (and (eq (car (c-beginning-of-decl-1 containing-sexp)) + 'same) + (save-excursion + (c-backward-syntactic-ws) + (eq (char-before) ?})))) + (c-add-stmt-syntax + (if (eq char-before-ip ?,) + ;; A preceding comma at the top level means that a + ;; new variable declaration starts here. Use + ;; topmost-intro-cont for it, for consistency with + ;; the first variable declaration. C.f. case 5N. + 'topmost-intro-cont + 'statement-cont) + nil containing-sexp paren-state)) + )) + ;; CASE 5E: we are looking at a access specifier + ((and inclass-p + c-opt-access-key + (looking-at c-opt-access-key)) + (setq placeholder (c-add-class-syntax 'inclass inclass-p + paren-state)) + ;; Append access-label with the same anchor point as inclass gets. + (nconc syntax (list (cons 'access-label placeholder)))) + ;; CASE 5F: extern-lang-close or namespace-close? + ((and inenclosing-p + (eq char-after-ip ?})) + (setq tmpsymbol (if (eq inenclosing-p 'extern) + 'extern-lang-close + 'namespace-close)) + (c-add-syntax tmpsymbol (aref inclass-p 0))) + ;; CASE 5G: we are looking at the brace which closes the + ;; enclosing nested class decl + ((and inclass-p + (eq char-after-ip ?}) + (save-excursion + (save-restriction + (widen) + (forward-char 1) + (and (c-safe (progn (c-backward-sexp 1) t)) + (= (point) (aref inclass-p 1)) + )))) + (c-add-class-syntax 'class-close inclass-p paren-state)) + ;; CASE 5H: we could be looking at subsequent knr-argdecls + ((and c-recognize-knr-p + (not (eq char-before-ip ?})) + (save-excursion + (setq placeholder (cdr (c-beginning-of-decl-1 lim))) + (and placeholder + ;; Do an extra check to avoid tripping up on + ;; statements that occur in invalid contexts + ;; (e.g. in macro bodies where we don't really + ;; know the context of what we're looking at). + (not (and c-opt-block-stmt-key + (looking-at c-opt-block-stmt-key))))) + (< placeholder indent-point)) + (goto-char placeholder) + (c-add-syntax 'knr-argdecl (point))) + ;; CASE 5I: ObjC method definition. + ((and c-opt-method-key + (looking-at c-opt-method-key)) + (c-beginning-of-statement-1 lim) + (c-add-syntax 'objc-method-intro (c-point 'boi))) + ;; CASE 5N: At a variable declaration that follows a class + ;; definition or some other block declaration that doesn't + ;; end at the closing '}'. C.f. case 5D.5. + ((progn + (c-backward-syntactic-ws lim) + (and (eq (char-before) ?}) + (save-excursion + (let ((start (point))) + (if paren-state + ;; Speed up the backward search a bit. + (goto-char (car (car paren-state)))) + (c-beginning-of-decl-1 containing-sexp) + (setq placeholder (point)) + (if (= start (point)) + ;; The '}' is unbalanced. + nil + (c-end-of-decl-1) + (> (point) indent-point)))))) + (goto-char placeholder) + (c-add-stmt-syntax 'topmost-intro-cont nil + containing-sexp paren-state)) + ;; CASE 5J: we are at the topmost level, make + ;; sure we skip back past any access specifiers + ((progn + (while (and inclass-p + c-opt-access-key + (not (bobp)) + (save-excursion + (c-safe (progn (c-backward-sexp 1) t)) + (and (looking-at "slots:") + (c-backward-sexp 1)) + (looking-at c-opt-access-key))) + (c-backward-sexp 1) + (c-backward-syntactic-ws lim)) + (or (bobp) + (memq (char-before) '(?\; ?})) + (and (c-major-mode-is 'objc-mode) + (progn + (c-beginning-of-statement-1 lim) + (eq (char-after) ?@))))) + ;; real beginning-of-line could be narrowed out due to + ;; enclosure in a class block + (save-restriction + (widen) + (c-add-syntax 'topmost-intro (c-point 'bol)) + ;; Using bol instead of boi above is highly bogus, and + ;; it makes our lives hard to remain compatible. :P + (if inclass-p + (progn + (goto-char (aref inclass-p 1)) + (or (= (point) (c-point 'boi)) + (goto-char (aref inclass-p 0))) + (cond + ((eq inenclosing-p 'extern) + (c-add-syntax 'inextern-lang (c-point 'boi))) + ((eq inenclosing-p 'namespace) + (c-add-syntax 'innamespace (c-point 'boi))) + (t (c-add-class-syntax 'inclass inclass-p paren-state))) + )) + (when (and c-syntactic-indentation-in-macros + macro-start + (/= macro-start (c-point 'boi indent-point))) + (c-add-syntax 'cpp-define-intro) + (setq macro-start nil)) + )) + ;; CASE 5K: we are at an ObjC method definition + ;; continuation line. + ((and c-opt-method-key + (progn + (c-beginning-of-statement-1 lim) + (beginning-of-line) + (looking-at c-opt-method-key))) + (c-add-syntax 'objc-method-args-cont (point))) + ;; CASE 5L: we are at the first argument of a template + ;; arglist that begins on the previous line. + ((eq (char-before) ?<) + (c-beginning-of-statement-1 (c-safe-position (point) paren-state)) + (c-add-syntax 'template-args-cont (c-point 'boi))) + ;; CASE 5M: we are at a topmost continuation line + ;; KDE Hack 2 + ;; NOTE: is there a way to detect these sooner ? + (t + (c-beginning-of-statement-1 (c-safe-position (point) paren-state)) + (if (re-search-forward c-access-key (point-at-eol) t) + (progn + (c-add-syntax 'topmost-intro (c-point 'bol)) + (c-add-class-syntax 'inclass inclass-p paren-state) + ) + (progn + (c-add-syntax 'topmost-intro-cont (c-point 'boi)) + )) + ) + )) + ;; (CASE 6 has been removed.) + ;; CASE 7: line is an expression, not a statement. Most + ;; likely we are either in a function prototype or a function + ;; call argument list + ((not (or (and c-special-brace-lists + (save-excursion + (goto-char containing-sexp) + (c-looking-at-special-brace-list))) + (eq (char-after containing-sexp) ?{))) + (cond + ;; CASE 7A: we are looking at the arglist closing paren + ((memq char-after-ip '(?\) ?\])) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (when (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (forward-char) + (skip-chars-forward " \t") + (setq placeholder (point))) + (c-add-syntax 'arglist-close placeholder)) + ;; CASE 7B: Looking at the opening brace of an + ;; in-expression block or brace list. C.f. cases 4, 16A + ;; and 17E. + ((and (eq char-after-ip ?{) + (progn + (setq placeholder (c-inside-bracelist-p (point) + c-state-cache)) + (if placeholder + (setq tmpsymbol '(brace-list-open . inexpr-class)) + (setq tmpsymbol '(block-open . inexpr-statement) + placeholder + (cdr-safe (c-looking-at-inexpr-block + (c-safe-position containing-sexp + paren-state) + containing-sexp))) + ;; placeholder is nil if it's a block directly in + ;; a function arglist. That makes us skip out of + ;; this case. + ))) + (goto-char placeholder) + (back-to-indentation) + (c-add-stmt-syntax (car tmpsymbol) t + (c-most-enclosing-brace paren-state (point)) + (c-whack-state-after (point) paren-state)) + (if (/= (point) placeholder) + (c-add-syntax (cdr tmpsymbol)))) + ;; CASE 7C: we are looking at the first argument in an empty + ;; argument list. Use arglist-close if we're actually + ;; looking at a close paren or bracket. + ((memq char-before-ip '(?\( ?\[)) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (when (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (forward-char) + (skip-chars-forward " \t") + (setq placeholder (point))) + (c-add-syntax 'arglist-intro placeholder)) + ;; CASE 7D: we are inside a conditional test clause. treat + ;; these things as statements + ((progn + (goto-char containing-sexp) + (and (c-safe (progn (c-forward-sexp -1) t)) + (looking-at "\\<for\\>[^_]"))) + (goto-char (1+ containing-sexp)) + (c-forward-syntactic-ws indent-point) + (if (eq char-before-ip ?\;) + (c-add-syntax 'statement (point)) + (c-add-syntax 'statement-cont (point)) + )) + ;; CASE 7E: maybe a continued ObjC method call. This is the + ;; case when we are inside a [] bracketed exp, and what + ;; precede the opening bracket is not an identifier. + ((and c-opt-method-key + (eq (char-after containing-sexp) ?\[) + (progn + (goto-char (1- containing-sexp)) + (c-backward-syntactic-ws (c-point 'bod)) + (if (not (looking-at c-symbol-key)) + (c-add-syntax 'objc-method-call-cont containing-sexp)) + ))) + ;; CASE 7F: we are looking at an arglist continuation line, + ;; but the preceding argument is on the same line as the + ;; opening paren. This case includes multi-line + ;; mathematical paren groupings, but we could be on a + ;; for-list continuation line + ((progn + (goto-char (1+ containing-sexp)) + (skip-chars-forward " \t") + (and (not (eolp)) + (not (looking-at "\\\\$")))) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (when (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (forward-char) + (skip-chars-forward " \t") + (setq placeholder (point))) + (c-add-syntax 'arglist-cont-nonempty placeholder)) + ;; CASE 7G: we are looking at just a normal arglist + ;; continuation line + (t (c-forward-syntactic-ws indent-point) + (c-add-syntax 'arglist-cont (c-point 'boi))) + )) + ;; CASE 8: func-local multi-inheritance line + ((and (c-major-mode-is 'c++-mode) + (save-excursion + (goto-char indent-point) + (skip-chars-forward " \t") + (looking-at c-opt-decl-spec-key))) + (goto-char indent-point) + (skip-chars-forward " \t") + (cond + ;; CASE 8A: non-hanging colon on an inher intro + ((eq char-after-ip ?:) + (c-backward-syntactic-ws lim) + (c-add-syntax 'inher-intro (c-point 'boi))) + ;; CASE 8B: hanging colon on an inher intro + ((eq char-before-ip ?:) + (c-add-syntax 'inher-intro (c-point 'boi))) + ;; CASE 8C: a continued inheritance line + (t + (c-beginning-of-inheritance-list lim) + (c-add-syntax 'inher-cont (point)) + ))) + ;; CASE 9: we are inside a brace-list + ((setq special-brace-list + (or (and c-special-brace-lists + (save-excursion + (goto-char containing-sexp) + (c-looking-at-special-brace-list))) + (c-inside-bracelist-p containing-sexp paren-state))) + (cond + ;; CASE 9A: In the middle of a special brace list opener. + ((and (consp special-brace-list) + (save-excursion + (goto-char containing-sexp) + (eq (char-after) ?\()) + (eq char-after-ip (car (cdr special-brace-list)))) + (goto-char (car (car special-brace-list))) + (skip-chars-backward " \t") + (if (and (bolp) + (assoc 'statement-cont + (setq placeholder (c-guess-basic-syntax)))) + (setq syntax placeholder) + (c-beginning-of-statement-1 + (c-safe-position (1- containing-sexp) paren-state)) + (c-forward-token-1 0) + (if (looking-at "typedef\\>[^_]") (c-forward-token-1 1)) + (c-add-syntax 'brace-list-open (c-point 'boi)))) + ;; CASE 9B: brace-list-close brace + ((if (consp special-brace-list) + ;; Check special brace list closer. + (progn + (goto-char (car (car special-brace-list))) + (save-excursion + (goto-char indent-point) + (back-to-indentation) + (or + ;; We were between the special close char and the `)'. + (and (eq (char-after) ?\)) + (eq (1+ (point)) (cdr (car special-brace-list)))) + ;; We were before the special close char. + (and (eq (char-after) (cdr (cdr special-brace-list))) + (= (c-forward-token-1) 0) + (eq (1+ (point)) (cdr (car special-brace-list))))))) + ;; Normal brace list check. + (and (eq char-after-ip ?}) + (c-safe (progn (goto-char (c-up-list-backward (point))) + t)) + (= (point) containing-sexp))) + (if (eq (point) (c-point 'boi)) + (c-add-syntax 'brace-list-close (point)) + (setq lim (c-most-enclosing-brace c-state-cache (point))) + (c-beginning-of-statement-1 lim) + (c-add-stmt-syntax 'brace-list-close t lim + (c-whack-state-after (point) paren-state) + t))) + (t + ;; Prepare for the rest of the cases below by going to the + ;; token following the opening brace + (if (consp special-brace-list) + (progn + (goto-char (car (car special-brace-list))) + (c-forward-token-1 1 nil indent-point)) + (goto-char containing-sexp)) + (forward-char) + (let ((start (point))) + (c-forward-syntactic-ws indent-point) + (goto-char (max start (c-point 'bol)))) + (c-skip-ws-forward indent-point) + (cond + ;; CASE 9C: we're looking at the first line in a brace-list + ((= (point) indent-point) + (if (consp special-brace-list) + (goto-char (car (car special-brace-list))) + (goto-char containing-sexp)) + (if (eq (point) (c-point 'boi)) + (c-add-syntax 'brace-list-intro (point)) + (setq lim (c-most-enclosing-brace c-state-cache (point))) + (c-beginning-of-statement-1 lim) + (c-add-stmt-syntax 'brace-list-intro t lim + (c-whack-state-after (point) paren-state) + t))) + ;; CASE 9D: this is just a later brace-list-entry or + ;; brace-entry-open + (t (if (or (eq char-after-ip ?{) + (and c-special-brace-lists + (save-excursion + (goto-char indent-point) + (c-forward-syntactic-ws (c-point 'eol)) + (c-looking-at-special-brace-list (point))))) + (c-add-syntax 'brace-entry-open (point)) + (c-add-syntax 'brace-list-entry (point)) + )) + )))) + ;; CASE 10: A continued statement or top level construct. + ((and (not (memq char-before-ip '(?\; ?:))) + (or (not (eq char-before-ip ?})) + (c-looking-at-inexpr-block-backward c-state-cache)) + (> (point) + (save-excursion + (c-beginning-of-statement-1 containing-sexp) + (setq placeholder (point)))) + (/= placeholder containing-sexp)) + ;; This is shared with case 18. + (c-guess-continued-construct indent-point + char-after-ip + placeholder + containing-sexp + paren-state)) + ;; CASE 14: A case or default label + ((looking-at c-label-kwds-regexp) + (goto-char containing-sexp) + (setq lim (c-most-enclosing-brace c-state-cache containing-sexp)) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax 'case-label t lim paren-state)) + ;; CASE 15: any other label + ((looking-at c-label-key) + (goto-char containing-sexp) + (setq lim (c-most-enclosing-brace c-state-cache containing-sexp)) + (save-excursion + (setq tmpsymbol + (if (and (eq (c-beginning-of-statement-1 lim) 'up) + (looking-at "switch\\>[^_]")) + ;; If the surrounding statement is a switch then + ;; let's analyze all labels as switch labels, so + ;; that they get lined up consistently. + 'case-label + 'label))) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax tmpsymbol t lim paren-state)) + ;; CASE 16: block close brace, possibly closing the defun or + ;; the class + ((eq char-after-ip ?}) + ;; From here on we have the next containing sexp in lim. + (setq lim (c-most-enclosing-brace paren-state)) + (goto-char containing-sexp) + (cond + ;; CASE 16E: Closing a statement block? This catches + ;; cases where it's preceded by a statement keyword, + ;; which works even when used in an "invalid" context, + ;; e.g. a macro argument. + ((c-after-conditional) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax 'block-close t lim paren-state)) + ;; CASE 16A: closing a lambda defun or an in-expression + ;; block? C.f. cases 4, 7B and 17E. + ((setq placeholder (c-looking-at-inexpr-block + (c-safe-position containing-sexp paren-state) + nil)) + (setq tmpsymbol (if (eq (car placeholder) 'inlambda) + 'inline-close + 'block-close)) + (goto-char containing-sexp) + (back-to-indentation) + (if (= containing-sexp (point)) + (c-add-syntax tmpsymbol (point)) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-stmt-syntax tmpsymbol t + (c-most-enclosing-brace paren-state (point)) + (c-whack-state-after (point) paren-state)) + (if (/= (point) (cdr placeholder)) + (c-add-syntax (car placeholder))))) + ;; CASE 16B: does this close an inline or a function in + ;; an extern block or namespace? + ((setq placeholder (c-search-uplist-for-classkey paren-state)) + (c-backward-to-decl-anchor lim) + (back-to-indentation) + (if (save-excursion + (goto-char (aref placeholder 0)) + (looking-at c-other-decl-block-key)) + (c-add-syntax 'defun-close (point)) + (c-add-syntax 'inline-close (point)))) + ;; CASE 16F: Can be a defun-close of a function declared + ;; in a statement block, e.g. in Pike or when using gcc + ;; extensions. Might also trigger it with some macros + ;; followed by blocks, and this gives sane indentation + ;; then too. Let it through to be handled below. + ;; C.f. cases B.3 and 17G. + ((and (not inenclosing-p) + lim + (save-excursion + (and (not (c-looking-at-bos)) + (eq (c-beginning-of-statement-1 lim nil nil t) 'same) + (setq placeholder (point))))) + (back-to-indentation) + (if (/= (point) containing-sexp) + (goto-char placeholder)) + (c-add-stmt-syntax 'defun-close t lim paren-state)) + ;; CASE 16C: if there an enclosing brace that hasn't + ;; been narrowed out by a class, then this is a + ;; block-close. C.f. case 17H. + ((and (not inenclosing-p) lim) + ;; If the block is preceded by a case/switch label on + ;; the same line, we anchor at the first preceding label + ;; at boi. The default handling in c-add-stmt-syntax is + ;; really fixes it better, but we do like this to keep + ;; the indentation compatible with version 5.28 and + ;; earlier. + (while (and (/= (setq placeholder (point)) (c-point 'boi)) + (eq (c-beginning-of-statement-1 lim) 'label))) + (goto-char placeholder) + (if (looking-at c-label-kwds-regexp) + (c-add-syntax 'block-close (point)) + (goto-char containing-sexp) + ;; c-backward-to-block-anchor not necessary here; those + ;; situations are handled in case 16E above. + (c-add-stmt-syntax 'block-close t lim paren-state))) + ;; CASE 16D: find out whether we're closing a top-level + ;; class or a defun + (t + (save-restriction + (narrow-to-region (point-min) indent-point) + (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) + (if decl + (c-add-class-syntax 'class-close decl paren-state) + (goto-char containing-sexp) + (c-backward-to-decl-anchor lim) + (back-to-indentation) + (c-add-syntax 'defun-close (point))))) + ))) + ;; CASE 17: Statement or defun catchall. + (t + (goto-char indent-point) + ;; Back up statements until we find one that starts at boi. + (while (let* ((prev-point (point)) + (last-step-type (c-beginning-of-statement-1 + containing-sexp))) + (if (= (point) prev-point) + (progn + (setq step-type (or step-type last-step-type)) + nil) + (setq step-type last-step-type) + (/= (point) (c-point 'boi))))) + (cond + ;; CASE 17B: continued statement + ((and (eq step-type 'same) + (/= (point) indent-point)) + (c-add-stmt-syntax 'statement-cont nil + containing-sexp paren-state)) + ;; CASE 17A: After a case/default label? + ((progn + (while (and (eq step-type 'label) + (not (looking-at c-label-kwds-regexp))) + (setq step-type + (c-beginning-of-statement-1 containing-sexp))) + (eq step-type 'label)) + (c-add-stmt-syntax (if (eq char-after-ip ?{) + 'statement-case-open + 'statement-case-intro) + t containing-sexp paren-state)) + ;; CASE 17D: any old statement + ((progn + (while (eq step-type 'label) + (setq step-type + (c-beginning-of-statement-1 containing-sexp))) + (eq step-type 'previous)) + (c-add-stmt-syntax 'statement t containing-sexp paren-state) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + ;; CASE 17I: Inside a substatement block. + ((progn + ;; The following tests are all based on containing-sexp. + (goto-char containing-sexp) + ;; From here on we have the next containing sexp in lim. + (setq lim (c-most-enclosing-brace paren-state containing-sexp)) + (c-after-conditional)) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax 'statement-block-intro t lim paren-state) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + ;; CASE 17E: first statement in an in-expression block. + ;; C.f. cases 4, 7B and 16A. + ((setq placeholder (c-looking-at-inexpr-block + (c-safe-position containing-sexp paren-state) + nil)) + (setq tmpsymbol (if (eq (car placeholder) 'inlambda) + 'defun-block-intro + 'statement-block-intro)) + (back-to-indentation) + (if (= containing-sexp (point)) + (c-add-syntax tmpsymbol (point)) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-stmt-syntax tmpsymbol t + (c-most-enclosing-brace c-state-cache (point)) + (c-whack-state-after (point) paren-state)) + (if (/= (point) (cdr placeholder)) + (c-add-syntax (car placeholder)))) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + ;; CASE 17F: first statement in an inline, or first + ;; statement in a top-level defun. we can tell this is it + ;; if there are no enclosing braces that haven't been + ;; narrowed out by a class (i.e. don't use bod here). + ;; However, we first check for statements that we can + ;; recognize by keywords. That increases the robustness in + ;; cases where statements are used on the top level, + ;; e.g. in macro definitions. + ((save-excursion + (save-restriction + (widen) + (c-narrow-out-enclosing-class paren-state containing-sexp) + (not (c-most-enclosing-brace paren-state)))) + (c-backward-to-decl-anchor lim) + (back-to-indentation) + (c-add-syntax 'defun-block-intro (point))) + ;; CASE 17G: First statement in a function declared inside + ;; a normal block. This can occur in Pike and with + ;; e.g. the gcc extensions. Might also trigger it with + ;; some macros followed by blocks, and this gives sane + ;; indentation then too. C.f. cases B.3 and 16F. + ((save-excursion + (and (not (c-looking-at-bos)) + (eq (c-beginning-of-statement-1 lim nil nil t) 'same) + (setq placeholder (point)))) + (back-to-indentation) + (if (/= (point) containing-sexp) + (goto-char placeholder)) + (c-add-stmt-syntax 'defun-block-intro t lim paren-state)) + ;; CASE 17H: First statement in a block. C.f. case 16C. + (t + ;; If the block is preceded by a case/switch label on the + ;; same line, we anchor at the first preceding label at + ;; boi. The default handling in c-add-stmt-syntax is + ;; really fixes it better, but we do like this to keep the + ;; indentation compatible with version 5.28 and earlier. + (while (and (/= (setq placeholder (point)) (c-point 'boi)) + (eq (c-beginning-of-statement-1 lim) 'label))) + (goto-char placeholder) + (if (looking-at c-label-kwds-regexp) + (c-add-syntax 'statement-block-intro (point)) + (goto-char containing-sexp) + ;; c-backward-to-block-anchor not necessary here; those + ;; situations are handled in case 17I above. + (c-add-stmt-syntax 'statement-block-intro t lim paren-state)) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + )) + ) + ;; now we need to look at any modifiers + (goto-char indent-point) + (skip-chars-forward " \t") + ;; are we looking at a comment only line? + (when (and (looking-at c-comment-start-regexp) + (/= (c-forward-token-1 0 nil (c-point 'eol)) 0)) + (c-add-syntax 'comment-intro)) + ;; we might want to give additional offset to friends (in C++). + (when (and c-opt-friend-key + (looking-at c-opt-friend-key)) + (c-add-syntax 'friend)) + ;; Start of or a continuation of a preprocessor directive? + (if (and macro-start + (eq macro-start (c-point 'boi)) + (not (and (c-major-mode-is 'pike-mode) + (eq (char-after (1+ macro-start)) ?\")))) + (c-add-syntax 'cpp-macro) + (when (and c-syntactic-indentation-in-macros macro-start) + (if in-macro-expr + (when (or (< syntactic-relpos macro-start) + (not (or (assq 'arglist-intro syntax) + (assq 'arglist-cont syntax) + (assq 'arglist-cont-nonempty syntax) + (assq 'arglist-close syntax)))) + ;; If inside a cpp expression, i.e. anywhere in a + ;; cpp directive except a #define body, we only let + ;; through the syntactic analysis that is internal + ;; in the expression. That means the arglist + ;; elements, if they are anchored inside the cpp + ;; expression. + (setq syntax `((cpp-macro-cont . ,macro-start)))) + (when (and (eq macro-start syntactic-relpos) + (not (assq 'cpp-define-intro syntax)) + (save-excursion + (goto-char macro-start) + (or (not (c-forward-to-cpp-define-body)) + (<= (point) (c-point 'boi indent-point))))) + ;; Inside a #define body and the syntactic analysis is + ;; anchored on the start of the #define. In this case + ;; we add cpp-define-intro to get the extra + ;; indentation of the #define body. + (c-add-syntax 'cpp-define-intro))))) + ;; return the syntax + syntax))))) + ((defun c-guess-basic-syntax () + (save-excursion + (save-restriction + (beginning-of-line) + (let* ((indent-point (point)) + (case-fold-search nil) + (fullstate (c-parse-state)) + (state fullstate) + literal containing-sexp char-before-ip char-after-ip lim + syntax placeholder c-in-literal-cache inswitch-p + tmpsymbol keyword injava-inher special-brace-list + ;; narrow out any enclosing class or extern "C" block + (inclass-p (c-narrow-out-enclosing-class state indent-point)) + inenclosing-p) + ;; check for meta top-level enclosing constructs, possible + ;; extern language definitions, possibly (in C++) namespace + ;; definitions. + (save-excursion + (save-restriction + (widen) + (if (and inclass-p + (progn + (goto-char (aref inclass-p 0)) + (looking-at (concat c-extra-toplevel-key "[^_]")))) + (let ((enclosing (match-string 1))) + (cond + ((string-equal enclosing "extern") + (setq inenclosing-p 'extern)) + ((string-equal enclosing "namespace") + (setq inenclosing-p 'namespace)) + ))))) + ;; get the buffer position of the most nested opening brace, + ;; if there is one, and it hasn't been narrowed out + (save-excursion + (goto-char indent-point) + (skip-chars-forward " \t}") + (skip-chars-backward " \t") + (while (and state + (not containing-sexp)) + (setq containing-sexp (car state) + state (cdr state)) + (if (consp containing-sexp) + ;; if cdr == point, then containing sexp is the brace + ;; that opens the sexp we close + (if (= (cdr containing-sexp) (point)) + (setq containing-sexp (car containing-sexp)) + ;; otherwise, ignore this element + (setq containing-sexp nil)) + ;; ignore the bufpos if its been narrowed out by the + ;; containing class or does not contain the indent point + (if (or (<= containing-sexp (point-min)) + (>= containing-sexp indent-point)) + (setq containing-sexp nil))))) + ;; (imenu "agulbra-c++-tab") + ;; set the limit on the farthest back we need to search + (setq lim (or containing-sexp + (if (consp (car fullstate)) + (cdr (car fullstate)) + nil) + (point-min))) + + ;; cache char before and after indent point, and move point to + ;; the most likely position to perform the majority of tests + (goto-char indent-point) + (skip-chars-forward " \t") + (setq char-after-ip (char-after)) + (c-backward-syntactic-ws lim) + (setq char-before-ip (char-before)) + (goto-char indent-point) + (skip-chars-forward " \t") + + ;; are we in a literal? + (setq literal (c-in-literal lim)) + + ;; now figure out syntactic qualities of the current line + (cond + ;; CASE 1: in a string. + ((memq literal '(string)) + (c-add-syntax 'string (c-point 'bopl))) + ;; CASE 2: in a C or C++ style comment. + ((memq literal '(c c++)) + (c-add-syntax literal (car (c-literal-limits lim)))) + ;; CASE 3: in a cpp preprocessor macro continuation. + ((and (eq literal 'pound) + (/= (save-excursion + (c-beginning-of-macro lim) + (setq placeholder (point))) + (c-point 'boi))) + (c-add-syntax 'cpp-macro-cont placeholder)) + ;; CASE 4: In-expression statement. + ((and (or c-inexpr-class-key c-inexpr-block-key c-lambda-key) + (setq placeholder (c-looking-at-inexpr-block))) + (setq tmpsymbol (assq (car placeholder) + '((inexpr-class . class-open) + (inexpr-statement . block-open)))) + (if tmpsymbol + ;; It's a statement block or an anonymous class. + (setq tmpsymbol (cdr tmpsymbol)) + ;; It's a Pike lambda. Check whether we are between the + ;; lambda keyword and the argument list or at the defun + ;; opener. + (setq tmpsymbol (if (eq char-after-ip ?{) + 'inline-open + 'lambda-intro-cont))) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-syntax tmpsymbol (point)) + (unless (eq (point) (cdr placeholder)) + (c-add-syntax (car placeholder)))) + ;; CASE 5: Line is at top level. + ((null containing-sexp) + (cond + ;; CASE 5A: we are looking at a defun, brace list, class, + ;; or inline-inclass method opening brace + ((setq special-brace-list + (or (and c-special-brace-lists + (c-looking-at-special-brace-list)) + (eq char-after-ip ?{))) + (cond + ;; CASE 5A.1: extern language or namespace construct + ((save-excursion + (goto-char indent-point) + (skip-chars-forward " \t") + (and (c-safe (progn (c-backward-sexp 2) t)) + (looking-at (concat c-extra-toplevel-key "[^_]")) + (setq keyword (match-string 1) + placeholder (point)) + (or (and (string-equal keyword "namespace") + (setq tmpsymbol 'namespace-open)) + (and (string-equal keyword "extern") + (progn + (c-forward-sexp 1) + (c-forward-syntactic-ws) + (eq (char-after) ?\")) + (setq tmpsymbol 'extern-lang-open))) + )) + (goto-char placeholder) + (c-add-syntax tmpsymbol (c-point 'boi))) + ;; CASE 5A.2: we are looking at a class opening brace + ((save-excursion + (goto-char indent-point) + (skip-chars-forward " \t{") + ;; TBD: watch out! there could be a bogus + ;; c-state-cache in place when we get here. we have + ;; to go through much chicanery to ignore the cache. + ;; But of course, there may not be! BLECH! BOGUS! + (let ((decl + (let ((c-state-cache nil)) + (c-search-uplist-for-classkey (c-parse-state)) + ))) + (and decl + (setq placeholder (aref decl 0))) + )) + (c-add-syntax 'class-open placeholder)) + ;; CASE 5A.3: brace list open + ((save-excursion + (c-beginning-of-statement-1 lim) + ;; c-b-o-s could have left us at point-min + (and (bobp) + (c-forward-syntactic-ws indent-point)) + (if (looking-at "typedef[^_]") + (progn (c-forward-sexp 1) + (c-forward-syntactic-ws indent-point))) + (setq placeholder (c-point 'boi)) + (or (consp special-brace-list) + (and (or (save-excursion + (goto-char indent-point) + (setq tmpsymbol nil) + (while (and (> (point) placeholder) + (= (c-backward-token-1 1 t) 0) + (/= (char-after) ?=)) + (if (and (not tmpsymbol) + (looking-at "new\\>[^_]")) + (setq tmpsymbol 'topmost-intro-cont))) + (eq (char-after) ?=)) + (looking-at "enum[ \t\n]+")) + (save-excursion + (while (and (< (point) indent-point) + (= (c-forward-token-1 1 t) 0) + (not (memq (char-after) '(?\; ?\())))) + (not (memq (char-after) '(?\; ?\())) + )))) + (if (and (c-major-mode-is 'java-mode) + (eq tmpsymbol 'topmost-intro-cont)) + ;; We're in Java and have found that the open brace + ;; belongs to a "new Foo[]" initialization list, + ;; which means the brace list is part of an + ;; expression and not a top level definition. We + ;; therefore treat it as any topmost continuation + ;; even though the semantically correct symbol still + ;; is brace-list-open, on the same grounds as in + ;; case 10B.2. + (progn + (c-beginning-of-statement-1 lim) + (c-forward-syntactic-ws) + (c-add-syntax 'topmost-intro-cont (c-point 'boi))) + (c-add-syntax 'brace-list-open placeholder))) + ;; CASE 5A.4: inline defun open + ((and inclass-p (not inenclosing-p)) + (c-add-syntax 'inline-open) + (c-add-class-syntax 'inclass inclass-p)) + ;; CASE 5A.5: ordinary defun open + (t + (goto-char placeholder) + (if inclass-p + (c-add-syntax 'defun-open (c-point 'boi)) + (c-add-syntax 'defun-open (c-point 'bol))) + ))) + ;; CASE 5B: first K&R arg decl or member init + ((c-just-after-func-arglist-p) + (cond + ;; CASE 5B.1: a member init + ((or (eq char-before-ip ?:) + (eq char-after-ip ?:)) + ;; this line should be indented relative to the beginning + ;; of indentation for the topmost-intro line that contains + ;; the prototype's open paren + ;; TBD: is the following redundant? + (if (eq char-before-ip ?:) + (forward-char -1)) + (c-backward-syntactic-ws lim) + ;; TBD: is the preceding redundant? + (if (eq (char-before) ?:) + (progn (forward-char -1) + (c-backward-syntactic-ws lim))) + (if (eq (char-before) ?\)) + (c-backward-sexp 1)) + (setq placeholder (point)) + (save-excursion + (and (c-safe (c-backward-sexp 1) t) + (looking-at "throw[^_]") + (c-safe (c-backward-sexp 1) t) + (setq placeholder (point)))) + (goto-char placeholder) + (c-add-syntax 'member-init-intro (c-point 'boi)) + ;; we don't need to add any class offset since this + ;; should be relative to the ctor's indentation + ) + ;; CASE 5B.2: K&R arg decl intro + (c-recognize-knr-p + (c-add-syntax 'knr-argdecl-intro (c-point 'boi)) + (if inclass-p (c-add-class-syntax 'inclass inclass-p))) + ;; CASE 5B.3: Inside a member init list. + ((c-beginning-of-member-init-list lim) + (c-forward-syntactic-ws) + (c-add-syntax 'member-init-cont (point))) + ;; CASE 5B.4: Nether region after a C++ or Java func + ;; decl, which could include a `throws' declaration. + (t + (c-beginning-of-statement-1 lim) + (c-add-syntax 'func-decl-cont (c-point 'boi)) + ))) + ;; CASE 5C: inheritance line. could be first inheritance + ;; line, or continuation of a multiple inheritance + ((or (and c-baseclass-key + (progn + (when (eq char-after-ip ?,) + (skip-chars-forward " \t") + (forward-char)) + (looking-at c-baseclass-key))) + (and (or (eq char-before-ip ?:) + ;; watch out for scope operator + (save-excursion + (and (eq char-after-ip ?:) + (c-safe (progn (forward-char 1) t)) + (not (eq (char-after) ?:)) + ))) + (save-excursion + (c-backward-syntactic-ws lim) + (if (eq char-before-ip ?:) + (progn + (forward-char -1) + (c-backward-syntactic-ws lim))) + (back-to-indentation) + (looking-at c-class-key))) + ;; for Java + (and (c-major-mode-is 'java-mode) + (let ((fence (save-excursion + (c-beginning-of-statement-1 lim) + (point))) + cont done) + (save-excursion + (while (not done) + (cond ((looking-at c-Java-special-key) + (setq injava-inher (cons cont (point)) + done t)) + ((or (not (c-safe (c-forward-sexp -1) t)) + (<= (point) fence)) + (setq done t)) + ) + (setq cont t))) + injava-inher) + (not (c-crosses-statement-barrier-p (cdr injava-inher) + (point))) + )) + (cond + ;; CASE 5C.1: non-hanging colon on an inher intro + ((eq char-after-ip ?:) + (c-backward-syntactic-ws lim) + (c-add-syntax 'inher-intro (c-point 'boi)) + ;; don't add inclass symbol since relative point already + ;; contains any class offset + ) + ;; CASE 5C.2: hanging colon on an inher intro + ((eq char-before-ip ?:) + (c-add-syntax 'inher-intro (c-point 'boi)) + (if inclass-p (c-add-class-syntax 'inclass inclass-p))) + ;; CASE agulbrahack.1: + ((and inclass-p + c-access-key + (looking-at c-access-key)) + (c-add-syntax 'access-label (c-point 'bonl)) + (c-add-class-syntax 'inclass inclass-p) + ) + ;; CASE 5C.3: in a Java implements/extends + (injava-inher + (let ((where (cdr injava-inher)) + (cont (car injava-inher))) + (goto-char where) + (cond ((looking-at "throws[ \t\n]") + (c-add-syntax 'func-decl-cont + (progn (c-beginning-of-statement-1 lim) + (c-point 'boi)))) + (cont (c-add-syntax 'inher-cont where)) + (t (c-add-syntax 'inher-intro + (progn (goto-char (cdr injava-inher)) + (c-beginning-of-statement-1 lim) + (point)))) + ))) + ;; CASE 5C.4: a continued inheritance line + (t + (c-beginning-of-inheritance-list lim) + (c-add-syntax 'inher-cont (point)) + ;; don't add inclass symbol since relative point already + ;; contains any class offset + ))) + ;; CASE 5D: this could be a top-level compound statement, a + ;; member init list continuation, or a template argument + ;; list continuation. + ((c-with-syntax-table (if (c-major-mode-is 'c++-mode) + c++-template-syntax-table + (syntax-table)) + (save-excursion + (while (and (= (c-backward-token-1 1 t lim) 0) + (not (looking-at "[;{<,]")))) + (eq (char-after) ?,))) + (goto-char indent-point) + (c-beginning-of-member-init-list lim) + (cond + ;; CASE 5D.1: hanging member init colon, but watch out + ;; for bogus matches on access specifiers inside classes. + ((and (save-excursion + (setq plaaceholder (point)) + (c-backward-token-1 1 t lim) + (and (eq (char-after) ?:) + (not (eq (char-before) ?:)))) + (save-excursion + (goto-char placeholder) + (back-to-indentation) + (or + (/= (car (save-excursion + (parse-partial-sexp (point) placeholder))) + 0) + (and + (if c-access-key (not (looking-at c-access-key)) t) + (not (looking-at c-class-key)) + (if c-bitfield-key (not (looking-at c-bitfield-key)) t)) + ))) + (goto-char placeholder) + (c-forward-syntactic-ws) + (c-add-syntax 'member-init-cont (point)) + ;; we do not need to add class offset since relative + ;; point is the member init above us + ) + ;; CASE 5D.2: non-hanging member init colon + ((progn + (c-forward-syntactic-ws indent-point) + (eq (char-after) ?:)) + (skip-chars-forward " \t:") + (c-add-syntax 'member-init-cont (point))) + ;; CASE 5D.3: perhaps a multiple inheritance line? + ((save-excursion + (c-beginning-of-statement-1 lim) + (setq placeholder (point)) + (looking-at c-inher-key)) + (goto-char placeholder) + (c-add-syntax 'inher-cont (c-point 'boi))) + ;; CASE 5D.4: perhaps a template list continuation? + ((save-excursion + (goto-char indent-point) + (skip-chars-backward "^<" lim) + ;; not sure if this is the right test, but it should + ;; be fast and mostly accurate. + (setq placeholder (point)) + (and (eq (char-before) ?<) + (not (c-in-literal lim)))) + ;; we can probably indent it just like an arglist-cont + (goto-char placeholder) + (c-beginning-of-statement-1 lim) + (c-add-syntax 'template-args-cont (c-point 'boi))) + ;; CASE 5D.5: perhaps a top-level statement-cont + (t + (c-beginning-of-statement-1 lim) + ;; skip over any access-specifiers + (and inclass-p c-access-key + (while (looking-at c-access-key) + (forward-line 1))) + ;; skip over comments, whitespace + (c-forward-syntactic-ws indent-point) + (c-add-syntax 'statement-cont (c-point 'boi))) + )) + ;; CASE 5E: we are looking at a access specifier + ((and inclass-p + c-access-key + (looking-at c-access-key)) + (c-add-syntax 'access-label (c-point 'bonl)) + (c-add-class-syntax 'inclass inclass-p)) + ;; CASE 5F: extern-lang-close or namespace-close? + ((and inenclosing-p + (eq char-after-ip ?})) + (setq tmpsymbol (if (eq inenclosing-p 'extern) + 'extern-lang-close + 'namespace-close)) + (c-add-syntax tmpsymbol (aref inclass-p 0))) + ;; CASE 5G: we are looking at the brace which closes the + ;; enclosing nested class decl + ((and inclass-p + (eq char-after-ip ?}) + (save-excursion + (save-restriction + (widen) + (forward-char 1) + (and (c-safe (progn (c-backward-sexp 1) t)) + (= (point) (aref inclass-p 1)) + )))) + (c-add-class-syntax 'class-close inclass-p)) + ;; CASE 5H: we could be looking at subsequent knr-argdecls + ((and c-recognize-knr-p + ;; here we essentially use the hack that is used in + ;; Emacs' c-mode.el to limit how far back we should + ;; look. The assumption is made that argdecls are + ;; indented at least one space and that function + ;; headers are not indented. + (let ((limit (save-excursion + (re-search-backward "^[^ \^L\t\n#]" nil 'move) + (point)))) + (save-excursion + (c-backward-syntactic-ws limit) + (setq placeholder (point)) + (while (and (memq (char-before) '(?\; ?,)) + (> (point) limit)) + (beginning-of-line) + (setq placeholder (point)) + (c-backward-syntactic-ws limit)) + (and (eq (char-before) ?\)) + (or (not c-method-key) + (progn + (c-forward-sexp -1) + (forward-char -1) + (c-backward-syntactic-ws) + (not (or (memq (char-before) '(?- ?+)) + ;; or a class category + (progn + (c-forward-sexp -2) + (looking-at c-class-key)) + ))))) + )) + (save-excursion + (c-beginning-of-statement-1) + (not (looking-at "typedef[ \t\n]+")))) + (goto-char placeholder) + (c-add-syntax 'knr-argdecl (c-point 'boi))) + ;; CASE 5I: ObjC method definition. + ((and c-method-key + (looking-at c-method-key)) + (c-add-syntax 'objc-method-intro (c-point 'boi))) + ;; CASE 5J: we are at the topmost level, make sure we skip + ;; back past any access specifiers + ((progn + (c-backward-syntactic-ws lim) + (while (and inclass-p + c-access-key + (not (bobp)) + (save-excursion + (c-safe (progn (c-backward-sexp 1) t)) + ;; agulbrahack 2 + (and (looking-at "slots:") + (c-backward-sexp 1)) + (looking-at c-access-key))) + (c-backward-sexp 1) + (c-backward-syntactic-ws lim)) + (or (bobp) + (memq (char-before) '(?\; ?\})))) + ;; real beginning-of-line could be narrowed out due to + ;; enclosure in a class block + (save-restriction + (widen) + (c-add-syntax 'topmost-intro (c-point 'bol)) + (if inclass-p + (progn + (goto-char (aref inclass-p 1)) + (or (= (point) (c-point 'boi)) + (goto-char (aref inclass-p 0))) + (cond + ((eq inenclosing-p 'extern) + (c-add-syntax 'inextern-lang (c-point 'boi))) + ((eq inenclosing-p 'namespace) + (c-add-syntax 'innamespace (c-point 'boi))) + (t (c-add-class-syntax 'inclass inclass-p))) + )) + )) + ;; CASE 5K: we are at an ObjC or Java method definition + ;; continuation line. + ((and c-method-key + (progn + (c-beginning-of-statement-1 lim) + (beginning-of-line) + (looking-at c-method-key))) + (c-add-syntax 'objc-method-args-cont (point))) + ;; CASE 5L: we are at the first argument of a template + ;; arglist that begins on the previous line. + ((eq (char-before) ?<) + (c-beginning-of-statement-1 lim) + (c-forward-syntactic-ws) + (c-add-syntax 'template-args-cont (c-point 'boi))) + ;; CASE 5M: we are at a topmost continuation line + (t + (c-beginning-of-statement-1 lim) + (c-forward-syntactic-ws) + (c-add-syntax 'topmost-intro-cont (c-point 'boi))) + )) ; end CASE 5 + ;; (CASE 6 has been removed.) + ;; CASE 7: line is an expression, not a statement. Most + ;; likely we are either in a function prototype or a function + ;; call argument list + ((not (or (and c-special-brace-lists + (save-excursion + (goto-char containing-sexp) + (c-looking-at-special-brace-list))) + (eq (char-after containing-sexp) ?{))) + (c-backward-syntactic-ws containing-sexp) + (cond + ;; CASE 7A: we are looking at the arglist closing paren + ((and (or (c-major-mode-is 'pike-mode) + ;; Don't check this in Pike since it allows a + ;; comma after the last arg. + (not (eq char-before-ip ?,))) + (memq char-after-ip '(?\) ?\]))) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (when (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (forward-char) + (skip-chars-forward " \t") + (setq placeholder (point))) + (c-add-syntax 'arglist-close placeholder)) + ;; CASE 7B: Looking at the opening brace of an + ;; in-expression block or brace list. + ((eq char-after-ip ?{) + (goto-char indent-point) + (setq placeholder (c-point 'boi)) + (goto-char containing-sexp) + (if (c-inside-bracelist-p placeholder + (cons containing-sexp state)) + (progn + (c-add-syntax 'brace-list-open (c-point 'boi)) + (c-add-syntax 'inexpr-class)) + (c-add-syntax 'block-open (c-point 'boi)) + (c-add-syntax 'inexpr-statement))) + ;; CASE 7C: we are looking at the first argument in an empty + ;; argument list. Use arglist-close if we're actually + ;; looking at a close paren or bracket. + ((memq char-before-ip '(?\( ?\[)) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (when (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (forward-char) + (skip-chars-forward " \t") + (setq placeholder (point))) + (c-add-syntax 'arglist-intro placeholder)) + ;; CASE 7D: we are inside a conditional test clause. treat + ;; these things as statements + ((save-excursion + (goto-char containing-sexp) + (and (c-safe (progn (c-forward-sexp -1) t)) + (looking-at "\\<for\\>[^_]"))) + (goto-char (1+ containing-sexp)) + (c-forward-syntactic-ws indent-point) + (c-beginning-of-statement-1 containing-sexp) + (if (eq char-before-ip ?\;) + (c-add-syntax 'statement (point)) + (c-add-syntax 'statement-cont (point)) + )) + ;; CASE 7E: maybe a continued method call. This is the case + ;; when we are inside a [] bracketed exp, and what precede + ;; the opening bracket is not an identifier. + ((and c-method-key + (eq (char-after containing-sexp) ?\[) + (save-excursion + (goto-char (1- containing-sexp)) + (c-backward-syntactic-ws (c-point 'bod)) + (if (not (looking-at c-symbol-key)) + (c-add-syntax 'objc-method-call-cont containing-sexp)) + ))) + ;; CASE 7F: we are looking at an arglist continuation line, + ;; but the preceding argument is on the same line as the + ;; opening paren. This case includes multi-line + ;; mathematical paren groupings, but we could be on a + ;; for-list continuation line + ((save-excursion + (goto-char (1+ containing-sexp)) + (skip-chars-forward " \t") + (not (eolp))) + (goto-char containing-sexp) + (setq placeholder (c-point 'boi)) + (when (and (c-safe (backward-up-list 1) t) + (> (point) placeholder)) + (forward-char) + (skip-chars-forward " \t") + (setq placeholder (point))) + (c-add-syntax 'arglist-cont-nonempty placeholder)) + ;; CASE 7G: we are looking at just a normal arglist + ;; continuation line + (t (c-beginning-of-statement-1 containing-sexp) + (forward-char 1) + (c-forward-syntactic-ws indent-point) + (c-add-syntax 'arglist-cont (c-point 'boi))) + )) + ;; CASE 8: func-local multi-inheritance line + ((and c-baseclass-key + (save-excursion + (goto-char indent-point) + (skip-chars-forward " \t") + (looking-at c-baseclass-key))) + (goto-char indent-point) + (skip-chars-forward " \t") + (cond + ;; CASE 8A: non-hanging colon on an inher intro + ((eq char-after-ip ?:) + (c-backward-syntactic-ws lim) + (c-add-syntax 'inher-intro (c-point 'boi))) + ;; CASE 8B: hanging colon on an inher intro + ((eq char-before-ip ?:) + (c-add-syntax 'inher-intro (c-point 'boi))) + ;; CASE 8C: a continued inheritance line + (t + (c-beginning-of-inheritance-list lim) + (c-add-syntax 'inher-cont (point)) + ))) + ;; CASE 9: we are inside a brace-list + ((setq special-brace-list + (or (and c-special-brace-lists + (save-excursion + (goto-char containing-sexp) + (c-looking-at-special-brace-list))) + (c-inside-bracelist-p containing-sexp state))) + (cond + ;; CASE 9A: In the middle of a special brace list opener. + ((and (consp special-brace-list) + (save-excursion + (goto-char containing-sexp) + (eq (char-after) ?\()) + (eq char-after-ip (car (cdr special-brace-list)))) + (goto-char (car (car special-brace-list))) + (skip-chars-backward " \t") + (if (and (bolp) + (assoc 'statement-cont + (setq placeholder (c-guess-basic-syntax)))) + (setq syntax placeholder) + (c-beginning-of-statement-1 lim) + (c-forward-token-1 0) + (if (looking-at "typedef\\>") (c-forward-token-1 1)) + (c-add-syntax 'brace-list-open (c-point 'boi)))) + ;; CASE 9B: brace-list-close brace + ((if (consp special-brace-list) + ;; Check special brace list closer. + (progn + (goto-char (car (car special-brace-list))) + (save-excursion + (goto-char indent-point) + (back-to-indentation) + (or + ;; We were between the special close char and the `)'. + (and (eq (char-after) ?\)) + (eq (1+ (point)) (cdr (car special-brace-list)))) + ;; We were before the special close char. + (and (eq (char-after) (cdr (cdr special-brace-list))) + (= (c-forward-token-1) 0) + (eq (1+ (point)) (cdr (car special-brace-list))))))) + ;; Normal brace list check. + (and (eq char-after-ip ?}) + (c-safe (progn (forward-char 1) + (c-backward-sexp 1) + t)) + (= (point) containing-sexp))) + (c-add-syntax 'brace-list-close (c-point 'boi))) + (t + ;; Prepare for the rest of the cases below by going to the + ;; token following the opening brace + (if (consp special-brace-list) + (progn + (goto-char (car (car special-brace-list))) + (c-forward-token-1 1 nil indent-point)) + (goto-char containing-sexp)) + (forward-char) + (let ((start (point))) + (c-forward-syntactic-ws indent-point) + (goto-char (max start (c-point 'bol)))) + (skip-chars-forward " \t\n\r" indent-point) + (cond + ;; CASE 9C: we're looking at the first line in a brace-list + ((= (point) indent-point) + (goto-char containing-sexp) + (c-add-syntax 'brace-list-intro (c-point 'boi)) + ) ; end CASE 9C + ;; CASE 9D: this is just a later brace-list-entry or + ;; brace-entry-open + (t (if (or (eq char-after-ip ?{) + (and c-special-brace-lists + (save-excursion + (goto-char indent-point) + (c-forward-syntactic-ws (c-point 'eol)) + (c-looking-at-special-brace-list (point))))) + (c-add-syntax 'brace-entry-open (point)) + (c-add-syntax 'brace-list-entry (point)) + )) ; end CASE 9D + )))) ; end CASE 9 + ;; CASE 10: A continued statement + ((and (not (memq char-before-ip '(?\; ?:))) + (or (not (eq char-before-ip ?})) + (c-looking-at-inexpr-block-backward containing-sexp)) + (> (point) + (save-excursion + (c-beginning-of-statement-1 containing-sexp) + (c-forward-syntactic-ws) + (setq placeholder (point)))) + (/= placeholder containing-sexp)) + (goto-char indent-point) + (skip-chars-forward " \t") + (let ((after-cond-placeholder + (save-excursion + (goto-char placeholder) + (if (and c-conditional-key (looking-at c-conditional-key)) + (progn + (c-safe (c-skip-conditional)) + (c-forward-syntactic-ws) + (if (eq (char-after) ?\;) + (progn + (forward-char 1) + (c-forward-syntactic-ws))) + (point)) + nil)))) + (cond + ;; CASE 10A: substatement + ((and after-cond-placeholder + (>= after-cond-placeholder indent-point)) + (goto-char placeholder) + (if (eq char-after-ip ?{) + (c-add-syntax 'substatement-open (c-point 'boi)) + (c-add-syntax 'substatement (c-point 'boi)))) + ;; CASE 10B: open braces for class or brace-lists + ((setq special-brace-list + (or (and c-special-brace-lists + (c-looking-at-special-brace-list)) + (eq char-after-ip ?{))) + (cond + ;; CASE 10B.1: class-open + ((save-excursion + (goto-char indent-point) + (skip-chars-forward " \t{") + (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) + (and decl + (setq placeholder (aref decl 0))) + )) + (c-add-syntax 'class-open placeholder)) + ;; CASE 10B.2: brace-list-open + ((or (consp special-brace-list) + (save-excursion + (goto-char placeholder) + (looking-at "\\<enum\\>")) + (save-excursion + (goto-char indent-point) + (while (and (> (point) placeholder) + (= (c-backward-token-1 1 t) 0) + (/= (char-after) ?=))) + (eq (char-after) ?=))) + ;; The most semantically accurate symbol here is + ;; brace-list-open, but we report it simply as a + ;; statement-cont. The reason is that one normally + ;; adjusts brace-list-open for brace lists as + ;; top-level constructs, and brace lists inside + ;; statements is a completely different context. + (goto-char indent-point) + (c-beginning-of-closest-statement) + (c-add-syntax 'statement-cont (c-point 'boi))) + ;; CASE 10B.3: The body of a function declared inside a + ;; normal block. This can only occur in Pike. + ((and (c-major-mode-is 'pike-mode) + (progn + (goto-char indent-point) + (not (c-looking-at-bos)))) + (c-beginning-of-closest-statement) + (c-add-syntax 'defun-open (c-point 'boi))) + ;; CASE 10B.4: catch-all for unknown construct. + (t + ;; Can and should I add an extensibility hook here? + ;; Something like c-recognize-hook so support for + ;; unknown constructs could be added. It's probably a + ;; losing proposition, so I dunno. + (goto-char placeholder) + (c-add-syntax 'statement-cont (c-point 'boi)) + (c-add-syntax 'block-open)) + )) + ;; CASE 10C: iostream insertion or extraction operator + ((looking-at "<<\\|>>") + (goto-char placeholder) + (and after-cond-placeholder + (goto-char after-cond-placeholder)) + (while (and (re-search-forward "<<\\|>>" indent-point 'move) + (c-in-literal placeholder))) + ;; if we ended up at indent-point, then the first + ;; streamop is on a separate line. Indent the line like + ;; a statement-cont instead + (if (/= (point) indent-point) + (c-add-syntax 'stream-op (c-point 'boi)) + (c-backward-syntactic-ws lim) + (c-add-syntax 'statement-cont (c-point 'boi)))) + ;; CASE 10D: continued statement. find the accurate + ;; beginning of statement or substatement + (t + (c-beginning-of-statement-1 after-cond-placeholder) + ;; KLUDGE ALERT! c-beginning-of-statement-1 can leave + ;; us before the lim we're passing in. It should be + ;; fixed, but I'm worried about side-effects at this + ;; late date. Fix for v5. + (goto-char (or (and after-cond-placeholder + (max after-cond-placeholder (point))) + (point))) + (c-add-syntax 'statement-cont (point))) + ))) + ;; CASE 11: an else clause? + ((looking-at "\\<else\\>[^_]") + (c-backward-to-start-of-if containing-sexp) + (c-add-syntax 'else-clause (c-point 'boi))) + ;; CASE 12: Statement. But what kind? Lets see if its a + ;; while closure of a do/while construct + ((progn + (goto-char indent-point) + (skip-chars-forward " \t") + (and (looking-at "while\\b[^_]") + (save-excursion + (c-backward-to-start-of-do containing-sexp) + (setq placeholder (point)) + (looking-at "do\\b[^_]")) + )) + (goto-char placeholder) + (c-add-syntax 'do-while-closure (c-point 'boi))) + ;; CASE 13: A catch or finally clause? This case is simpler + ;; than if-else and do-while, because a block is required + ;; after every try, catch and finally. + ((save-excursion + (and (cond ((c-major-mode-is 'c++-mode) + (looking-at "\\<catch\\>[^_]")) + ((c-major-mode-is 'java-mode) + (looking-at "\\<\\(catch\\|finally\\)\\>[^_]"))) + (c-safe (c-backward-sexp) t) + (eq (char-after) ?{) + (c-safe (c-backward-sexp) t) + (if (eq (char-after) ?\() + (c-safe (c-backward-sexp) t) + t) + (looking-at "\\<\\(try\\|catch\\)\\>[^_]") + (setq placeholder (c-point 'boi)))) + (c-add-syntax 'catch-clause placeholder)) + ;; CASE 14: A case or default label + ((looking-at c-switch-label-key) + (goto-char containing-sexp) + ;; check for hanging braces + (if (/= (point) (c-point 'boi)) + (c-forward-sexp -1)) + (c-add-syntax 'case-label (c-point 'boi))) + ;; CASE 15: any other label + ((looking-at c-label-key) + (goto-char containing-sexp) + ;; check for hanging braces + (if (/= (point) (c-point 'boi)) + (c-forward-sexp -1)) + (c-add-syntax 'label (c-point 'boi))) + ;; CASE 16: block close brace, possibly closing the defun or + ;; the class + ((eq char-after-ip ?}) + (let* ((lim (c-safe-position containing-sexp fullstate)) + (relpos (save-excursion + (goto-char containing-sexp) + (if (/= (point) (c-point 'boi)) + (c-beginning-of-statement-1 lim)) + (c-point 'boi)))) + (cond + ;; CASE 16A: closing a lambda defun or an in-expression + ;; block? + ((save-excursion + (goto-char containing-sexp) + (setq placeholder (c-looking-at-inexpr-block))) + (setq tmpsymbol (if (eq (car placeholder) 'inlambda) + 'inline-close + 'block-close)) + (goto-char containing-sexp) + (back-to-indentation) + (if (= containing-sexp (point)) + (c-add-syntax tmpsymbol (point)) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-syntax tmpsymbol (point)) + (if (/= (point) (cdr placeholder)) + (c-add-syntax (car placeholder))))) + ;; CASE 16B: does this close an inline or a function in + ;; an extern block or namespace? + ((progn + (goto-char containing-sexp) + (setq placeholder (c-search-uplist-for-classkey state))) + (goto-char (aref placeholder 0)) + (if (looking-at (concat c-extra-toplevel-key "[^_]")) + (c-add-syntax 'defun-close relpos) + (c-add-syntax 'inline-close relpos))) + ;; CASE 16C: if there an enclosing brace that hasn't + ;; been narrowed out by a class, then this is a + ;; block-close + ((and (not inenclosing-p) + (c-most-enclosing-brace state) + (or (not (c-major-mode-is 'pike-mode)) + ;; In Pike it can be a defun-close of a + ;; function declared in a statement block. Let + ;; it through to be handled below. + (or (c-looking-at-bos) + (progn + (c-beginning-of-statement-1) + (looking-at c-conditional-key))))) + (c-add-syntax 'block-close relpos)) + ;; CASE 16D: find out whether we're closing a top-level + ;; class or a defun + (t + (save-restriction + (narrow-to-region (point-min) indent-point) + (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) + (if decl + (c-add-class-syntax 'class-close decl) + (c-add-syntax 'defun-close relpos))))) + ))) + ;; CASE 17: statement catchall + (t + ;; we know its a statement, but we need to find out if it is + ;; the first statement in a block + (goto-char containing-sexp) + (forward-char 1) + (c-forward-syntactic-ws indent-point) + ;; now skip forward past any case/default clauses we might find. + (while (or (c-skip-case-statement-forward fullstate indent-point) + (and (looking-at c-switch-label-key) + (not inswitch-p))) + (setq inswitch-p t)) + ;; we want to ignore non-case labels when skipping forward + (while (and (looking-at c-label-key) + (goto-char (match-end 0))) + (c-forward-syntactic-ws indent-point)) + (cond + ;; CASE 17A: we are inside a case/default clause inside a + ;; switch statement. find out if we are at the statement + ;; just after the case/default label. + ((and inswitch-p + (progn + (goto-char indent-point) + (c-beginning-of-statement-1 containing-sexp) + (setq placeholder (point)) + (beginning-of-line) + (when (re-search-forward c-switch-label-key + (max placeholder (c-point 'eol)) t) + (setq placeholder (match-beginning 0))))) + (goto-char indent-point) + (skip-chars-forward " \t") + (if (eq (char-after) ?{) + (c-add-syntax 'statement-case-open placeholder) + (c-add-syntax 'statement-case-intro placeholder))) + ;; CASE 17B: continued statement + ((eq char-before-ip ?,) + (goto-char indent-point) + (c-beginning-of-closest-statement) + (c-add-syntax 'statement-cont (c-point 'boi))) + ;; CASE 17C: a question/colon construct? But make sure + ;; what came before was not a label, and what comes after + ;; is not a globally scoped function call! + ((or (and (memq char-before-ip '(?: ??)) + (save-excursion + (goto-char indent-point) + (c-backward-syntactic-ws lim) + (back-to-indentation) + (not (looking-at c-label-key)))) + (and (memq char-after-ip '(?: ??)) + (save-excursion + (goto-char indent-point) + (skip-chars-forward " \t") + ;; watch out for scope operator + (not (looking-at "::"))))) + (goto-char indent-point) + (c-beginning-of-closest-statement) + (c-add-syntax 'statement-cont (c-point 'boi))) + ;; CASE 17D: any old statement + ((< (point) indent-point) + (let ((safepos (c-most-enclosing-brace fullstate)) + relpos done) + (goto-char indent-point) + (c-beginning-of-statement-1 safepos) + ;; It is possible we're on the brace that opens a nested + ;; function. + (if (and (eq (char-after) ?{) + (save-excursion + (c-backward-syntactic-ws safepos) + (not (eq (char-before) ?\;)))) + (c-beginning-of-statement-1 safepos)) + (if (and inswitch-p + (looking-at c-switch-label-key)) + (progn + (goto-char (match-end 0)) + (c-forward-syntactic-ws))) + (setq relpos (c-point 'boi)) + (while (and (not done) + (<= safepos (point)) + (/= relpos (point))) + (c-beginning-of-statement-1 safepos) + (if (= relpos (c-point 'boi)) + (setq done t)) + (setq relpos (c-point 'boi))) + (c-add-syntax 'statement relpos) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open)))) + ;; CASE 17E: first statement in an in-expression block + ((setq placeholder + (save-excursion + (goto-char containing-sexp) + (c-looking-at-inexpr-block))) + (goto-char containing-sexp) + (back-to-indentation) + (let ((block-intro (if (eq (car placeholder) 'inlambda) + 'defun-block-intro + 'statement-block-intro))) + (if (= containing-sexp (point)) + (c-add-syntax block-intro (point)) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-syntax block-intro (point)) + (if (/= (point) (cdr placeholder)) + (c-add-syntax (car placeholder))))) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + ;; CASE 17F: first statement in an inline, or first + ;; statement in a top-level defun. we can tell this is it + ;; if there are no enclosing braces that haven't been + ;; narrowed out by a class (i.e. don't use bod here!) + ((save-excursion + (save-restriction + (widen) + (goto-char containing-sexp) + (c-narrow-out-enclosing-class state containing-sexp) + (not (c-most-enclosing-brace state)))) + (goto-char containing-sexp) + ;; if not at boi, then defun-opening braces are hung on + ;; right side, so we need a different relpos + (if (/= (point) (c-point 'boi)) + (progn + (c-backward-syntactic-ws) + (c-safe (c-forward-sexp (if (eq (char-before) ?\)) + -1 -2))) + ;; looking at a Java throws clause following a + ;; method's parameter list + (c-beginning-of-statement-1) + )) + (c-add-syntax 'defun-block-intro (c-point 'boi))) + ;; CASE 17G: First statement in a function declared inside + ;; a normal block. This can only occur in Pike. + ((and (c-major-mode-is 'pike-mode) + (progn + (goto-char containing-sexp) + (and (not (c-looking-at-bos)) + (progn + (c-beginning-of-statement-1) + (not (looking-at c-conditional-key)))))) + (c-add-syntax 'defun-block-intro (c-point 'boi))) + ;; CASE 17H: first statement in a block + (t (goto-char containing-sexp) + (if (/= (point) (c-point 'boi)) + (c-beginning-of-statement-1 + (if (= (point) lim) + (c-safe-position (point) state) lim))) + (c-add-syntax 'statement-block-intro (c-point 'boi)) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + )) + ) + ;; now we need to look at any modifiers + (goto-char indent-point) + (skip-chars-forward " \t") + (cond + ;; are we looking at a comment only line? + ((and (looking-at c-comment-start-regexp) + (/= (c-forward-token-1 0 nil (c-point 'eol)) 0)) + (c-add-syntax 'comment-intro)) + ;; we might want to give additional offset to friends (in C++). + ((and (c-major-mode-is 'c++-mode) + (looking-at c-C++-friend-key)) + (c-add-syntax 'friend)) + ;; Start of a preprocessor directive? + ((and (eq literal 'pound) + (= (save-excursion + (c-beginning-of-macro lim) + (setq placeholder (point))) + (c-point 'boi)) + (not (and (c-major-mode-is 'pike-mode) + (eq (char-after (1+ placeholder)) ?\")))) + (c-add-syntax 'cpp-macro))) + ;; return the syntax + syntax)))))) + +(add-hook 'find-file-hooks 'agulbra-c++-clean-out-spaces) +(add-hook 'write-file-hooks 'agulbra-c++-clean-out-spaces) + +(add-hook 'c++-mode-hook 'kde-c++-mode-hook) +(add-hook 'c-mode-hook 'kde-c-mode-hook) +; always end a file with a newline +(setq-default require-final-newline t) +; 'next-line won't be adding newlines +(setq-default next-line-add-newlines nil) +(setq compilation-error-regexp-systems-list '(gnu of comma 4bsd) + compilation-ask-about-save nil) + +(provide 'kde-emacs-core) diff --git a/scripts/kde-emacs/kde-emacs-doc.el b/scripts/kde-emacs/kde-emacs-doc.el new file mode 100644 index 00000000..5fca1361 --- /dev/null +++ b/scripts/kde-emacs/kde-emacs-doc.el @@ -0,0 +1,322 @@ +;; kde-emacs-doc.el +;; +;; Copyright (C) 2002 Zack Rusin <zack@kde.org> +;; +;; This library is free software; you can redistribute it and/or +;; modify it under the terms of the GNU Lesser General Public +;; License as published by the Free Software Foundation; either +;; version 2.1 of the License, or (at your option) any later version. +;; +;; This library is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public +;; License along with this library; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +;; 02110-1301 USA +;; +;; +;;; Documentation : +;; Interactive functions: +;; kde-license-insert - inserts the chosen license header in the current +;; buffer, +;; kde-doc-function-insert - insert documentation skeleton for the function +;; at the current location +;; kde-doc-multiline-insert - inserts blank mutliline comment skeleton +;; kde-doc-oneliner-insert - inserts blank one line comment skeleton +;; +;;; TODO : +;; - add interactive functions to insert file, class, brief, +;; and group comments, +;; - change the way commenting works after license insertion, +;; - add syntax higlighting for doxygen/kdoc keywords +;; - add more license headers + + +(require 'kde-emacs-core) +(require 'kde-emacs-semantic) + +;*---------------------------------------------------------------------*/ +;* Licenses ... */ +;*---------------------------------------------------------------------*/ + +(defvar LGPL "This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +02110-1301 USA" + "GNU LGPL license header.") + +(defvar GPL "This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +02110-1301, USA." + "GNU GPL license header.") + +(defvar FDL "Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with the Invariant Sections being LIST THEIR TITLES, with the +Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. +A copy of the license is included in the section entitled \"GNU +Free Documentation License\"." + "GNU FDL license header.") + +(defvar BSD "Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + "BSD license header.") + + +;;---------------- +;; Variables | +;;---------------- + +(defconst kde-doc-styles + '( + (javadoc . + ((start . "/**") + (end . "*/") + (separator . "\n*") + (oneliner . "///") + (element . "/**< */") + (param . "@param %s") + (return . "@return") + (seealso . "@see") + (class . "") + (brief . "@brief") + (file . "@file %s") + )) + (qt . + ((start . "/*!") + (end . "*/") + (separator . "\n") + (oneliner . "//!") + (element . "/*!< */") + (param . "\\param %s") + (return . "\\return") + (seealso . "\\sa") + (class . "\\class") + (brief . "\\brief") + (file . "\\file %s") + )) + ) + "Documentation styles used by KDE.") + +(defcustom kde-doc-style 'javadoc + "Current documentation style. This variable is buffer local." + :group 'kde-devel + :version "0.1" + :type (if (boundp 'kde-doc-styles) + `(choice ,@(mapcar (lambda (s) `(const ,(car s))) kde-doc-styles)) + 'symbol)) +(make-variable-buffer-local 'kde-doc-style) + +(defcustom kde-license-comment-style 'box + "Style to be used for `kde-license-insert'. +See `comment-styles' for a list of available styles." + :group 'kde-devel + :version "0.1" + :type (if (boundp 'comment-styles) + `(choice ,@(mapcar (lambda (s) `(const ,(car s))) comment-styles)) + 'symbol)) + +;*---------------------------------------------------------------------*/ +;* Functions ... */ +;*---------------------------------------------------------------------*/ + +(defun kde-license-header () + (let ((ret (file-name-nondirectory (buffer-file-name)))) + (setq ret (concat ret " \n\n")) + (setq ret (concat ret "Copyright (C) " (format-time-string "%Y ") + kde-full-name " <"kde-email">\n\n")) + )) + +(defun kde-license-insert (license) + "Inserts the chosen license header at the top of the current +buffer." + (interactive (list (completing-read + "Which license do you want to use? " + '(("GNU GPL" 1) ("GNU LGPL" 2) ("GNU FDL" 3) ("BSD" 4)) + nil t nil))) + (save-excursion + (let ((start (point-min)) + (end) + ) + (setq comment-style kde-license-comment-style) + (goto-char start) + (if license + (progn + (cond ((string= license "GNU GPL") + (insert (kde-license-header)) + (insert GPL) + ) + ((string= license "GNU LGPL") + (insert (kde-license-header)) + (insert LGPL) + ) + ((string= license "GNU FDL") + (insert (kde-license-header)) + (insert FDL) + ) + ((string= license "BSD") + (insert (kde-license-header)) + (insert BSD) + ) + ) + (insert "\n") + (setq end (point)) + (comment-region start end) + ) + ) + ) + )) + +(defmacro kde-doc-type-string (arg) + "Maps doc element from kde-doc-style to string." + `(cdr (assoc ,arg (assoc kde-doc-style kde-doc-styles))) + ) + +(defun kde-doc-param-string (ARG) + "Substitues %s in the param string with ARG." + (let ((par (kde-doc-type-string 'param))) + (if (string-match "\%s" par) + (replace-match ARG t t par) + par)) + ) + +(defun kde-function-documentation (function) + (let ((ret "") (rettype (semantic-token-type function))) + (setq ret (kde-doc-type-string 'start)) + (setq ret (concat ret (kde-doc-type-string 'separator))) + (dolist (elt (semantic-token-function-args function) ret) + (setq ret (concat ret (kde-doc-type-string 'separator) " " + (kde-doc-param-string (semantic-token-name elt)))) + ) + (if (not (or + (kde-is-constructor function) + (semantic-token-function-destructor function))) + (progn + (if (listp rettype) + (setq rettype (car rettype))) + (if (not (string= rettype "void")) + (setq ret (concat ret (kde-doc-type-string 'separator) " " (kde-doc-type-string 'return))) + ) + ) + ) + (setq ret (concat ret "\n" (kde-doc-type-string 'end) )) + )) + +(defun kde-doc-function-insert () + "Inserts skeleton function documentation for a function +at the current location." + (interactive) + (save-excursion + (let* ((pt (point)) + (token (kde-function-at-point pt)) + (ret "") + (start) (end) + ) + (if (not token) + (error "There's no function at %d." pt) + (progn + (setq ret (kde-function-documentation token)) + (goto-char (semantic-token-start token)) + (previous-line) + (goto-char (point-at-eol)) + (setq start (point)) + (insert "\n " ret) + (setq end (semantic-token-end token)) + (indent-region start end nil) + ) + ) + ))) + +(defun kde-doc-oneliner-insert () + "Insert oneliner comment at the current point. If the line is not empty newline is inserted." + (interactive) + (let ((thisblank)(pt)) + (save-excursion + (beginning-of-line) + (setq pt (point)) + (setq thisblank (looking-at "[ \t]*$")) + (if (not thisblank) + (progn + (newline) + (goto-char pt) + )) + (insert (kde-doc-type-string 'oneliner)) + (setq pt (point-at-eol)) + (end-of-line) + ) + (goto-char pt) + )) + +(defun kde-doc-multiline-insert () + "Inserts blank multiline comment at point. If the current line isn't blank +the functions inserts a newline." + (interactive) + (let ((thisblank)(start) (end)) + (save-excursion + (beginning-of-line) + (setq start (point)) + (setq thisblank (looking-at "[ \t]*$")) + (if (not thisblank) + (progn + (newline) + (goto-char start) + )) + ;; The blank to fix sometimes occuring + ;; weird behavior in indent-region + (insert " " + (kde-doc-type-string 'start) + (kde-doc-type-string 'separator) "\n" + (kde-doc-type-string 'end) + ) + (setq end (point)) + (indent-region start end nil) + ) + (goto-char start) + (end-of-line) + )) + + +(provide 'kde-emacs-doc) diff --git a/scripts/kde-emacs/kde-emacs-general.el b/scripts/kde-emacs/kde-emacs-general.el new file mode 100644 index 00000000..be34047c --- /dev/null +++ b/scripts/kde-emacs/kde-emacs-general.el @@ -0,0 +1,179 @@ +;; kde-emacs-general.el +;; +;; Copyright (C) 2002 KDE Development Team <www.kde.org> +;; +;; This library is free software; you can redistribute it and/or +;; modify it under the terms of the GNU Lesser General Public +;; License as published by the Free Software Foundation; either +;; version 2.1 of the License, or (at your option) any later version. +;; +;; This library is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public +;; License along with this library; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +;; 02110-1301 USA + +;;; Commentary: +;; + +;;; Code: + +(require 'kde-emacs-vars) + +;*---------------------------------------------------------------------*/ +;* Functions ... */ +;*---------------------------------------------------------------------*/ + +;; Helper for kde-file-get-cpp-h +(defun kde-find-file (filename basedir) + "Looks for \"filename\" under \"basedir\"" + (if basedir + (let ((path (concat basedir "/" filename))) + (if (file-readable-p path) + path)) + ) +) + +(defun kde-file-get-cpp-h () + "Function returns a corresponding source or header file. The returned +variable is a list of the form (FILENAME IS_READABLE) e.g. when being in +test.h file and having test.cpp file readable in the same directory it will +return (\"test.cpp\" t)." + (interactive) + (let* ((name (buffer-file-name)) + (nname (file-name-sans-extension name)) + (ext (file-name-extension name)) + (path nil) + (ret nil) + (listit nil)) + (cond + ((member ext kde-header-files) + (setq listit kde-source-files) + (while (and listit (not ret)) ; loop over the list but stop once ret is set + (setq path (concat nname "." (car listit))) + (if (file-readable-p path) + (setq ret (cons path t)) + ) + (if (not ret) + (if (string-match "_p$" nname) + (progn + (setq path (concat (substring nname 0 (string-match "_p$" nname)) "." (car listit))) + (if (file-readable-p path) + (setq ret (cons path t)) + ))) + ) + (if (not ret) + (progn ; look in kde-source-directory + (setq path (kde-find-file (file-name-nondirectory path) kde-source-directory)) + (if (and + path + (file-readable-p path)) + (setq ret (cons path t)) + )) + ) + (setq listit (cdr listit)) ; ++listit + ) + ; not found, will create one + (if (not ret) + (setq ret (cons (concat nname "." kde-prefered-source-extension) nil )) + )) + + ((member ext kde-source-files) + (setq listit kde-header-files) + (while (and listit (not ret)) ; loop over the list but stop once ret is set + (setq path (concat nname "." (car listit))) + ; look in current dir + (if (file-readable-p path) + (setq ret (cons path t))) + (if (not ret) ;check for header_p.h files + (progn (setq path (concat nname "_p." (car listit))) + (if (file-readable-p path) + (setq ret (cons path t))))) + (if (not (file-readable-p path)) + (progn ; look in kde-include-directory + (setq path (kde-find-file (file-name-nondirectory path) kde-include-directory)) + (if (and + path + (file-readable-p path)) + (setq ret (cons path t)) + )) + ) + (setq listit (cdr listit)) ; ++listit + ) + ; not found, will create one + (if (not ret) + (setq ret (cons (concat nname "." (car kde-header-files)) nil )) + )) + ) + ret + )) + +(defun kde-switch-cpp-h () + "Switches between the source and the header file +(both directions)." + (interactive) + (let ((file (kde-file-get-cpp-h))) + (if (car file) + (find-file (car file)) + (error "Corresponding source file doesn't exist.") + ) + )) + +(defun kde-delete-backward-ws () + "Function deletes all preceding whitespace characters." + (interactive) + (let ((start (point)) + end) + (save-excursion + (setq end (re-search-backward "[^ \t]" (point-at-bol) t)) + (if (not end) + (setq end (point-at-bol)) + (setq end (1+ end)))) + (delete-backward-char (- start end)))) + +(defun kde-skip-blank-lines () + "Skips backwards past blank lines, stopping +at a first non-blank line" + (let* ((start (point-at-bol)) + (end (point-at-eol)) + (mstring (buffer-substring start end)) + (ret 0)) + (while (or + (string-match "^[ \t\r\n]+$" mstring) + (and (string= mstring "") + (= ret 0))) + (setq ret (forward-line -1)) ; if ret != 0, we stop, since we're at the first line... + (setq start (point-at-bol) + end (point-at-eol)) + (setq mstring (buffer-substring start end)) + ) + )) + +(defun kde-comments-begin () + "Skip back from current point past any preceding C-based comments at the beginning of lines. +Presumes no \"/*\" strings are nested within multi-line comments." + (let ((opoint)) + (while (progn (setq opoint (point)) + ;; To previous line + (if (zerop (forward-line -1)) + (cond + ;; If begins with "//" or ends with "*/", then is a + ;; comment. + ((looking-at "[ \t]*\\(//\\|$\\)")) + ((looking-at ".*\\*/[ \t]*$") + (progn (end-of-line) + ;; Avoid //*** single line comments here. + (if (re-search-backward "\\(^\\|[^/]\\)/\\*" nil t) + (progn (beginning-of-line) + (looking-at "[ \t]*/\\*"))))) + (t nil))))) + (goto-char opoint) + ;; Skip past whitespace + (skip-chars-forward " \t\n\r\f") + (beginning-of-line))) + +(provide 'kde-emacs-general) diff --git a/scripts/kde-emacs/kde-emacs-semantic.el b/scripts/kde-emacs/kde-emacs-semantic.el new file mode 100644 index 00000000..1753520b --- /dev/null +++ b/scripts/kde-emacs/kde-emacs-semantic.el @@ -0,0 +1,456 @@ +;; kde-emacs-semantic.el +;; +;; Copyright (C) 2002 Zack Rusin <zack@kde.org> +;; +;; This library is free software; you can redistribute it and/or +;; modify it under the terms of the GNU Lesser General Public +;; License as published by the Free Software Foundation; either +;; version 2.1 of the License, or (at your option) any later version. +;; +;; This library is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public +;; License along with this library; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +;; 02110-1301 USA + +;;; Commentary: +;; Package provides four interactive functions: +;; - kde-function-doc-insert - creates a skeleton doxygen +;; documentation for function at point. +;; Customize it with kde-func-doc variables. +;; +;; - kde-function-expanded-at-point - returns t if function at point +;; has already been expanded. +;; +;; - kde-function-expand-at-point - expand (creates a stub) for function +;; at point (as long as function is a prototype +;; and haven't been expanded). +;; +;; - kde-create-skeletons - creates stubs for all methods in the current +;; header file. +;; +;; Package is very flexible, look at defcustom variables for things +;; you can customize. + +;;; Problems: +;; Most problems relate to C++ syntax which isn't handled correctly +;; by the Semantic package. For now templates aren't supported, I +;; have a temporary solution for other problems (e.g. const functions, +;; QT/KDE specific access specifiers) + +;;; Code: +(require 'kde-emacs-vars) +(require 'kde-emacs-general) + +;*---------------------------------------------------------------------*/ +;* User configuration ... */ +;*---------------------------------------------------------------------*/ +;;Not yet, not yet +;(defcustom kde-summary-function 'semantic-uml-prototype-nonterminal +; "*Function to use when showing info about the token" +; :group 'kde-devel +; :type semantic-token->text-custom-list +; ) + +(defcustom kde-generate-docs-with-stubs nil + "*Should function documentation be generated with the stubs." + :group 'kde-devel + :type 'boolean) + +(defcustom kde-expand-arg-start "( " + "*A string which specifies how the function arguments format should start. +e.g. \"( \" would start function arguments list like : \"func( int arg\". +and \" (\" will format the begining of the function argument list as +follows : \"func (int arg\"." + :group 'kde-devel + :version "0.1" + :type 'string) + +(defcustom kde-expand-arg-end " )" + "*Just like kde-expand-arg-start but specifies how the list should end." + :group 'kde-devel + :version "0.1" + :type 'string) + +(defcustom kde-expand-arg-break ", " + "*Specifies how the arguments should be separated." + :group 'kde-devel + :version "0.1" + :type 'string) + + +;*---------------------------------------------------------------------*/ +;* Functions ... */ +;*---------------------------------------------------------------------*/ +;; FIXME : semantic doesn't handle QT access specifiers +;(setq-default global-semantic-show-unmatched-syntax-mode nil) +;(setq-default global-semantic-show-dirty-mode nil) + +(defun kde-format-func-arg (arg) + "Formats one argument (from token to string)." + (let ((ret "")) + (if (semantic-token-variable-extra-spec arg 'const) + (setq ret "const ")) + (setq ret (concat ret (car (semantic-token-type arg)))) + (if (semantic-token-variable-extra-spec arg 'pointer) + (dotimes (idx (semantic-token-variable-extra-spec arg 'pointer)) + (setq ret (concat ret "*")) + ) + ) + (if (semantic-token-variable-extra-spec arg 'reference) + (setq ret (concat ret "&")) + ) + (setq ret (concat ret " " (semantic-token-name arg))) + ret + )) + +(defun kde-format-args (token) + "Formats all arguments from token to string. +Token has to be the function variable list e.g. +from semantic-token-function-args" + (let ((res kde-expand-arg-start) (idx 1)) + (dolist (elt token res) + (setq res (concat res (kde-format-func-arg elt))) + (when (< idx (length token)) + (setq res (concat res kde-expand-arg-break))) + (setq idx (1+ idx)) + ) + (setq res (concat res kde-expand-arg-end)) + ;; if it's something like "( )" replace it with "()" + (when (string= res (concat kde-expand-arg-start kde-expand-arg-end)) + (setq res (replace-regexp-in-string "([ \t]+)" "()" res))) + res + )) + +(defun kde-function-in-tokens (FUNC TOKENS) + "Search for function in tokens. FUNC has to be a function +token and TOKENS have to be a list of functions from buffer." + (let ((ret)(elt)) + (while (and TOKENS (not ret)) + (setq elt (car TOKENS)) + (setq TOKENS (cdr TOKENS)) + (if (and (string= (semantic-token-name FUNC) + (semantic-token-name elt)) + (equal (semantic-token-type FUNC) + (semantic-token-type elt)) + ;; FIXME (semantic) : Functions in some classes don't have the + ;; 'parent property set !!! + ;;(string= (semantic-token-function-parent FUNC1) + ;; (semantic-token-function-parent FUNC2)) + (string= (kde-format-args (semantic-token-function-args FUNC)) + (kde-format-args (semantic-token-function-args elt)))) + (setq ret t)) + ) + ret + )) + +(defmacro kde-label-signals (pt) + "Returns none-nil if the current access label == \"signals\"" + `(save-excursion + (goto-char ,pt) + (if (looking-at ":") + (re-search-backward "signals" (point-at-bol) t) + ) + )) + +(defun kde-label-namespace (pt) + "Return the namespace to which the variable/function at point PT belongs to." + (save-excursion + (goto-char pt) + (if (looking-at "::") + (let ((start) (end)) + (re-search-backward "\\b\\w+" (point-at-bol) t) + (setq start (match-beginning 0)) + (setq end (match-end 0)) + (buffer-substring-no-properties start end) + ) + ) + )) + +(defmacro kde-label-slots (pt) + "Return none-nil if at PT there's slots access specifier." + `(save-excursion + (goto-char ,pt) + (if (looking-at ":") + ;; export this regex to a kde-emacs-vars defvar + (re-search-backward "\\(public\\|protected\\|private\\)[ \t]+slots" (point-at-bol) t)) + )) + +(defmacro kde-is-constructor (function) + "Returns t if the FUNCTION is a constructor." + `(semantic-token-function-extra-spec ,function 'constructor) + ) + +(defun kde-function-const (function) + "Returns t if the FUNCTION has been declared as const, e.g. +if given a token representing \"int getInt() const\" this functions +would return t" + (save-excursion + (let ((start (semantic-token-start function)) + (end (semantic-token-end function))) + (goto-char end) + (if (re-search-backward "const\b*;" start t) + t + nil) + ) + )) + +(defun kde-is-prototype (function) + "Returns t if the FUNCTION is only a prototype." + (cond + ((semantic-token-function-extra-spec function 'prototype) + t) + (t + (kde-function-const function)) + )) + + + +(defun kde-function-at-point (pt) + "Return function at pt as a token." + (save-excursion + (let ((token) + (what (semantic-find-nonterminal-by-position pt (current-buffer))) + (ctx)) + (goto-char pt) + (if (eq (semantic-token-token what) 'function) + what + (semantic-find-nonterminal-by-position pt (semantic-token-type-parts what))) + ) + )) + +(defun kde-function-construct (token pclass) + "Constructs a function string from the TOKEN, with the parent class PCLASS." + (let ((fname (semantic-token-name token))) + (if (semantic-token-function-destructor token) + (setq fname (concat "~" fname)) + ) + (if pclass + (setq fname (concat pclass "::" fname)) + ) + (if (and + (not (kde-is-constructor token)) + (not (semantic-token-function-destructor token))) + (progn + (cond + ((stringp (semantic-token-type token)) + (setq fname (concat (semantic-token-type token) "\n" fname)) + ) + (t + (setq fname (concat (car (semantic-token-type token)) "\n" fname))) + ) + (if (semantic-token-function-extra-spec token 'const) + (setq fname (concat "const " fname)) + ) + ) + ) + (setq fname (concat fname (kde-format-args (semantic-token-function-args token)))) + (if (kde-function-const token) + (setq fname (concat fname " const" )) + ) + (setq fname (concat fname "\n{" "\n}")) + fname + ) + ) + +(defun kde-class-expand (class-token) + "Returns stubs for member functions as a string. +class-token has to be a token representing either a class or a struct." + (let ((ret "") + (name (semantic-token-name class-token)) + (parents (semantic-token-type-parent class-token)) + (parts (semantic-token-type-parts class-token)) + (cur-token) + (cur-token-name) + (asignal) + (aslot) + (namespace) + ) + (dolist (elt parts ret) + (setq cur-token (semantic-token-token elt)) + (setq cur-token-name (semantic-token-name elt)) + (cond + ((and + (eq cur-token 'type) + (stringp cur-token-name)) + (cond + ((string= cur-token-name "class") + (kde-class-expand elt) + ) + ((string= cur-token-name "enum") + ;;skip enums + ) + ((string= cur-token-name "struct") + (kde-class-expand elt) + ) + ) + ) + ((and + (eq cur-token 'function) + (stringp cur-token-name)) + ;;FUNCTION - generate a skeleton for it + (if (and (kde-is-prototype elt) + (not asignal)) + (setq ret (concat ret (kde-function-construct elt name) "\n\n")) + ) + ;(insert (kde-function-documentation elt) "\n") + ) + ((and + (eq cur-token 'label) + (stringp cur-token-name)) + (setq aslot nil + asignal nil) + ;;LABEL - unsets both signals and slots + ) + ((and + (eq cur-token 'variable) + cur-token-name) + ;;VARIABLE - doesn't handle static variables correctly right now + ) + ((not (stringp cur-token-name)) + (cond + ((kde-label-signals (car (semantic-token-extent elt))) + ;;SIGNALS - next prototypes belong to signals and we don't want to + ;; expand those + (setq asignal t + aslot nil) + ) + ((kde-label-namespace (car (semantic-token-extent elt))) + ;;NAMESPACE - semantic doesn't handle things like Qt::ButtonState correctly + ;; so we do ;) + (setq namespace (kde-label-namespace (car (semantic-token-extent elt)))) + ) + ((kde-label-slots (car (semantic-token-extent elt))) + ;;SLOTS - for now just unset signals + (setq aslot t + asignal nil) + ) + (t + (insert "something else at " (number-to-string (car (semantic-token-extent elt))) "\n")) + )) + (t + (insert "Unknown type :: " (prin1-to-string elt) " >>" (prin1-to-string cur-token) "\n")) + ) + ) + ret + ) + ) + +(defun kde-expand-tokens (tokens) + "Expands smenatic tokens to strings." + (let ((ret "")) + (dolist (elt tokens ret) + (cond + ((eq (semantic-token-token elt) 'type) + (setq ret (concat ret (kde-class-expand elt))) + ) + ((eq (semantic-token-token elt) 'function) + (if (kde-is-prototype elt) + (setq ret (concat ret (kde-function-construct elt nil) "\n\n")) + ) + ) + ((eq (semantic-token-token elt) 'variable) + ;; skip + ;;(kde-extract-variable elt) + ) + ((eq (semantic-token-token elt) 'include) + ;;ignore includes for now + ) + (t (insert "Unknown type : " (prin1-to-string (semantic-token-type elt)) "\n")) + ) + ) + ) + ) + + +(defun kde-tokens-in-file (FILENAME) + "Returns all tokens from a file with the FILENAME." + (let ((exists (file-readable-p FILENAME)) + (buf (current-buffer)) + (tokens)) + (if exists + (progn + (find-file FILENAME) + (setq tokens (semantic-bovinate-toplevel t)) + (switch-to-buffer buf) + tokens) + nil) + )) + +(defun kde-function-in-file (FUNC FILENAME) + "Returns non-nil if FUNC is in a file named FILENAME" + (let ((tokens (kde-tokens-in-file FILENAME))) + (if tokens + (kde-function-in-tokens FUNC tokens) + nil + ) + )) + +(defun kde-function-is-expanded (FUNC) + "Returns t if the function FUNC has been expanded." + (let ((file (kde-file-get-cpp-h))) + (if (cdr file) + (if (kde-function-in-file FUNC (car file)) + t + nil + ) + nil) + )) + +(defun kde-function-expanded-at-point (PT) + "Returns non-nil if the function at point PT has already been expanded." + (interactive "d") + (let ((func (kde-function-at-point PT))) + (kde-function-is-expanded func) + ) + ) + +(defun kde-create-skeletons () + "Creates functions stubs in the source file, for all functions +in the current header file." + (interactive) + (let* ((all-tokens (semantic-bovinate-toplevel t)) + (filename (buffer-name)) + (cppfile (car (kde-file-get-cpp-h))) + (funcs (kde-expand-tokens all-tokens))) + (find-file cppfile) + (save-excursion + (insert "#include \"" filename "\"\n\n") + (insert funcs) + ) + ) + ) + +(defun kde-function-expand-at-point (PT) + "Expand function at point PT." + (interactive "d") + (let ((object (semantic-find-nonterminal-by-position PT (current-buffer))) + (func (kde-function-at-point PT)) + (file) + (buf) + (parent)) + (if (and object (equal (semantic-token-type object) "class")) + (setq parent (semantic-token-name object))) + (if (and (not (kde-function-expanded-at-point PT)) + (kde-is-prototype func)) + (progn + (setq func (kde-function-construct func parent)) + (setq file (car (kde-file-get-cpp-h))) + (setq buf (current-buffer)) + (find-file file) + (save-excursion + (goto-char (point-max)) + (insert "\n" func "\n") + ) + (switch-to-buffer buf) + ) + (error "Function already expanded or defined!") + ) + ) + ) + +(provide 'kde-emacs-semantic) diff --git a/scripts/kde-emacs/kde-emacs-tips.texi b/scripts/kde-emacs/kde-emacs-tips.texi new file mode 100644 index 00000000..ee7c0f19 --- /dev/null +++ b/scripts/kde-emacs/kde-emacs-tips.texi @@ -0,0 +1,257 @@ +\input texinfo @c -*-texinfo-*- + +@finalout + +@c %**start of header +@setfilename kde-emacs-tips +@settitle KDE Emacs usefull programming tips +@footnotestyle end +@c @setchapternewpage odd !! we don't want blank pages +@c %**end of header + +@dircategory Emacs +@direntry +* KDE Emacs: (kde-emacs). Emacs mode for editing KDE/QT C++/C code. +@end direntry + +@ifnottex +Copyright @copyright{} 2002 Zack Rusin and KDE Development Team + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 or +any later version published by the Free Software Foundation; with the +Invariant Sections being ``The GNU Manifesto'', ``Distribution'' and +``GNU GENERAL PUBLIC LICENSE'', with the Front-Cover texts being ``A GNU +Manual'', and with the Back-Cover Texts as in (a) below. A copy of the +license is included in the section entitled ``GNU Free Documentation +License'' in the Emacs manual. + +(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify +this GNU Manual, like GNU software. Copies published by the Free +Software Foundation raise funds for GNU development.'' + +This document is part of a collection distributed under the GNU Free +Documentation License. If you want to distribute this document +separately from the collection, you can do so by adding a copy of the +license to the document, as described in section 6 of the license. +@end ifnottex + +@titlepage +@sp 10 + +@center @titlefont{KDE Emacs Package} +@sp 2 +@center @subtitlefont{KDE Emacs package documentation and programming tips.} +@sp 2 +@author Zack Rusin + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 2002 Zack Rusin & KDE Development Team +@sp 1 +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 or +any later version published by the Free Software Foundation; with the +Invariant Sections being ``The GNU Manifesto'', ``Distribution'' and +``GNU GENERAL PUBLIC LICENSE'', with the Front-Cover texts being ``A GNU +Manual'', and with the Back-Cover Texts as in (a) below. A copy of the +license is included in the section entitled ``GNU Free Documentation +License'' in the Emacs manual. + +(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify +this GNU Manual, like GNU software. Copies published by the Free +Software Foundation raise funds for GNU development.'' + +This document is part of a collection distributed under the GNU Free +Documentation License. If you want to distribute this document +separately from the collection, you can do so by adding a copy of the +license to the document, as described in section 6 of the license. +@end titlepage + +@node Top, Introduction, (dir), (dir) +@comment node-name, next, previous, up + +@macro kdeemacs +KDE Emacs +@end macro + +@ifinfo +@top @kdeemacs{} + +@kdeemacs{} is an Emacs package with tons of useful features +which ease KDE development process. +KDE Emacs usefull programming tips. + +@end ifinfo + +@menu +* Introduction:: +* Getting Connected:: +* Generating stubs:: +* Tips:: +@end menu + +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +@node Introduction, Getting Connected, Top, Top +@comment node-name, next, previous, up +@chapter Introduction +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +@node Getting Connected, Generating stubs, Introduction, Top +@comment node-name, next, previous, up +@chapter Getting Connected +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +@menu +* Sect. 2.1:: Installation +* Sect. 2.2:: Files +* Sect. 2.3:: Keybindings +@end menu + +@node Sect. 2.1, Sect. 2.2, Chapter 2, Chapter 2 +@section @code{Installation} +@comment node-name, next, previous, up + +@node Sect. 2.2, Sect. 2.3, Sect. 2.1, Chapter 2 +@section @code{Files} +@comment node-name, next, previous, up + +@node Sect. 2.3, , Sect 2.2, Chapter 2 +@section @code{Keybindings} +@comment node-name, next, previous, up + +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +@node Generating stubs , Tips, Getting Connected, Top +@comment node-name, next, previous, up +@chapter Generating stubs +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +@node Tips, Top, Generating stubs, Top +@comment node-name, next, previous, up +@chapter Tips +@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +@sp 1 +@strong{Q.} @emph{How do I hide #ifdef's in source files without +actually changing them?} + +@strong{A.} Use @code{hide-ifdef-mode} which supports hiding of ifdef +blocks without actually changing the file. In this mode @kbd{C-c @@ +C-d} hides ifdef block and @kbd{C-c @@ C-s} shows it again. + +@sp 1 +@strong{Q.} @emph{How do I get more informations about the keybindings +of the currently active modes?} + +@strong{A.} Type @kbd{M-x describe-mode}. + +@sp 1 +@strong{Q.} @emph{How do I get automatic syntax higlighting of my +custom types?} + +@strong{A.} Use a package named @file{ctypes.el} which does exactly +that. + +@sp 1 +@strong{Q.} @emph{Is it possible to highlight dangerous syntax, just +like Borland JBuilder does it?} + +@strong{A.} Yes, use the @file{cwarn.el} package. + +@sp 1 +@strong{Q.} @emph{How do I easily customize Emacs faces/colors?} + +@strong{A.} Use the @file{color-theme.el} package. + +@sp 1 +@strong{Q.} @emph{How do I set the taskbar Emacs identification string?} + +@strong{A.} To your @file{.emacs} add a line like: +@example +(setq frame-title-format "%b (%m)") +@end example +which will display ``filename (mode)'' type of string in the +taskbar. Type @kbd{C-h v frame-title-format} to get more info. + +@sp 1 +@strong{Q.} @emph{Can I make Emacs jump to the matching parenthesis +with @kbd{%} just like vi?} + +@strong{A.} Yes, just add to your @file{.emacs} something like: +@example +;; Make the % key jump to the matching {}[]() if on another, like VI +(global-set-key "%" 'match-paren) + +(defun match-paren (arg) + "Go to the matching parenthesis if on parenthesis otherwise insert %." + (interactive "p") + (cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1)) + ((looking-at "\\s\)") (forward-char 1) (backward-list 1)) + (t (self-insert-command (or arg 1))))) +@end example + +@sp 1 +@strong{Q.} @emph{Can I have words like FIXME, TODO, HACK or NOTE +higlighted in documentation strings?} + +@strong{A.} Yes, either use @file{code-keywords.el} package or wait +till I'll add it to @kdeemacs{}. + +@sp 1 +@strong{Q.} @emph{I really, really hate identifiersNamedLikeThis. I'd +like to change them to identifiers_named_like_this but the +maintainer of the application/library that I'm hacking on doesn't +agree with me. What can I do? } + +@strong{A.} Use the @file{glasses.el} package which changes +identifiersNamedLikeThis to identifiers_named_like_this in the +buffers you're editing and switches them back to their original form +once you save those buffers. + +@sp 1 +@strong{Q.} @emph{Is it possible to get function completion or +signature display in Emacs? Will it ever be done?} + +@strong{A.} Yes and yes. I've been planning on doing this for quite a +while and hopefully will have this finished pretty soon (no dates +though :) ) The first thing that should be done is writing a few +fixes for the Semantic package (@file{c.bnf} to be more exact), +because Semantic doesn't handle templates, member function declared +as const or KDE access specifiers, once this is done all that will be +left is using semanticdb package which efficiently stores and retrieves +large amounts of tokens and then displaying tokens belonging to types at +point which match current context. + +@sp 1 +@strong{Q.} @emph{Is there a package that would highlight changes that +I made to a certain file?} + +@strong{A.} I wouldn't be writing this if there wouldn't - try +@kbd{M-x highlight-changes-mode}. + +@sp 1 +@strong{Q.} @emph{How to get a diff between the stuff I have in my +local buffer and the file on disk?} + +@strong{A.} Use ibuffer package. After @kbd{M-x ibuffer} typing +@kbd{=} over a file will display a diff between the buffer and the +file on the disk. + +@sp 1 +@strong{Q.} @emph{I want to temporarily highlight certain variable in +a file, how to do it?} + +@strong{A.} Type @kbd{M-x hi-lock-mode}, now @kbd{C-x w h +@emph{regexp} @key{RET} @emph{face} @key{RET}} highlights regexp with +face in the current file and @kbd{C-x w r @emph{regexp} @key{RET}} +unhighlights it. + +@node Concept Index, , Variables Index, Top +@c node-name, next, previous, up +@unnumbered Concept Index + +@printindex cp + +@contents +@bye diff --git a/scripts/kde-emacs/kde-emacs-utils.el b/scripts/kde-emacs/kde-emacs-utils.el new file mode 100644 index 00000000..c6904539 --- /dev/null +++ b/scripts/kde-emacs/kde-emacs-utils.el @@ -0,0 +1,894 @@ +;; kde-emacs-utils.el +;; +;; Copyright (C) 2002-2005 KDE Development Team <www.kde.org> +;; +;; This library is free software; you can redistribute it and/or +;; modify it under the terms of the GNU Lesser General Public +;; License as published by the Free Software Foundation; either +;; version 2.1 of the License, or (at your option) any later version. +;; +;; This library is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public +;; License along with this library; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +;; 02110-1301 USA + + +(require 'kde-emacs-vars) +(require 'kde-emacs-general) +(require 'kde-emacs-compat) + +(if (eq kde-emacs-type 'xemacs) + (progn + (require 'func-menu) + (add-hook 'find-file-hooks 'fume-add-menubar-entry)) + (require 'imenu)) + +(defmacro c-safe-scan-lists (from count depth) + "Like `scan-lists' but returns nil instead of signalling errors. +This function does not do any hidden buffer changes." + (if (featurep 'xemacs) + `(scan-lists ,from ,count ,depth nil t) + `(c-safe (scan-lists ,from ,count ,depth)))) + +;; returns non-nil if the given file has a using declaration +;; with the passed namespace +(defun kde-file-has-using (namespace) + (let (found) + (save-excursion + (beginning-of-buffer) + (setq found (re-search-forward "^using" nil 1)) + (if found + (setq found (search-forward namespace (line-end-position) 1)) + ) + ) + found) + ) + +;; returns non-nill if the given file has a "namespace SomeNM" declaration +;; where SomeNM is passed via the namespace argument +(defun kde-file-is-in-namespace (namespace) + (let (found) + (save-excursion + (beginning-of-buffer) + (setq found (re-search-forward "^namespace" nil 1)) + (if found + (setq found (search-forward namespace (line-end-position) 1)) + ) + ) + found) + ) + +; Helper function for parsing our current position in a C++ header file +; returns (namespace (class function)) where (a b) is a cons. +(defun method-under-point () + (let ((class nil) + (namespace "") ; will contain A::B:: + (function nil)) + (save-excursion + (backward-char) ; in case we're after the ';' + (search-forward ";" nil t) ; look for the ';' + (backward-char) + (save-excursion + ; Go up a level, skipping entire classes etc. + ; This is a modified version of (backward-up-list) which doesn't + ; throw an error when not found. + (let ((pos (c-safe-scan-lists (point) -1 1))) + ; +1 added here so that the regexp in the while matches the { too. + (goto-char (if pos (+ pos 1) (point-min)))) + (while (re-search-backward "^[ ]*\\(class\\|namespace\\|struct\\)[ \t][^};]*{" nil t) + (save-excursion + (forward-word 1) + (when (looking-at "[ \t]*[A-Z_]*_EXPORT[A-Z_]*[ \t]") + (forward-word 1) + (re-search-forward "[ \t]" nil t)) + (while (looking-at "[ \t]") + (forward-char 1)) + (setq start (point)) + ; Parse class name ("Foo" or "Foo::Bar::Blah"). + ; Beware of "Foo:" + (while (or (looking-at "[A-Za-z0-9_]") (looking-at "::")) + (while (looking-at "[A-Za-z0-9_]") + (forward-char 1)) + (while (looking-at "::") + (forward-char 2)) + ) + (cond + (class ; class found already, so the rest goes into the namespace + (setq namespace (concat (buffer-substring start (point)) "::" namespace))) + (t ; class==nil + (setq class (buffer-substring start (point))))) + ) + ; Go up one level again + (let ((pos (c-safe-scan-lists (point) -1 1))) + (goto-char (if pos (+ pos 1) (point-min)))) + )) + + ; Back to where we were, parse function name + (let ((end (point))) ; remember where the function decl ends + (search-backward ")" nil t) ; look back for the end of the argument list + (forward-char) + (backward-sexp) ; brings us back to the '(' + (backward-word 1) + (when (looking-at "throw[ \t]") ; exception specification, look for () again + (search-backward ")" nil t) + (forward-char) + (backward-sexp)) + ; now that we moved back enough, go to beginning of line. + ; (we assume that the return type, function name, and '(' are on the same line) + (re-search-backward "^[ \t]*") + (while (looking-at "[ \t]") + (forward-char 1)) + (setq function (buffer-substring (point) end)) + ) + ) ; end of global save-excursion + (cons namespace (cons class function)) ; the returned value + ) + ) + +; get rid of virtual, static, multiple spaces, default values. +(defun canonical-function-sig (function) + (and (string-match "[ \t]*\\<virtual\\>[ \t]*" function) + (setq function (replace-match " " t t function))) + (and (string-match "^\\(virtual\\>\\)?[ \t]*" function) + (setq function (replace-match "" t t function))) + (and (string-match "^\\(explicit\\>\\)?[ \t]*" function) + (setq function (replace-match "" t t function))) + (and (string-match "^\\(static\\>\\)?[ \t]*" function) + (setq function (replace-match "" t t function))) + (while (string-match " +" function) ; simplifyWhiteSpace + (setq function (replace-match " " t t function))) + (while (string-match "\t+" function) + (setq function (replace-match " " t t function))) + (while (string-match "^ " function) ; remove leading whitespace + (setq function (replace-match "" t t function))) + (let ((startargs (string-match "(" function))) + (while (string-match " ?=[^,)]+" function startargs) ; remove default values + (setq function (replace-match " " t t function)))) + (while (string-match " +," function) ; remove space before commas + (setq function (replace-match "," t t function))) + function ; the return value +) + +; Helper method which turns the function as seen in the header +; into the signature for its implementation +; Returns the fully-qualified signature of the function implementation +(defun kde-function-impl-sig (namespace class _function) + (let ( + (function (canonical-function-sig _function)) + (insertion-string nil)) + (and (stringp class) + (cond + ((string-match (concat "^ *" class "[ \\t]*(") function) ; constructor + (setq insertion-string + (replace-match + (concat namespace class "::" class "(") + t t function) + )) + ((string-match (concat "^ *~" class "[ \\t]*(") function) ; destructor + (setq insertion-string + (replace-match + (concat namespace class "::~" class "(") + t t function) + )) + )) ; end of "class required" + (if (not (stringp insertion-string)) ; no ctor nor dtor + (if (or (string-match " *\\([a-zA-Z0-9_]+\\)[ \\t]*(" function) ; normal method + (string-match " *\\(operator[^ \\t]+\\)[ \\t]*(" function)) ; operator + (setq insertion-string + (replace-match + (if class + (concat " " namespace class "::" "\\1(") ; c++ method + (concat " " "\\1(")) ; c function + t nil function) + ) + ; else + (error (concat "Can't parse declaration ``" + function "'' in class ``" class + "'', aborting")))) + insertion-string ; the return value + ) + ) + +;; Switch between the declaration of a class member in .cc/.cpp/.C, and its definition in the .h file +;; Written by David and Reggie after much hair tearing +;; Found since, might be worth looking at: http://www.hendawi.com/emacs/sourcepair.el +(defun switch-to-function-def () + (interactive) + (let ((n (buffer-file-name)) + (namespace "") + (class "") + (function "") + found + ) + (if (or (string-match "\\.cc$" n) + (string-match "\\.cpp$" n) + (string-match "\\.C$" n)) + ; TODO replace fume-function-before-point, needed for emacs, + ; and for better namespace support. + ;(progn + ; (let ((pos (kde-scan-lists (point) -1 1 nil t))) ; Go up a level + ; (goto-char (if pos (+ pos 1) (point-min)))) + (let ((a (fume-function-before-point))) + (and (string-match "^\\(.*\\)::\\(.*\\)$" a) + (progn + (setq class (match-string 1 a)) + (setq function (match-string 2 a)) + (kde-switch-cpp-h) + (goto-char 0) + ; Look for beginning of class ("\\s-+" means whitespace including newlines) + (re-search-forward + (concat "\\(class\\|struct\\|namespace\\)\\s-+" + "\\([A-Z_]+_EXPORT[A-Z_]*\\)?\\s-+" ; allow for optional EXPORT macro + class "\\b" ; the classname - with word separator + "[^;]+{" ; the optional inheritance and the '{' + ) nil t) + ;; TODO keep looking, until we find a match that's not inside a comment + (re-search-forward (concat "\\b" (kde-function-regexp-quote function) "[ \t]*(") nil t))))) + (if (string-match "\\.h$" n) + (progn + (let ((mup (method-under-point)) + (sig "") + (pos 0)) + (setq namespace (car mup)) + (setq class (car (cdr mup))) + (setq function (cdr (cdr mup))) + (kde-switch-cpp-h) + + ;; First search with namespace prefixed + (goto-char 0) + (setq sig (kde-remove-newline (kde-function-impl-sig namespace class function))) + (if (string-match "(.*" sig) ; remove args + (setq sig (replace-match "" nil t sig))) + (setq found (re-search-forward (concat "^[^()]*" (kde-function-regexp-quote sig) "[ \t]*(") nil t) ) + + (if (not found) + (progn + ; Now search without name space prefix + + (goto-char 0) + (setq sig (kde-remove-newline (kde-function-impl-sig "" class function))) + + (if (string-match "(.*" sig) ; remove args + (setq sig (replace-match "" nil t sig))) + (re-search-forward (concat "^[^()]*" (kde-function-regexp-quote sig) "[ \t]*(") nil t) ) ) + ))))) + +(defun kde-remove-newline (str) + (replace-in-string str "\n" " ")) +; quote for use as regexp, but replace spaces with "any whitespace" +(defun kde-function-regexp-quote (str) + (replace-in-string (regexp-quote str) "[ \n\t]" "[ \n\t]")) + +; Initial implementation by Arnt Gulbransen +; Current maintainer: David Faure +(defun agulbra-make-member () + "make a skeleton member function in the .cpp or .cc file" + (interactive) + (let* ( + (mup (method-under-point)) + (namespace (car mup)) ; will contain A::B:: + (class (car (cdr mup))) + (function (cdr (cdr mup))) + (file (buffer-file-name)) + (insertion-string (kde-function-impl-sig namespace class function)) + (msubstr nil) + (start nil) + (newcppfile nil) + ) + (setq insertion-string + (concat insertion-string "\n{\n" + (replace-in-string kde-make-member-default-impl "FUNCTION" + ; the function name and args, without newlines + (replace-in-string insertion-string "\n" " " t) + t) + "}\n")) + ; move to next method, to be ready for next call + (backward-char) ; in case we're after the ';' + (re-search-forward ";" nil t) ; end of this method decl + (let ((moveToNext t)) + (while moveToNext + (re-search-forward ";" nil t) ; end of next method decl + (save-excursion + (forward-char -2) ; -1 goes to ';' itself, so go before that + (while (looking-at "[ \t0=]") + (forward-char -1)) + (forward-char 1) + ; move to next method again if we're at a pure virtual method + (setq moveToNext (looking-at "[ \t]*=[ \t]*0;")) + ) + ) + ) + + (setq newcppfile (not (cdr (kde-file-get-cpp-h)))) + (if (string-match "\\.h$" file) + (kde-switch-cpp-h) + ) + (goto-char (point-max)) + (kde-comments-begin) + (kde-skip-blank-lines) + (setq msubstr (buffer-substring (point-at-bol) (point-at-eol))) + (if (string-match "^#include.*moc.*" msubstr) + (progn + (forward-line -1) + (end-of-line) + (insert "\n"))) + (if (string-match "}" msubstr) + (progn + (end-of-line) + (insert "\n") + (forward-line 1) + )) + (when newcppfile + (insert "\n")) + (insert insertion-string) + (forward-char -3) + (c-indent-defun) + (save-excursion + (and (string-match ".*/" file) + (setq file (replace-match "" t nil file))) + (and (string-match "\\.h$" file) + (functionp 'kdab-insert-include-file) + (kdab-insert-include-file file 't nil))) + (when (featurep 'fume-rescan-buffer) + (fume-rescan-buffer)) + )) + +(defun add-file-to-buildsystem () + "Add the current (C++) file to either Makefile.am or a .pro file, whichever exists." + ; Author: David + (interactive) + (if (file-readable-p "Makefile.am") + (add-file-to-makefile-am) + ; else: find a .pro file and add it there + (let* ((files (directory-files "." nil ".pro$" nil t)) + (projfile (car files))) + (if projfile + (add-file-to-project projfile "^SOURCES[ \t]*") ; could be SOURCES= or SOURCES+= + ; else: error + (error "No build system file found") + ))) + ) + +; internal helper for add-file-to-* +(defun add-file-to-project (makefile searchString) + (let ((file (buffer-name))) + (if (not (file-readable-p makefile)) + (error (concat makefile " not found!")) + ) + (find-file makefile) + (goto-char (point-min)) + (if (re-search-forward searchString nil t) + (progn + (end-of-line) + ; check if line ends with '\' [had to read make-mode.el to find this one!] + (while (= (char-before) ?\\) + (end-of-line 2)) ; moves to end of next line + (insert " ") + (insert file) + ) + (error (concat searchString " not found")) + )) + ) + +(defun add-file-to-makefile-am () + "Add the current file to the first _SOURCES line in the Makefile.am" + ; Author: David + (interactive) + (add-file-to-project "Makefile.am" "_SOURCES") + ) + + +; Inserts a kdDebug statement showing the name of the current method. +; You need to create the empty line first. +(defun insert-kdDebug () + (interactive) + (insert "kdDebug() << ") + ;; no unnecessary fume-* functions which aren't available on GNU/Emacs + (insert "k_funcinfo") + (insert " << endl;") + ) + +; finds a string to be used in the header-protection function ( see below ) +(defun kde-header-protection-definable-string () + (let* ((definablestring "") + (f (buffer-file-name)) + (parts (nreverse (split-string f "/"))) + (i) + (first-iter t) + (iters (min (length parts) kde-header-protection-parts-to-show))) + (dotimes (i iters) + (let ((part (pop parts))) + (setq definablestring + (concat + (upcase (replace-in-string part "[\\.-]" "_")) + (if (not first-iter) "_" "") + definablestring + ) + ) + (setq first-iter nil) + ) + ) + definablestring + ) + ) + +; Creates the ifndef/define/endif statements necessary for a header file +(defun header-protection () + (interactive) + (let ((s (kde-header-protection-definable-string))) + (save-excursion + (goto-char (point-min)) + (insert "#ifndef " s "\n#define " s "\n\n") + (goto-char (point-max)) + (insert "\n#endif\n") + ) + ) + ) + +; Makes '(' insert '(' or ' ( ' where appropiate +(defun insert-parens (arg) (interactive "*P") + (if (not (c-in-literal)) + (let ((n nil) (except nil)) + (save-excursion + (setq n (or (progn (forward-char -2) (looking-at "if")) + (progn (forward-char -1) (looking-at "for")) + (progn (forward-char -1) (looking-at "case")) + (progn (forward-char -1) (looking-at "while")) + ) + ) + (setq except (or (progn (forward-char -2) (looking-at "kdDebug")) + (looking-at "kdError") + (progn (forward-char -2) (looking-at "kdWarning")) + ) + ) + ) + (cond + (n (progn + (insert " ") + (self-insert-command (prefix-numeric-value arg)) + (insert kde-emacs-after-parent-string) + )) + (t ;else + (self-insert-command (prefix-numeric-value arg)) + (cond ((not except) (insert kde-emacs-after-parent-string))) + ))) + (self-insert-command (prefix-numeric-value arg))) + ) + +(defun insert-parens2 (arg) (interactive "*P") + (if (not (c-in-literal)) + (let ((remv nil) (nospac nil)) + (forward-char -2) + (setq remv (looking-at "( ")) ; () -> we'll have to remove that space + (forward-char 1) + (setq nospac ; no space to be added + (or (looking-at " ") + (looking-at "(") + (save-excursion ; check for kdDebug(123 + (while (looking-at "[0-9]") + (forward-char -1)) + (forward-char -7) + (or (looking-at "kdDebug(") + (looking-at "kdError(") + (progn (forward-char -2) (looking-at "kdWarning(")) + ) + ) + ) + ) + (forward-char 1) + (cond + (remv (progn + (delete-backward-char 1) + (self-insert-command (prefix-numeric-value arg)))) ; the () case + (nospac (self-insert-command (prefix-numeric-value arg))) ; no space to be added + (t ;else + (if abbrev-mode ; XEmacs + (expand-abbrev)) + (insert kde-emacs-after-parent-string) + (self-insert-command (prefix-numeric-value arg)) + ))) ; normal case, prepend a space + ;;(blink-matching-open) ; show the matching parens + (self-insert-command (prefix-numeric-value arg))) + ) + +; Makes ',' insert ', ' +(defun insert-comma (arg) + (interactive "*P") + (let* ((ch (char-after)) + (spacep (not (or (eq ch ? ) + (c-in-literal) + arg)))) + (self-insert-command (prefix-numeric-value arg)) + (if spacep + (insert " ")))) + +(defun insert-semicolon (arg) + (interactive "*P") + (self-insert-command (prefix-numeric-value arg)) + (newline-and-indent)) + +(defun insert-curly-brace (arg) (interactive "*P") + (if (not (c-in-literal)) + (let ((n nil) (o nil) + (spacep nil) (c nil) + (oneliner nil)) + (save-excursion + (save-excursion + (if (re-search-forward "[a-zA-Z]" (point-at-eol) t) + (setq oneliner t))) + (forward-char -1) ; These three lines are for the situation where + (if (not (looking-at " ")) ; the user already have inserted a space after + (forward-char 1) ; the closing parenthesis + (setq spacep t)) + (forward-char -2) + (setq o (looking-at "()")) + (forward-char 1) + (setq n (looking-at ")")) + (if (and + (not oneliner) + (not (eq + (count-lines (point-min) (point)) + (count-lines (point-min) (point-max))))) + (progn + (next-line 1) + (beginning-of-line) + (if (re-search-forward "[a-zA-Z]" (point-at-eol) t) + (setq c (eq (car (car (c-guess-basic-syntax))) 'substatement))) + ) + ) + ) + (cond + (n (progn + (if (not spacep) (insert " ")) + (self-insert-command (prefix-numeric-value arg)) + (if (not c) (newline-and-indent)) + (if oneliner (end-of-line)) + (save-excursion + (if c + (progn + (next-line 1) + (end-of-line) + )) + (newline-and-indent) + (insert "}")(c-indent-line)) + (c-indent-line) + )) + (o (progn + (newline) + (self-insert-command (prefix-numeric-value arg)) + (newline-and-indent))) + (t (progn ;else + (self-insert-command (prefix-numeric-value arg)) + (save-excursion + (beginning-of-line) + (c-indent-command)))) + )) + (self-insert-command (prefix-numeric-value arg)) + ) +) + +;; have PelDel mode work +(put 'insert-parens 'pending-delete t) +(put 'insert-parens2 'pending-delete t) +(put 'insert-comma 'pending-delete t) +(put 'insert-curly-brace 'pending-delete t) +(put 'newline-and-indent 'pending-delete t) + +; A wheel mouse that doesn't beep, unlike mwheel-install +(defun scroll-me-up () (interactive) (scroll-up 4)) +(defun scroll-me-down () (interactive) (scroll-down 4)) +(defun scroll-me-up-a-bit () (interactive) (scroll-up 1)) +(defun scroll-me-down-a-bit () (interactive) (scroll-down 1)) + +; Compilation +(defun makeclean () + "Executes a \"make clean\" in the current directory" + (interactive) + (compile (concat kde-emacs-make " clean")) + ) + +(defun make () + "Executes a \"make\" in the current directory" + (interactive) + (compile (concat kde-emacs-make " -k")) + ) + +(defun makeinstall () + "Executes a \"make install\" in the current directory" + (interactive) + (compile (concat kde-emacs-make " -k install")) + ) + +(defun makeinstallexec () + "Executes a \"make install-exec\" in the current directory" + (interactive) + (compile (concat kde-emacs-make " -k install-exec")) + ) + +(defun makethisfile () + "Try to compile the currently opened file" + (interactive) + (let ((f (file-name-nondirectory (buffer-file-name))) + (objext nil)) + + (if (file-readable-p "Makefile.am") + (setq objext "\.lo") + (setq objext "\.o")) + (if (string-match "\.cpp$" f) (setq f (replace-match objext t t f))) + (if (string-match "\.cc$" f) (setq f (replace-match objext t t f))) + (compile (concat kde-emacs-make " " f))) + ) + +;; pc-like textmarking +(when kde-use-pc-select + (progn + (load "pc-select") + (if (eq kde-emacs-type 'xemacs) + (funcall 'pc-select-mode) + (funcall 'pc-selection-mode)))) + + +; Move in other window +(defun scroll-other-up () (interactive) (scroll-other-window-down 1)) ; hehe :) +(defun scroll-other-down () (interactive) (scroll-other-window 1)) + +(defun match-paren (arg) + "Go to the matching parenthesis if on parenthesis otherwise insert %." + (interactive "p") + (cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1)) + ((looking-at "\\s\)") (forward-char 1) (backward-list 1)) + (t (self-insert-command (or arg 1))))) + +(defun kde-start-c++-header () + "Start a new C++ header by inserting include guards ( see \ + header-protection function ), inserting a license statement \ + and putting (point) at the correct position" + (interactive) + (header-protection) + (insert "\n") + (beginning-of-buffer) + (kde-license-insert "GNU GPL") + (next-line 1) + (kill-line) + (end-of-buffer) + (next-line -3) + (insert "\n") +) + +(defun kde-year-range-parse-years-string (string) + "parses something like \"2000, 2008-2010\" into a list of the form \ + ((2008 . 2010)(2000 . 2000))" + (let ((pos -1) + (oldpos) + (l (length string)) + (currange "") + (startyear) + (endyear) + (ret) + ) + (while (< pos l) + (setq oldpos (+ pos 1)) + (setq pos (string-match "[,]" string (+ pos 1))) + (unless pos (setq pos l)) + (setq currange (substring string oldpos pos)) + (string-match "[0-9]+" currange) + (setq startyear (string-to-int (match-string 0 currange))) + (setq endyear + (if (string-match "-" currange) + (string-to-int (substring currange (match-end 0))) + startyear)) + (setq ret (cons (cons startyear endyear) ret)) + ) + ret + ) + ) + +(defun kde-year-range-contains-year (ranges year) + "checks whether year is in ranges.. ( ranges is a list as \ + kde-year-range-parse-years-string returns.. " + (let ((ret)) + (dolist (range ranges ret) + (when (and (>= year (car range)) (<= year (cdr range))) + (setq ret t)) + ))) + +(defun kde-year-range-to-string (ranges) + "converts ranges to a string.." + (let ((ret "")) + (dolist (range ranges) + (setq ret + (concat + (int-to-string (car range)) + (if (/= (cdr range) (car range)) + (concat "-" (int-to-string (cdr range))) + "") + ", " + ret) + ) + ) + ; remove extraneous ", " + (setq ret (substring ret 0 (- (length ret) 2))) + ) + ) + +; merges adjacent year ranges into one.. +(defun kde-year-range-cleanup (range) + (let ((origrange range)) + (while (and range (cdr range)) + (let ((years (car range)) (nyears (cadr range))) + (when (>= (+ (cdr nyears) 1) (car nyears)) + (setcar range (cons (car nyears) (cdr years))) + (setcdr range (cddr range))) + ) + (setq range (cdr range)) + ) + origrange + ) + ) + +; adds year to range.. +(defun kde-year-range-add-year (range year) + (while range + (let ((years (car range))) + (cond + ((and (>= year (car years)) (<= year (cdr years)) + ; year is already in the range.. + (setq range nil))) + ((= year (+ (cdr years) 1)) + (setcdr years year) + (setq range nil)) + ((= year (- (car years) 1)) + (setcar years year) + (setq range nil)) + ) + ) + (setq range (cdr range)) + ) + (kde-year-range-cleanup range) + ) + +(defun kde-add-copyright () (interactive) + "Tries to add your kde-full-name and kde-email to the Copyright \ + statements at the top of a file... It tries to figure out \ + if it's already there, and if so, updates the line to include the \ + current year.. ( well, replaces it by a new one, anyway :) )" + (let ((wascomment "")) + (save-excursion + (beginning-of-buffer) + (if (re-search-forward (concat "Copyright ([Cc]) \\([0-9 ,-]*\\) " (regexp-quote kde-full-name)) nil t) + (progn + (beginning-of-line) + (let ((years (kde-year-range-cleanup (kde-year-range-parse-years-string (match-string 1)))) + (new-copyright-string "Copyright (C) ") + (this-year (string-to-int (format-time-string "%Y")))) + (when (not (kde-year-range-contains-year years this-year)) + (kde-year-range-add-year years this-year)) + (setq new-copyright-string + (concat new-copyright-string (kde-year-range-to-string years))) + ; finish new-copyright-string + (setq new-copyright-string + (concat new-copyright-string " " kde-full-name " <" kde-email ">")) + (beginning-of-line) + (re-search-forward "Copyright ([Cc])") + (beginning-of-line) + (setq wascomment + (buffer-substring (point) + (match-beginning 0) + )) + (kill-line nil) + (insert new-copyright-string) + ) + ) + (beginning-of-buffer) + (let ((first-copyright-str (re-search-forward "Copyright ([Cc])" nil t))) + (if first-copyright-str + (progn + (goto-char first-copyright-str) + (beginning-of-line) + (setq wascomment (buffer-substring (point) (match-beginning 0))) + (forward-line 1) + ) + (goto-line 2)) + ) + (beginning-of-line) + (insert "Copyright (C) " (format-time-string "%Y") " " + kde-full-name " <" kde-email ">\n") + (forward-line -1) + ) + (end-of-line) + (let ((end (point))) + (beginning-of-line) + (insert wascomment) + ) + ) + ) + ) + +(defun kde-emacs-file-style-update () + "Updates the style header of this file" + (interactive) + (if (or (eq major-mode 'c++-mode) + (eq major-mode 'c-mode)) + (let ((startpoint) (endpoint) + (firstline) (strings) + (str) (m) (m2) (var) (value) + (final)) + (save-excursion + (beginning-of-buffer) + (setq startpoint (point)) + (setq endpoint (point-at-eol))) + (setq firstline (buffer-substring startpoint endpoint)) + (if (string-match "-\*-\\([A-Za-z0-9\-\+\:\; ]+\\)-\*-" firstline) + (delete-region startpoint endpoint)) + (setq final (concat "-*- " + "Mode: " mode-name "; " + "c-basic-offset: " (prin1-to-string c-basic-offset) "; " + "indent-tabs-mode: " (prin1-to-string indent-tabs-mode) "; " + "tab-width: " (prin1-to-string tab-width) "; " + "-*-")) + (save-excursion + (beginning-of-buffer) + (insert final) + (comment-region (point-at-bol) (point-at-eol)) + (newline))))) + +; Helper for qt-open-header, for Qt 4. Opens a file if it says #include "../foo/bar.h", +; close it and open that file instead; recursively until finding a real file. +(defun qt-follow-includes (file) + (let ((line "") + (begin nil) + (buffer nil)) + (find-file file) + (goto-char 0) + (if (looking-at "#include \"") + (progn + (forward-char 10) + (setq begin (point)) + (re-search-forward "\"" nil t) + (backward-char 1) + (setq file (buffer-substring begin (point))) + (setq buffer (current-buffer)) + (qt-follow-includes file) + (kill-buffer buffer) + ) + ; else: this is the right file, skip the comments and go to the class + (progn + (re-search-forward "^class" nil t) + (beginning-of-line)) + ))) + +(defun qt-open-header () + "Open the Qt header file for the class under point" + (interactive) + (let* ((qtinc (concat (getenv "QTDIR") "/include/")) + (class (thing-at-point 'word)) + (f nil) + (file nil) + (files nil) + ) + (save-excursion + ; The Qt3 case: the includes are directly in $QTDIR/include/, lowercased + (setq f (concat qtinc (downcase class) ".h" )) + (if (file-readable-p f) + (setq file f) + ; For some Qt3/e classes: add _qws + (setq f (concat qtinc (downcase class) "_qws.h" )) + (if (file-readable-p f) + (setq file f) + ; The Qt4 case: the includes are in $QTDIR/include/QSomething/, in original case + (setq files (directory-files qtinc t nil "dirsonly")) + (dolist (f files nil) + (if (file-readable-p (concat f "/" class) ) + (setq file (concat f "/" class)))) + )) + (and file + (qt-follow-includes file)) + ) + )) + +(provide 'kde-emacs-utils) diff --git a/scripts/kde-emacs/kde-emacs-vars.el b/scripts/kde-emacs/kde-emacs-vars.el new file mode 100644 index 00000000..216e64f5 --- /dev/null +++ b/scripts/kde-emacs/kde-emacs-vars.el @@ -0,0 +1,147 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; kde-emacs-vars.el ;; +;; ;; +;; Copyright (C) 2002 Zack Rusin <zack@kde.org> ;; +;; ;; +;; This program is free software; you can redistribute it and/or ;; +;; modify it under the terms of the GNU General Public License ;; +;; as published by the Free Software Foundation; either version 2 ;; +;; of the License, or (at your option) any later version. ;; +;; ;; +;; This program is distributed in the hope that it will be useful, ;; +;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; +;; GNU General Public License for more details. ;; +;; ;; +;; You should have received a copy of the GNU General Public License ;; +;; along with this program; if not, write to the Free Software ;; +;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA ;; +;; 02110-1301, USA. ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defconst kde-emacs-version "0.2" + "KDE Emacs package version number.") +(defun kde-emacs-version () + "Returns the version of KDE Emacs package." + (interactive) + (message "KDE Emacs version : %s" kde-emacs-version)) + + +(defvar kde-emacs-type + (eval-when-compile + (if (string-match "XEmacs" (emacs-version)) + 'xemacs + 'emacs)) + "The type of Emacs we are running on.") + +;*---------------------------------------------------------------------*/ +;* Constants ... */ +;*---------------------------------------------------------------------*/ + +(defconst kde-access-labels + "\\<\\(signals\\|k_dcop\\|\\(public\\|protected\\|private\\)\\([ ]+slots\\)?\\)\\>:" + "KDE specific access labels regexp.") + +(defconst kde-source-files '("cpp" "cc" "cxx" "CC" "C" "c") + "List of source-file extensions.") + +(defconst kde-header-files '("h" "H" "hh" "hxx" "hpp") + "List of header-file extensions.") + +;*---------------------------------------------------------------------*/ +;* Group ... */ +;*---------------------------------------------------------------------*/ +(defgroup kde-devel nil + "Development utilities." + :tag "KDE devel" + :prefix "kdedevel-" + :group 'programming) + +(defcustom kde-full-name (or user-full-name + (getenv "USER") + "Your Name") + "*Name used by kde-emacs." + :group 'kde-devel + :version "0.1" + :type 'string) + +(defcustom kde-email (or user-mail-address + (concat (getenv "LOGNAME") "@" (getenv "HOSTNAME")) + "Your Email") + "*Email address used by kde-emacs." + :group 'kde-devel + :version "0.1" + :type 'string) + +(defcustom kde-cvs-root (concat (getenv "HOME") "/cvs/kde") + "*Root Directory of KDE CVS Respiratory" + :group 'kde-devel + :type 'string) + +(defcustom magic-keys-mode 't + "Set this variable to true to have some special keybindings. E.g. bind '(' to a function which inserts '( ' when appropriate..." + :group 'kde-devel + :type 'boolean) + +(defcustom kde-emacs-make "make" + "Specifies the make command which KDE Emacs will use" + :group 'kde-devel + :type 'string) + +;;Make styles a list of the format (radio (const kde-c++) (const kde-c) style) +;;and assign it to type. +(defcustom kde-c++-style "kde-c++" + "Set this variable to the CC Mode style you would like loaded when you open a C++ KDE source code file..." + :group 'kde-devel + :type 'string) + +(defcustom kde-c-style "kde-c" + "Set this variable to the CC Mode style you would like loaded when you open a C KDE source code file..." + :group 'kde-devel + :type 'string) + +(defcustom kde-use-pc-select 't + "Set this to nil if you really hate PC Select Mode..." + :group 'kde-devel + :type 'boolean) + +(defcustom kde-emacs-newline-semicolon nil + "Set this to true to have typing \";\" automatically insert +a newline." + :group 'kde-devel + :type 'boolean) + +(defcustom kde-header-protection-parts-to-show 1 + "Set this variable to the number of parts from the file name you want to be used for the defined word in the +header-protection function.. E.g. setting this to 3 makes header-protection define KIG_MISC_NEWTYPE_H for a +file named /home/domi/src/kdenonbeta/kig/misc/newtype.h" + :group 'kde-devel + :type 'integer) + +(defcustom kde-emacs-after-parent-string " " + "Set this to whatever you want to have inserted after the first parenthesis. Works only if +magic-keys-mode is set to true. " + :group 'kde-devel + :type 'string) + +(defcustom kde-include-directory nil + "Set this to the directory holding the includes for the current module/project/whatever." + :group 'kde-devel + :type 'string) + +(defcustom kde-source-directory nil + "Set this to the directory holding the sources for the current module/project/whatever." + :group 'kde-devel + :type 'string) + +(defcustom kde-make-member-default-impl " \n" + "Default implementation added by agulbra-make-member. FUNCTION gets replaced by the full signature of the function/method." + :group 'kde-devel + :type 'string) + +; a grep in the part of kde-source I have gives: +; 5579 files uses .cpp, 1402 uses .cc, 10 uses .cxx, and 1 uses .C +(defconst kde-prefered-source-extension "cpp" + "Source extension which kde-* functions should use for creating new files.") + +(provide 'kde-emacs-vars) diff --git a/scripts/kde-emacs/kde-emacs.el b/scripts/kde-emacs/kde-emacs.el new file mode 100644 index 00000000..b2865c53 --- /dev/null +++ b/scripts/kde-emacs/kde-emacs.el @@ -0,0 +1,66 @@ +;; kde-emacs.el +;; Time-stamp: <2002-06-26 00:49:48 zack> +;; +;; Copyright (C) 2002 Zack Rusin <zackrat@att.net> +;; +;; This library is free software; you can redistribute it and/or +;; modify it under the terms of the GNU Lesser General Public +;; License as published by the Free Software Foundation; either +;; version 2.1 of the License, or (at your option) any later version. +;; +;; This library is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public +;; License along with this library; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +;; 02110-1301 USA + +;;; Installation: +;; +;; Put the following lines in your ".emacs": +;; (add-to-list 'load-path "~/path-to-kde-emacs") +;; (require 'kde-emacs) +;; +;; I also strongly recommend to add the following two lines to +;; .emacs file: +;; (setq kde-full-name "Your Name") +;; (setq kde-email "Your Email") +;; +;; You may want to byte-compile the package to speed it up +;; a bit. To do it in the *scratch* buffer type in the following +;; line: +;; (byte-recompile-directory "~/kde-emacs" t) +;; place the cursor after the closing paren and hit "Ctrl-x Ctrl-e", +;; that's it. +;; +;; All keybindings are in kde-emacs-bindings.el, look at/customize +;; this file before byte-compiling the package! +;; If you want to see things you can customize type: +;; M-x customize-group +;; and type in "kde-devel" group. +;; +;; TODO: +;; - in (if kde-emacs-type... change direct function calls +;; to funcall's +;; + +(require 'cc-mode) ;; needed by kde-emacs-core's test on c-version + +(require 'kde-emacs-compat) +(require 'kde-emacs-core) +(require 'kde-emacs-general) +(require 'klaralv) +(require 'kde-emacs-utils) +(require 'dirvars) + +;; load this only if semantic package is present +(when (featurep 'semantic) + (require 'kde-emacs-semantic) + (require 'kde-emacs-doc)) + +(require 'kde-emacs-bindings) + +(provide 'kde-emacs) diff --git a/scripts/kde-emacs/klaralv.el b/scripts/kde-emacs/klaralv.el new file mode 100644 index 00000000..df29ff78 --- /dev/null +++ b/scripts/kde-emacs/klaralv.el @@ -0,0 +1,422 @@ +;; ------------------------------ COPYRIGHT NOTICE ------------------------------ +;; klaralv.el version 1.3 +;; Copyright Klaralvdalens Datakonsult AB. +;; +;; This program is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2 of the License, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You should have received a copy of the GNU General Public License along +;; with GNU Emacs. If you did not, write to the Free Software Foundation, +;; Inc., 675 Mass Ave., Cambridge, MA 02139, USA. + + +;; ------------------------------ INSTALLATION ------------------------------ +;; To use this file, add the current directory to your load path. +;; you do this by inserting something like the following to your .emacs: +;; (setq load-path (cons "/home/blackie/Emacs/" load-path)) +;; +;; Next insert the following line into your .emacs +;; (require 'klaralv) +;; (global-set-key [(f5)] 'kdab-insert-header) +;; (global-set-key [(shift f5)] 'kdab-insert-forward-decl) +;; (setq kdab-qt-documentation "file://usr/local/qt/html/doc/XXX.html") +;; (global-set-key [(control f5)] 'kdab-lookup-qt-documentation) +;; +;; If you use QTopia, and do not want include files to be prefixed with qpe/, +;; as in qpe/qpeapplication, then insert the following code in your setup +;; (setq kdab-prefix-qpe nil) + +;; ------------------------------ CONFIGURATION ------------------------------ +(defvar kdab-qt-documentation + "http://doc.trolltech.com/3.0/XXX.html" + "URL for Qt documentation. XXX must be in the string. + Example: file://packages/kde-src/qt-copy/doc/html/XXX.html") + +(defvar kdab-qpe-documentation + "file://opt/qtopia/doc/XXX.html" + "URL for QTopia documentatin. XXX must be in the string. + Example: file:/opt/qtopia/doc/XXX.html") + + +(defvar kdab-prefix-qpe 't + "set this to nil if you do not want QPE header files prefixed with qpe/") + +;; special case for include files +;; Please notify blackie@klaralvdalens-datakonsult.se with any modification to this variable! +(defvar kdab-special-includes + '( + (qlayout.h QHBoxLayout QVBoxLayout QGridLayout QBoxLayout) + (qlistview.h QListViewItem QCheckListItem QListViewItemIterator) + (qiconview.h QIconViewItem QIconDragItem QIconDrag) + (qdragobject.h QTextDrag QStoredDrag QUriDag QColorDrag QImageDrag QDragManager) + (qmime.h QMimeSource QMimeSourceFactory QWindowsMime) + (qptrlist.h QPtrListIterator) + (qevent.h QTimerEvent QMouseEvent QWheelEvent QTabletEvent QKeyEvent + QFocusEvent QPaintEvent QMoveEvent QResizeEvent QCloseEvent + QShowEvent QHideEvent QContextMenuEvent QIMEvent QDropEvent + QDragMoveEvent QDragEnterEvent QDragResponseEvent QDragLeaveEvent + QChildEvent QCustomEvent) + (qdatetime.h QTime QDateTime QDate) + (qdatetimeedit.h QTimeEdit QDateTimeEditBase QDateEdit QDateTimeEdit) + (qcstring.h QByteArray) + (qobjectlist.h QObjectListIt QObjectListIterator) + (qwidgetlist.h QWidgetListIt) + (qtabbar.h QTab) + (qpalette.h QColorGroup) + (qaction.h QActionGroup) + (qvalidator.h QIntValidator QDoubleValidator QRegExpValidator) + (qlistbox.h QListBoxItem QListBoxText QListBoxPixmap) + (qstring.h QChar QCharRef QConstString) + (qcanvas.h QCanvasSprite QCanvasPolygonalItem QCanvasRectangle + QCanvasPolygon QCanvasEllipse QCanvasText QCanvasLine + QCanvasChunk QCanvas QCanvasItem QCanvasView QCanvasPixmap) + (qgl.h QGLFormat QGL QGLContext QGLWidget QGLColormap) + (qtable.h QTableSelection QTableItem QComboTableItem QCheckTableItem) + (qsqlfield.h QSqlField QSqlFieldInfo) + (qsqlrecord.h QSqlRecord QSqlRecordInfo) + + ; Qt/Embedded + (qcopchannel_qws.h QCopChannel) + (qdirectpainter_qws.h QDirectPainter) + (qfontfactorybdf_qws.h QFontFactoryBDF) + (qfontfactoryttf_qws.h QFontFactoryFT) + (qfontmanager_qws.h QGlyphMetrics QGlyph QRenderedFont QDiskFont QFontManager QFontFactory) + (qgfx_qws.h QScreenCursor QPoolEntry QScreen QGfx) + (qgfxlinuxfb_qws.h QLinuxFbScreen) + (qgfxmatroxdefs_qws.h QQnxFbGfx QQnxScreen) + (qgfxraster_qws.h QGfxRasterBase QGfxRaster) + (qgfxvnc_qws.h QRfbRect QRfbPixelFormat QRfbServerInit QRfbSetEncodings + QRfbFrameBufferUpdateRequest QRfbKeyEvent QRfbPointerEvent QRfbClientCutText QVNCServer) + (qkeyboard_qws.h QWSKeyboardHandler) + (qlock_qws.h QLock QLockHolder) + (qmemorymanager_qws.h QMemoryManagerPixmap QMemoryManager) + (qsoundqss_qws.h QWSSoundServer QWSSoundClient QWSSoundServerClient QWSSoundServerSocket) + (qwindowsystem_qws.h QWSInternalWindowInfo QWSScreenSaver QWSWindow QWSSoundServer + QWSServer QWSServer KeyboardFilter QWSClient) + (qwsbeosdecoration_qws.h QWSBeOSDecoration) + (qwscursor_qws.h QWSCursor) + (qwsdecoration_qws.h QWSDecoration) + (qwsdefaultdecoration_qws.h QWSDefaultDecoration) + (qwsdisplay_qws.h QWSWindowInfo QWSDisplay) + (qwshydrodecoration_qws.h QWSHydroDecoration) + (qwskde2decoration_qws.h QWSKDE2Decoration) + (qwskdedecoration_qws.h QWSKDEDecoration) + (qwsmanager_qws.h QWSManager QWSButton) + (qwsmouse_qws.h QWSPointerCalibrationData QWSMouseHandler QCalibratedMouseHandler + QAutoMouseHandlerPrivate QWSMouseHandlerPrivate QVrTPanelHandlerPrivate + QTPanelHandlerPrivate QYopyTPanelHandlerPrivate QCustomTPanelHandlerPrivate + QVFbMouseHandlerPrivate) + (qwsproperty_qws.h QWSPropertyManager) + (qwsregionmanager_qws.h QWSRegionManager) + (qwssocket_qws.h QWSSocket QWSServerSocket) + (qwswindowsdecoration_qws.h QWSWindowsDecoration) + (qstatusbar.h statusBar()) + + ; KDE + (kdebug.h kdDebug kdWarning kdError kdFatal kdBacktrace) + (kconfig.h KConfigGroup) + (kiconloader.h BarIcon SmallIcon DesktopIcon KIcon) + (kicondialog.h KIconCanvas KIconButton) + (knuminput.h KDoubleNumInput KIntNumInput) + + ; KDGear - http://www.klaralvdalens-datakonsult.se + (KDCheckableGroupBox.h KDCheckableGroupBox) + (KDCheckableHGroupBox.h KDCheckableHGroupBox) + (KDCheckableVGroupBox.h KDCheckableVGroupBox) + (KDCloseableWidget.h KDCloseableWidget) + (KDConfigDialog.h KDConfigDialog) + (KDConfigWidget.h KDConfigWidget) + (KDDateWidget.h KDDateWidget KDDateTimeWidget) + (KDDirMonitor.h KDDirMonitor) + (KDGridWidget.h KDGridWidget) + (KDListBoxPair.h KDListBoxPair) + (KDMinimizeSplitter.h KDMinimizeSplitter) + (KDSearchableListBox.h KDSearchableListBox) + (KDSemiSizingControl.h KDSemiSizingControl) + (KDShowHideTableControl.h KDShowHideTableControl) + (KDSimpleSizingControl.h KDSimpleSizingControl) + (KDSizingControl.h KDSizingControl) + (KDStream.h KDStream) + (KDTimeWidget.h KDTimeWidget) + + ; KDChart - http://www.klaralvdalens-datakonsult.se + (KDChart.h KDChart) + (KDChartAxisParams.h KDChartAxisParams) + (KDChartBaseSeries.h KDChartBaseSeries) + (KDChartCustomBox.h KDChartCustomBox) + (KDChartData.h KDChartData) + (KDChartEnums.h KDChartEnums) + (KDChartListTable.h KDChartListTableData KDChartListTablePrivate) + (KDChartNotEnoughSpaceException.h KDChartNotEnoughSpaceException) + (KDChartPainter.h KDChartPainter) + (KDChartParams.h KDChartFrameSettings KDChartParams ModeAndChart) + (KDChartPlaneSeries.h KDChartPlaneSeries) + (KDChartPropertySet.h KDChartPropertySet) + (KDChartSeriesCollection.h KDChartSeriesCollection) + (KDChartTable.h KDChartTableData) + (KDChartTableBase.h KDChartTableDataBase) + (KDChartTextPiece.h KDChartTextPiece) + (KDChartUnknownTypeException.h KDChartUnknownTypeException) + (KDChartVectorSeries.h KDChartVectorSeries) + (KDChartVectorTable.h KDChartVectorTableData KDChartVectorTablePrivate) + (KDChartWidget.h KDChartWidget) + (KDFrame.h KDFrame KDFrameCorner) + (KDFrameProfileSection.h KDFrameProfileSection) + + + ; Useful fake entries + (qapplication.h qApp) + (kapplication.h kapp) + (klocale.h i18n I18N_NOOP) + (kstandarddirs.h locate locateLocal) + (stdlib.h getenv) + (unistd.h unlink sleep usleep) + (iostream cout cerr) + (ctype.h isalnum isalpha isascii isblank iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit) + (qeventloop.h eventloop) + + ) + "List of special include files which do not follow the normal scheme") + +(defvar kdab-qpe-includes + '( + (alarmserver.h AlarmServer) + (applnk.h AppLnk DocLnk AppLnkSet DocLnkSet) + (calendar.h Calendar) + (categories.h CategoryGroup CategoryGroup Categories CheckedListView) + (categorymenu.h CategoryMenu) + (categoryselect.h CategoryCombo CategorySelect CategoryEdit CategoryWidget) + (config.h Config) + (contact.h Contact) + (database.h QWSDatabase DatabaseDefaultView Database DatabaseView DatabaseDefaultView) + (datebookdb.h DateBookDB) + (datebookmonth.h DateBookMonthHeader DayItemMonth DateBookMonthTable DateBookMonth DateButton) + (event.h Event EffectiveEvent EffectiveEventSizeSorter EffectiveEventTimeSorter) + (filemanager.h FileManager) + (fileselector.h FileSelectorItem FileSelector) + (finddialog.h FindDialog) + (fontdatabase.h FontDatabase) + (fontmanager.h FontManager) + (global.h Global) + (imageedit.h ImageEdit) + (inputmethodinterface.h InputMethodInterface) + (ir.h Ir) + (lightstyle.h LightStyle) + (lnkproperties.h LnkProperties) + (mediaplayerplugininterface.h MediaPlayerDecoder) + (menubutton.h MenuButton) + (mimetype.h MimeType) + (network.h Network) + (palmtoprecord.h Record) + (palmtopuidgen.h UidGen) + (password.h Password) + (power.h PowerStatus PowerStatusManager ) + (process.h Process) + (qcopenvelope_qws.h QCopEnvelope) + (qdawg.h QDawg) + (qlibrary.h QLibrary) + (qpeapplication.h QPEApplication) + (qpedecoration_qws.h QPEDecoration QPEManager) + (qpedialog.h QPEDialogListener) + (qpemenubar.h QPEMenuToolFocusManager QPEMenuBar) + (qpemessagebox.h QPEMessageBox) + (qpestyle.h QPEStyle : public QWindowsStyle) + (qpetoolbar.h QPEToolBar) + (record.h Record) + (resource.h Resource) + (sound.h Sound) + (storage.h StorageInfo FileSystem) + (task.h Task) + (timeconversion.h TimeConversion) + (timestring.h DateFormat TimeString) + (tzselect.h TZCombo TimeZoneSelector) + )) + +;; ------------------------------ SOURCE CODE ------------------------------ + +;; Merge in qpe classes +(defun kdab-get-special-include-list () + (let (elm header classes (list kdab-qpe-includes) filename (result kdab-special-includes)) + (while list + (setq elm (car list)) + (setq list (cdr list)) + (setq filename (concat (if kdab-prefix-qpe "qpe/" "") (symbol-name (car elm)))) + (setq result (cons (cons (intern filename) (cdr elm)) result))) + result)) + +;; Lookup class `cls' in kdab-special-includes and return the associate include file name +(defun kdab-map-special (cls) + (let ((list (kdab-get-special-include-list)) + (found nil)) + (while (and list (not found)) + (let* ( (elm (car list)) + (include-file (car elm)) + (classes (cdr elm))) + ( while (and classes (not found)) + (if (string= (downcase cls) (downcase (symbol-name (car classes)))) + (setq found include-file) + (setq classes (cdr classes))))) + (setq list (cdr list))) + (if found + (symbol-name found) + nil) ; return value + )) + + + +;-------------------------------------------------------------------------------- +; Insert include file for Qt program. +; Place point anywhere on a Qt class, and invoke this function. A result of +; this is that an include line is added (if it does not already exists) for +; the given class. +;-------------------------------------------------------------------------------- +(defun kdab-insert-header ( prefix ) + "Insert include file for class at point" + (interactive "P") + (save-excursion + (let* ((word-at-point (if prefix + (read-from-minibuffer "Class: ") + (current-word)))) + (kdab-insert-header-non-interactive word-at-point)))) + +;-------------------------------------------------------------------------------- +; insert include file for `word-with-case' non-interactively. +; for an interactive version see kdab-insert-header +;-------------------------------------------------------------------------------- +(defun kdab-insert-header-non-interactive (word-with-case) + (save-excursion + (let* ((word (downcase word-with-case)) + (special-header (cond + ((kdab-map-special word) (kdab-map-special word)) + ((string-match "^qdom" word) "qdom.h") + ((string-match "^qxml" word) "qxml.h") + (t (concat word ".h")))) + header is-local) + + + ;; decide on the header file. + (if (file-exists-p (concat word-with-case ".h")) + (progn ; file exists in given case in pwd. + (setq header (concat word-with-case ".h")) + (setq is-local 't)) + (if (file-exists-p (concat word ".h")) ; file exists in lowercase in pwd + (progn + (setq header (concat word ".h")) + (setq is-local 't)) + (progn ; header in <..> path + (setq header special-header) + (setq is-local nil)))) + + (kdab-insert-include-file header is-local t)))) + +;-------------------------------------------------------------------------------- +; Insert header file for header. If is-local insert it with "" +; otherwise insert it with <> +;-------------------------------------------------------------------------------- +(defun kdab-insert-include-file (header is-local show-message) + (let ((include-file (if is-local + (concat "#include \"" header "\"") + (concat "#include <" header ">")))) + + (beginning-of-buffer) + (if (re-search-forward (concat "^ *// *\\(#include *[<\"][ \t]*" header "[ \t]*[>\"]\\)") nil t) + (progn + (replace-match "\\1") + (when show-message + (message (concat "commented in #include for " header)))) + + (if (not (re-search-forward (concat "#include *[\"<][ \t]*" header "[ \t]*[\">]") nil t)) + (progn + ; No include existed + (goto-char (point-max)) ; Using end-of-buffer makes point move, despite save-excursion + (if (not (re-search-backward "^#include *[\"<][^\">]+\.h *[\">]" nil t)) + (beginning-of-buffer) + (progn (end-of-line) (forward-char 1))) + + ;; Now insert the header + (insert (concat include-file "\n")) + (when show-message + (message (concat "inserted " include-file)))) + (when show-message + (message (concat "header file \"" header "\" is already included"))))))) + + + +;---------------------------------------------------------------------------- +; Insert a forward declaration for a Qt class. +; Place point anywhere on a Qt class, and invoke this function. A +; result of this is that a forward declaration line is added (if it does +; not already exist) for the given class. +;---------------------------------------------------------------------------- +(defun kdab-insert-forward-decl ( prefix ) + (interactive "P") + (save-excursion + (let* ((word (if prefix (read-from-minibuffer "Class: ") + (current-word)))) + (beginning-of-buffer) + (if (re-search-forward (concat "^ *// *\\(class *" word ";\\)") nil t) + (progn + (replace-match "\\1") + (message (concat "commented in forward declaration for " word))) + + (if (not (re-search-forward (concat "class *" word ";") nil t)) + (progn + ; No forward decl existed + ; Look for other forward declarations and insert this one before them + ; (this avoids finding class Private; inside a class, or other stuff in the middle of the file) + (if (re-search-forward "^[ \t]*class .*;" nil t) + (progn + ; Exit namespace foo { class bar; } if necessary + ; This is a modified version of (backward-up-list) which doesn't + ; throw an error when not found. + (goto-char (or (scan-lists (point) -1 1 nil t) (point))) ; ### do multiple times if necessary + (re-search-backward "^[ \t]*namespace " nil t) ; in case of namespace foo\n{ + (beginning-of-line)) + ; No forward declarations found, lets search for include lines. + ; For those we start from the end, because we want to leave file.h first. + (progn (goto-char (point-max)) + (if (re-search-backward "#include" nil t) + (progn (end-of-line) (forward-char 1)) + (beginning-of-buffer)))) + + (progn + (insert "class " word ";\n") + (message (concat "inserted class " word ";")))) + (message (concat "forward decl for \"" word "\" already exists"))))))) + + +(defun is-qpe-class (class) + (let ((list kdab-qpe-includes) classes (found nil)) + (while (and (not found) list) + (setq classes (cdr (car list))) + (while classes + (if (string= (downcase (symbol-name (car classes))) (downcase class)) + (setq found 't)) + (setq classes (cdr classes))) + (setq list (cdr list))) + found)) + +;-------------------------------------------------------------------------------- +; Start konqueror with documentation for the class under point. +; set `kdab-qt-documentation' and `kdab-qpe-documentation' +; to specify the replacement for the documentation +;-------------------------------------------------------------------------------- +(defun kdab-lookup-qt-documentation () + (interactive "") + (save-excursion + (let* ((word (downcase (current-word))) + (doc (if (is-qpe-class word) kdab-qpe-documentation kdab-qt-documentation)) + (url (if (not (string-match "XXX" doc)) + (error "didn't find three X's in kdab-qt-documentation or kdab-qpe-documentation") + (replace-match word t t doc)))) + (start-process "qt documentation" nil "kfmclient" "openURL" url) + (message (concat "Loading " url))))) + +(provide 'klaralv) diff --git a/scripts/kde-spellcheck.pl b/scripts/kde-spellcheck.pl new file mode 100755 index 00000000..2a8974e0 --- /dev/null +++ b/scripts/kde-spellcheck.pl @@ -0,0 +1,1537 @@ +#! /usr/bin/env perl + +# CORRECTIONS GO IN THE __DATA__ SECTION AT THE END OF THIS SCRIPT + +# Checks and corrects common spelling errors in text files - code +# derived from kde-spellcheck.pl (Dirk Mueller <mueller@kde.org>) +# +# Copyright (c) 2004 Richard Evans <rich@ridas.com> +# +# License: LGPL 2.0 +# +# 2004-05-14: Richard Evans <rich@ridas.com> +# +# Initial revision differs from kde-spellcheck.pl as follows: +# +# Text file detection no longer spawns external program. +# No longer checks cwd if arguments omitted - just specify '.' +# No longer recurses through sub directories without --recurse. +# Can now check internal dictionary for mistakes using aspell. +# Changes are not made unless --make-changes is specified. +# File modification now uses an intermediate file to reduce the +# chance of data loss. +# Fixed bug that missed words with apostrophes. +# Removed the code checking for "nonword misspelling" - I don't +# believe it was doing anything useful, but please correct me +# if that's not the case! +# Corrected some dictionary entries. +# Runs much, much faster. + +sub usage +{ + warn <<"EOF"; + +kde-spellcheck.pl [flags] filenames/directories + +This script checks for, and optionally replaces, commonly misspelled words +with the correct US English equivalents. The behaviour has changed from +kde-spellcheck.pl - to check subdirectories you must specify --recurse, +omitting arguments does not check the current directory, and changes are +not made to files unless you specify --make-changes + +CAUTION IS NEEDED WHEN USING THIS SCRIPT - changes are made to the original +file and are not programming language syntax aware - this is why the script +only suggests the changes to be made unless --make-changes is specified. + +Hidden files, CVS directories, .desktop, and .moc files are excluded +from checking. + +--check-dictionary : Checks the internal dictionary for potential + spelling mistakes - requires aspell with a US + English dictionary, and Text::Aspell installed. + +--suggest-corrections : Behaves as --check-dictionary, but also suggests + spelling corrections. + +--recurse : Check subdirectories recursively. +--quiet : Disable informational output (not recommended). +--make-changes : Displays the changes that would have been made. +--help|? : Display this summary. + +EOF + + exit; +} + +use strict; +use warnings; +use Getopt::Long; +use File::Temp qw( tempfile ); +use File::Copy qw( copy ); + +my $DICTIONARY = build_dictionary_lookup_table(); + +########################################################################################### +# Add options here as necessary - perldoc Getopt::Long for details on GetOptions + +die "kde-spellcheck2 --help for usage\n" + unless GetOptions ( "check-dictionary" => \my $opt_check_dictionary, + "suggest-corrections" => \my $opt_suggest_corrections, + "quiet" => \my $opt_quiet, + "make-changes" => \my $opt_make_changes, + "recurse" => \my $opt_recurse, + "help|?" => \&usage ); + +check_dictionary($opt_suggest_corrections) if $opt_suggest_corrections or $opt_check_dictionary; + +usage() unless @ARGV; + +require File::MMagic; + +my $MIME = File::MMagic->new; + +my @dirqueue; + +$opt_quiet = 0 unless $opt_make_changes; + +sub info; *info = $opt_quiet ? sub {} : sub { print @_ }; + +for ( @ARGV ) +{ + if ( -f ) { check_file($_) } + elsif ( -d _ ) { push @dirqueue, $_ } + else { warn "Unknown: '$_' is neither a directory or file" } +} + +my $dir; + +process_directory($dir) while $dir = pop @dirqueue; + +$opt_make_changes or print <<EOF; + +NB No changes have been made to any file. Please check the output to +see if the suggested changes are correct - if so, re-run this script +adding argument --make-changes + +EOF + +########################################################################################### + +sub check_file +{ + my $filename = shift; + my $fh; + + unless ( open $fh, "<", $filename ) + { + warn "Failed to open: '$filename': $!"; + return; + } + + my $file_modified = 0; + my @contents = <$fh>; + + close $fh or warn "Failed to close: '$filename': $!"; + + my $original; + my $line_no = 0; + + for ( @contents ) + { + $line_no++; + $original = $_ unless $opt_make_changes; + + for my $word ( split /[^\w']/ ) # \W would split on apostrophe + { + next unless defined (my $correction = $DICTIONARY->{$word}); + + $file_modified ||= 1; + + s/\b$word\b/$correction/g; + + info "$filename ($line_no): $word => $correction\n"; + } + + print "FROM: $original", + " TO: $_\n" if !$opt_make_changes and $_ ne $original; + } + + return unless $file_modified; + return unless $opt_make_changes; + + info "Correcting: $filename\n"; + + my ($tmp_fh, $tmp_filename) = tempfile(UNLINK => 0); + + eval + { + print $tmp_fh @contents or die "Write"; + + $tmp_fh->flush or die "Flush"; + $tmp_fh->seek(0, 0) or die "Seek"; + }; + + die "$@ failed on: '$tmp_filename': $!" if $@; + + copy($tmp_fh, $filename) or die "Failed to copy: $tmp_filename => $filename: $!\n", + "You can manually restore from: $tmp_filename"; + + close $tmp_fh or warn "Close failed on: '$tmp_filename': $!"; + unlink $tmp_filename or warn "Unlink failed on: '$tmp_filename': $!"; +} + + +# Could be more robustly rewitten with File::Find / File::Find::Rules etc + +sub process_directory +{ + my $directory = shift; + + info "Processing directory: $directory\n"; + + opendir my $dh, $directory or die "Failed to read dir: '$directory': $!"; + + while ( my $entry = readdir($dh) ) + { + if ( $entry =~ /^\./ or + $entry =~ /\.desktop$/ or + $entry =~ /\.moc$/ or + $entry eq "CVS" ) + { + info "Skipping excluded file or directory: $entry\n"; + next; + } + + my $file = "$directory/$entry"; + + if ( -d $file ) + { + push(@dirqueue, $file) if $opt_recurse; + next; + } + + next unless -f _; + + # First use perl's heuristic check to discard files as quickly as possible... + + unless ( -T _ ) + { + info "Skipping binary file: $file\n"; + next; + } + + # ...it's not always good enough though, so now check the Mimetype + + unless ( (my $type = $MIME->checktype_filename($file)) =~ /text/i ) + { + info "Skipping $type file: $file\n"; + next; + } + + check_file($file); + } + + closedir $dh or warn "Failed to close dir: '$directory': $!"; +} + + +######################################################################################################## + +sub check_dictionary +{ + my $suggest_corrections = shift; + + print <<EOF; + +Attempting to check the internal dictionary - you must have aspell +and the perl module Text::Aspell installed for this to succeed, +otherwise the script will fail at this point. + +EOF + + require Text::Aspell; + + my $speller = Text::Aspell->new or die "Failed to create Text::Aspell instance"; + + # Despite the docs, set_option doesnt seem to return undef on error ... + + $speller->set_option('lang','en_US') + or die "Text::Aspell failed to select language: 'en_US'", $speller->errstr; + + # ... so try a very simple check + + unless ( $speller->check('color') ) + { + warn "You dont appear to have the en_US dictionary installed - cannot check"; + exit; + } + + print "Checking Lexicon for identical misspelling and corrections:\n"; + + while ( my($key, $value) = each %$DICTIONARY ) + { + print "\n$key" if $key eq $value; + } + + print "\n\nChecking Lexicon for possible misspellings:\n\n"; + + for my $word ( values %$DICTIONARY ) + { + next if $speller->check($word); + + print "$word\n"; + print join(", ", $speller->suggest($word)), "\n\n" if $suggest_corrections; + } + + print "\n"; + + exit; +} + + +######################################################################################################## + +sub build_dictionary_lookup_table +{ + my %hash; + + while (<DATA>) + { + next if /^\s*$/ or /^\s*#/; # Skip blank lines and comments + + next unless /^\s*"([^"]+)"\s+(.*)\s*$/ or /^\s*(\S+)\s+(.*)\s*$/; + + if ( $1 eq $2 ) + { + warn "WARNING: Ignoring identical misspelling and correction: '$1' in __DATA__ offset line $.\n"; + next; + } + + $hash{$1} = $2; + } + + return \%hash; +} + +__DATA__ + +#INCORRECT SPELLING CORRECTION + +aasumes assumes +abailable available +Abbrevation Abbreviation +abbrevations abbreviations +abbriviate abbreviate +abbriviation abbreviation +abilties abilities +Ablolute Absolute +abreviate abbreviate +acces access +accesible accessible +accesing accessing +accomodate accommodate +accross across +Acess Access +achive achieve +achived achieved +achiving achieving +acknoledged acknowledged +acknowledgement acknowledgment +Acknowledgements Acknowledgments +Acknowlege Acknowledge +acommodate accommodate +aconyms acronyms +acording according +acount account +acouting accounting +activ active +actons actions +acually actually +adapater adapter +adatper adapter +addded added +adddress address +Additinoally Additionally +additionaly additionally +Additionaly Additionally +additionnal additional +additonal additional + +#INCORRECT SPELLING CORRECTION + +Addtional Additional +aditional additional +adminstrator administrator +Adminstrator Administrator +adress address +Adress Address +adressed addressed +adresses addresses +advertize advertise +aesthetic esthetic +Afganistan Afghanistan +agressive aggressive +Agressive Aggressive +agressively aggressively +alignement alignment +alligned aligned +Allignment Alignment +allmost almost +allready already +allways always +Allways Always +alook a look +alot a lot +alows allows +alrady already +alreay already +alternativly alternatively +ammount amount +Ammount Amount +analagous analogous +analizer analyzer +analogue analog +analyse analyze +analyses analyzes +anfer after +angainst against +annoucement announcement +announcments announcements +anwer answer +anwser answer +anwsers answers +aplication application +appeareance appearance +appearence appearance +appeares appears +apperarance appearance +appers appears + +#INCORRECT SPELLING CORRECTION + +applicaiton application +Applicalble Applicable +appliction application +appplication application +approciated appreciated +appropiate appropriate +approriate appropriate +approximatly approximately +apropriate appropriate +aquire acquire +aquired acquired +arbitarily arbitrarily +arbitary arbitrary +Arbitary Arbitrary +aribrary arbitrary +aribtrarily arbitrarily +aribtrary arbitrary +arround around +assosciated associated +assosiated associated +assoziated associated +asssembler assembler +assumend assumed +asume assume +asynchonous asynchronous +asyncronous asynchronous +aticles articles +atleast at least +atomicly atomically +attatchment attachment +auhor author +authentification authentication +authoratative authoritative +authorisations authorizations +automaticaly automatically +Automaticaly Automatically +automaticly automatically +autoreplacment autoreplacement +auxilary auxiliary +Auxilary Auxiliary +avaible available +Avaible Available +availble available +availibility availability +availible available +Availible Available +avaliable available +avaluate evaluate +avare aware +aviable available +backrefences backreferences +baloon balloon +basicly basically + +#INCORRECT SPELLING CORRECTION + +Basicly Basically +beautifull beautiful +becuase because +beeep beep +beeing being +beexported be exported +befor before +beggining beginning +begining beginning +behaviour behavior +Behaviour Behavior +Belarussian Belarusian +beteen between +betrween between +betweeen between +Blueish Bluish +bofore before +botton bottom +boudaries boundaries +boundries boundaries +boundry boundary +boxs boxes +bruning burning +buton button +Buxfixes Bugfixes +cacheing caching +calulation calculation +cancelation cancellation +cancelled canceled +cancelling canceling +capabilites capabilities +caracters characters +cataloge catalog +Cataloge Catalog +catalogue catalog +catched caught +ceneration generation +centralised centralized +centre center +Centre Center +changable changeable +chaning changing +characers characters +charachters characters +Characteres Characters +charakters characters +charater character +Chatacter Character +chatwindow chat window +childs children +choosed chose +choosen chosen +Choosen Chosen + +#INCORRECT SPELLING CORRECTION + +chosing choosing +cirumstances circumstances +classess classes +cloumn column +Coffie Coffee +colaboration collaboration +collecion collection +collumns columns +coloum column +coloumn column +colour color +colours colors +colum column +comamnd command +comination combination +commense commence +commerical commercial +comming coming +commited committed +commiting committing +Commiting Committing +commmand command +commuication communication +communcation communication +compability compatibility +comparision comparison +Comparision Comparison +comparisions comparisons +Compatability Compatibility +compatibilty compatibility +compatiblity compatibility +Compedium Compendium +compiiled compiled +compleion completion +completly completely +complient compliant +comsumer consumer +comunication communication +concatonated concatenated +concurent concurrent +configration configuration +Configuraton Configuration +connent connect +connnection connection +consecutivly consecutively +consequtive consecutive +constuctors constructors +contactlist contact list +containg containing +contexual contextual +contigious contiguous +contingous contiguous +continouos continuous + +#INCORRECT SPELLING CORRECTION + +continous continuous +Continous Continuous +contiribute contribute +contoller controller +Contorll Control +controler controller +controling controlling +controll control +conver convert +convient convenient +convinience convenience +conviniently conveniently +coordiator coordinator +Copys Copies +coresponding corresponding +corrent correct +correponds corresponds +Costraints Constraints +Coudn't Couldn't +coursor cursor +Coverted Converted +coypright copyright +cricles circles +criticisim criticism +cryptograhy cryptography +Culculating Calculating +curren current +currenty currently +curteousy courtesy +Custimize Customize +customisation customization +customise customize +Customise Customize +customised customized +cutsom custom +cutt cut +Cutt Cut +datas data +DCOPCient DCOPClient +deactive deactivate +Deamon Daemon +debuging debugging +Debuging Debugging +decriptor descriptor +defaul default +defered deferred +Defininition Definition +defintions definitions +deleteing deleting +Demonsrative Demonstrative +Denstiy Density +depencies dependencies + +#INCORRECT SPELLING CORRECTION + +dependeds depends +dependend dependent +dependig depending +depricated deprecated +derfined defined +derivs derives +descide decide +desciptor descriptor +descryption description +desctroyed destroyed +desiabled disabled +desidered desired +desination destination +deskop desktop +desription description +Desription Description +destiantion destination +determiend determined +determins determines +detremines determines +develloped developed +developerss developers +developped developed +devided divided +devide divide +diabled disabled +diable disable +diaglostic diagnostic +dialag dialog +dialler dialer +Dialler Dialer +dialling dialing +Dialling Dialing +dialogue dialog +diaog dialog +didnt didn't +diffcult difficult +differenciate differentiate +differenly differently +Differntiates Differentiates +dificulty difficulty +Difusion Diffusion +digitised digitized +diplayed displayed +dirctely directly +dirctory directory +direcory directory +directorys directories +directoy directory +disactivate deactivate +disappers disappears +Disbale Disable + +#INCORRECT SPELLING CORRECTION + +discontigous discontiguous +discpline discipline +discription description +disppear disappear +dissassembler disassembler +distingush distinguish +distribtuion distribution +distrubutor distributor +divizor divisor +docucument document +documentaiton documentation +documentors documenters +doens't doesn't +doesnt doesn't +donnot do not +Donot Do not +dont don't +dont't don't +Dou Do +draging dragging +dreamt dreamed +Droped Dropped +duotes quotes +durring during +dynamicly dynamically +eallocate deallocate +eample example +editory editor +efficent efficient +efficently efficiently +effiency efficiency +embedabble embeddable +embedable embeddable +embeddabble embeddable +embeded embedded +emcompass encompass +emty empty +encyption encryption +enhandcements enhancements +enles endless +enought enough +entitities entities +entrys entries +Entrys Entries +enumarated enumerated +envirnment environment +envirnoment environment +enviroment environment +environemnt environment +environent environment +Equador Ecuador +equiped equipped +equlas equals + +#INCORRECT SPELLING CORRECTION + +errorous erroneous +errror error +escriptor descriptor +espacially especially +espesially especially +Evalute Evaluate +everytime every time +exacly exactly +exapmle example +excecpt except +execeeded exceeded +execess excess +exection execution +execuable executable +executeble executable +exept except +exisiting existing +existance existence +exlusively exclusively +exmaple example +experienceing experiencing +explicitely explicitly +explicity explicitly +explit explicit +Expresion Expression +expresions expressions +extented extended +extention extension +Extention Extension +extentions extensions +extesion extension +fabilous fabulous +falg flag +familar familiar +fastes fastest +favourable favorable +favour favor +favourite favorite +favours favors +featue feature +feeded fed +filsystem filesystem +firware firmware +fisrt first +fixiated fixated +fixiate fixate +fixiating fixating +flaged flagged +flavours flavors +focussed focused +folllowed followed +follwing following +folowing following + +#INCORRECT SPELLING CORRECTION + +Folowing Following +footnotexs footnotes +formaly formally +fortunatly fortunately +foward forward +fragement fragment +framesyle framestyle +framset frameset +fucntion function +Fucntion Function +fuction function +fuctions functions +fufill fulfill +fulfiling fulfilling +fullfilled fulfilled +funcion function +funciton function +functin function +funtional functional +funtionality functionality +funtion function +funtions functions +furthur further +gaalxies galaxies +Gamee Game +gernerated generated +ges goes +Ghostscipt Ghostscript +giude guide +globaly globally +goind going +Gostscript Ghostscript +grapphis graphics +greyed grayed +guaranted guaranteed +guarenteed guaranteed +guarrantee guarantee +gziped gzipped +handeling handling +harware hardware +Harware Hardware +hasnt hasn't +havn't haven't +heigt height +heigth height +hiddden hidden +Hierachical Hierarchical +highlighlighted highlighted +highligting highlighting +Higlighting Highlighting +honour honor +honouring honoring + +#INCORRECT SPELLING CORRECTION + +honours honors +horziontal horizontal +hypens hyphens +hysical physical +iconized iconified +illumnating illuminating +imaginery imaginary +i'm I'm +imitatation imitation +immedialely immediately +immediatly immediately +imortant important +imperical empirical +implemantation implementation +implemenation implementation +implenetation implementation +implimention implementation +implmentation implementation +inactiv inactive +incldue include +incomming incoming +Incomming Incoming +incovenient inconvenient +indeces indices +indentical identical +Indentification Identification +indepedancy independency +independant independent +independend independent +indetectable undetectable +indicdate indicate +indice index +indictes indicates +infinitv infinitive +infomation information +informaion information +informatation information +informationon information +informations information +Inifity Infinity +inital initial +initalization initialization +initalized initialized +initalize initialize +Initalize Initialize +initialisation initialization +initialise initialize +initialising initializing +Initialyze Initialize +Initilialyze Initialize +initilization initialization +initilize initialize + +#INCORRECT SPELLING CORRECTION + +Initilize Initialize +innacurate inaccurate +innacurately inaccurately +insde inside +inteface interface +interactivelly interactively +interfer interfere +interfrace interface +interisting interesting +internationalisation internationalization +interrrupt interrupt +interrumped interrupted +interrups interrupts +Interupt Interrupt +intervall interval +intervalls intervals +intiailize initialize +Intial Initial +intialisation initialization +intialization initialization +intialize initialize +Intialize Initialize +intializing initializing +introdutionary introductory +introdution introduction +intrrupt interrupt +intruction instruction +invarient invariant +invokation invocation +Ionisation Ionization +irrevesible irreversible +isntance instance +is'nt isn't +issueing issuing +istory history +Iterface Interface +itselfs itself +journalised journalized +judgement judgment +kdelbase kdebase +keyboad keyboard +klicking clicking +knowlege knowledge +Konquerer Konqueror +konstants constants +kscreensave kscreensaver +labelling labeling +Labelling Labeling +lauching launching +layed laid +learnt learned +leats least +lenght length + +#INCORRECT SPELLING CORRECTION + +Lenght Length +Licenced Licensed +licence license +Licence License +Licens License +liset list +listenening listening +listveiw listview +litle little +litteral literal +localisation localization +losely loosely +maanged managed +maching matching +magnication magnification +magnifcation magnification +mailboxs mailboxes +maillinglists mailinglists +maintainance maintenance +maintainence maintenance +Malicous Malicious +mamage manage +managment management +Managment Management +manangement management +mannually manually +Mantainer Maintainer +manupulation manipulation +marbels marbles +matchs matches +maximimum maximum +Maxium Maximum +mdification modification +mdified modified +menues menus +mesages messages +messanger messenger +messanging messaging +Microsft Microsoft +millimetres millimeters +mimimum minimum +minimise minimize +minimising minimizing +Minimun Minimum +Minium Minimum +minumum minimum +miscelaneous miscellaneous +miscelanous miscellaneous +miscellaneaous miscellaneous +miscellanous miscellaneous +Miscellanous Miscellaneous +mispeled misspelled +mispelled misspelled + +#INCORRECT SPELLING CORRECTION + +mistery mystery +Modifes Modifies +modifing modifying +modul module +mosue mouse +Mozzila Mozilla +mssing missing +Mulitimedia Multimedia +mulitple multiple +multible multiple +multipe multiple +multy multi +mutiple multiple +neccesary necessary +neccessary necessary +necessery necessary +nedd need +neet need +negativ negative +negociated negotiated +negociation negotiation +neighbourhood neighborhood +neighbour neighbor +Neighbour Neighbor +neighbours neighbors +neogtiation negotiation +nessecarry necessary +nessecary necessary +nessesary necessary +nework network +newtork network +nickanme nickname +nonexistant nonexistent +noone nobody +Noone No-one +normalisation normalization +noticable noticeable +nucleous nucleus +obtail obtain +occoured occurred +occouring occurring +occurance occurrence +occurances occurrences +occured occurred +occurence occurrence +occurences occurrences +occure occur +occuring occurring +occurrance occurrence +occurrances occurrences +ocupied occupied +offical official +ommited omitted + +#INCORRECT SPELLING CORRECTION + +onthe on the +opend opened +optimisation optimization +optionnal optional +orangeish orangish +organisational organizational +organisation organization +Organisation Organization +organisations organizations +organised organized +organise organize +organiser organizer +organising organizing +Organising Organizing +orginate originate +Originaly Originally +orignal original +oscilating oscillating +otehr other +ouput output +outputing outputting +overidden overridden +overriden overridden +overriden overridden +ownes owns +pakage package +panelised panelized +paramaters parameters +parametres parameters +parametrize parameterize +paramter parameter +paramters parameters +particip participle +particularily particularly +paticular particular +Pendings Pending +percetages percentages +Perfomance Performance +performace performance +Periferial Peripheral +permision permission +permisions permissions +permissable permissible +Personalizsation Personalization +perticularly particularly +phyiscal physical +plaforms platforms +plese please +politness politeness +posibilities possibilities +posibility possibility + +#INCORRECT SPELLING CORRECTION + +posible possible +positon position +possebilities possibilities +possebility possibility +possibilty possibility +possiblity possibility +posssibility possibility +potentally potentially +practise practice +practising practicing +preceeded preceded +preceeding preceding +precison precision +preemphasised preemphasized +Preemphasised Preemphasized +prefered preferred +Prefered Preferred +preferrable preferable +prefiously previously +preformance performance +prerequisits prerequisites +presense presence +pressentation presentation +prgramm program +Prining Printing +priveleges privileges +priviledge privilege +priviledges privileges +priviliges privileges +probatility probability +probelm problem +proberly properly +problmes problems +proceedure procedure +proctection protection +proecss process +progess progress +programing programming +programme program +programm program +promille per mill +promiscous promiscuous +promped prompted +pronounciation pronunciation +Pronounciation Pronunciation +pronunce pronounce +pronunciated pronounced +properies properties +Propertites Properties +Propogate Propagate +protoypes prototypes + +#INCORRECT SPELLING CORRECTION + +Proxys Proxies +psuedo pseudo +Psuedo Pseudo +pult desk +purposees purposes +quatna quanta +queing queuing +querys queries +queueing queuing +Queueing Queuing +quiten quiet +quiting quitting +readony readonly +realise realize +realy really +REAMDE README +reasonnable reasonable +receieve receive +recepeient recipient +recepient recipient +recevie receive +recevie receive +receving receiving +recieved received +recieve receive +Recieve Receive +reciever receiver +recieves receives +Recieves Receives +recives receives +recognised recognized +recognise recognize +recognises recognizes +recomended recommended +recommanded recommended +recommand recommend +recommented recommended +redialling redialing +reets resets +refered referred +Refering Referring +Refeshes Refreshes +refreshs refreshes +regarless regardless +registaration registration +registred registered +Regsiter Register +regulare regular +regularily regularly +Reigster Register +reimplemenations reimplementations + +#INCORRECT SPELLING CORRECTION + +Reimplemenations Reimplementations +releated related +relection reselection +relevent relevant +relocateable relocatable +remaing remaining +remeber remember +remebers remembers +remotley remotely +renderes renders +renewd renewed +reorienting reorientating +Repalcement Replacement +replys replies +reponsibility responsibility +requeusts requests +resently recently +resetted reset +resistent resistant +resognized recognized +resonable reasonable +resoure resource +responsability responsibility +responsivness responsiveness +resposible responsible +ressources resources +retreived retrieved +retreive retrieve +retults results +Rewritebles Rewritables +richt right +rigths rights +Rigt Right +saftey safety +satified satisfied +savely safely +savety safety +scalled scaled +scather scatter +scenerio scenario +sceptical skeptical +schduler scheduler +Sectionning Sectioning +selction selection +selectde selected +sensistve sensitive +separed separated +separeted separated +sepcified specified +seperated separated +seperately separately +seperate separate +seperate separate + +#INCORRECT SPELLING CORRECTION + +Seperate Separate +seperation separation +seperatly separately +seperator separator +sequencially sequentially +sertificate certificate +serveral several +setted set +sheduled scheduled +sheme scheme +shorctuts shortcuts +shoud should +shouldnt shouldn't +Shouldnt Shouldn't +shure sure +Similarily Similarly +Similiarly Similarly +similiar similar +simlar similar +simpliest simplest +simultaneuosly simultaneously +skript script +slewin slewing +smaple sample +Sombody Somebody +somehwat somewhat +soure source +sparcely sparsely +speakiing speaking +specefied specified +specfic specific +specfied specified +specialised specialized +specifc specific +specifed specified +Specificiation Specification +specifieing specifying +specifing specifying +specifiy specify +Specifiy Specify +speficied specified +speling spelling +spezifying specifying +sprectrum spectrum +standar standard +Startp Startup +Statfeul Stateful +statfull stateful +storeys storys +straighforward straightforward +streched stretched +Streches Stretches +Strech Stretch + +#INCORRECT SPELLING CORRECTION + +Striked Stroked +stuctures structures +styleshets stylesheets +subcribed subscribed +subdirectorys subdirectories +subseqently subsequently +Substracting Subtracting +subystem subsystem +succeded succeeded +succesfully successfully +succesful successful +succesive successive +succesor successor +successfull successful +sucessfull successful +sucessfully successfully +sucessfuly successfully +sucess success +sufficent sufficient +superflous superfluous +supossed supposed +supressed suppressed +supress suppress +suprised surprised +susbstitute substitute +swaped swapped +synchonization synchronization +synchronisation synchronization +Synchronisation Synchronization +synchronised synchronized +synchronises synchronizes +synchronise synchronize +synchronyze synchronize +Syncronization Synchronization +syncronized synchronized +Syncronizes Synchronizes +syncronize synchronize +syncronizing synchronizing +Syncronizing Synchronizing +syncronous synchronous +syncrounous synchronous +syndrom syndrome +syntex syntax +synthetizer synthesizer +syntheziser synthesizer +sytem system +talbs tables +talse false +tecnology technology +temparary temporary +Tempertures Temperatures +terminatin terminating + +#INCORRECT SPELLING CORRECTION + +texured textured +themc them +thet that +threshholds thresholds +threshhold threshold +throtte throttle +throught through +throuth through +tiggered triggered +tihs this +timditiy timidity +Timdity Timidity +timming timing +tranceiver transceiver +Tranfers Transfers +tranfer transfer +Tranlate Translate +tranlation translation +transalted translated +transation transaction +transfering transferring +transferrable transferable +transmiter transmitter +transmiting transmitting +transmition transmission +transmittion transmission +transparancy transparency +transparant transparent +trasfered transferred +traveller traveler +travelling traveling +triggerg triggering +triggerred triggered +truely truly +trys tries +uglyness ugliness +unabiguous unambiguous +unaccesible unaccessible +unallowed disallowed +unamed unnamed +unathorized unauthorized +uncrypted unencrypted +Uncutt Uncut +underlieing underlying +underrrun underrun +undesireable undesirable +undestood understood +Undexpected Unexpected +undoedne undid +unecessary unnecessary +unexperienced inexperienced +unexperience inexperience +unfortunatly unfortunately + +#INCORRECT SPELLING CORRECTION + +Unfortunatly Unfortunately +uniq unique +unitialized uninitialized +unkown unknown +Unmoveable Unmovable +unneccessary unnecessary +unneccessay unnecessary +unsellectected unselected +unsuccesful unsuccessful +unuseable unusable +unusuable unusable +unvailable unavailable +uploades uploads +upppercase uppercase +usally usually +usefull useful +usere user +usuable usable +usuallly usually +Usualy Usually +utilisation utilization +vaild valid +valied valid +valueable valuable +varb verb +vays ways +verfication verification +verically vertically +versins versions +verticaly vertically +verticies vertices +Veryify Verify +vicitim victim +visualisations visualizations +visualisation visualization +Visualisation Visualization +visualise visualize +visul visual +volonteer volunteer +Volumen Volume +Voribis Vorbis +vrtual virtual +waranty warranty +watseful wasteful +weigth weight +wheter whether +whicn which +whishes wishes +whitch which +whith with + +#INCORRECT SPELLING CORRECTION + +Wiazrd Wizard +wich which +wich which +wierd weird +wieving viewing +wiev view +wih with +willl will +wnat want +workimg working +workstatio workstation +woud would +wouldd would +writting writing +Writting Writing +yeld yield +yorself yourself +you'ld you would +yourContryCode yourCountryCode + diff --git a/scripts/kde.supp b/scripts/kde.supp new file mode 100644 index 00000000..213d9bb1 --- /dev/null +++ b/scripts/kde.supp @@ -0,0 +1,155 @@ +# +# Some valgrind suppressions handy for ignoring stuff we don't care +# about when valgrinding kde applications +# +# Library paths and versions from debian unstable, YMMV +# + +# +# pthread errors +# + +{ + pthread_mutex_unlock + core:PThread + fun:__pthread_mutex_unlock +} + +{ + pthread_error/pthread_mutex_destroy + core:PThread + fun:pthread_error + fun:__pthread_mutex_destroy +} + +# +# ld.so errors +# + +{ + strchr/decompose_rpath/_dl_map_object + MemCheck:Cond + fun:strchr + fun:decompose_rpath + fun:_dl_map_object +} + +{ + strlen/libc/_dl_catch_error + MemCheck:Cond + fun:strlen + fun:_dl_open + obj:*libdl-2*.so + fun:_dl_catch_error* +} + +{ + strchr/libc/_dl_catch_error + MemCheck:Cond + fun:strchr + obj:*libc-2.2.?.so + fun:_dl_catch_error +} + +{ + strrchr/_dl_map_object_from_fd/_dl_map_object + MemCheck:Cond + fun:strrchr + fun:_dl_map_object_from_fd + fun:_dl_map_object +} + +{ + strlen/_dl_signal_cerror/_dl_lookup_symbol_internal + Memcheck:Cond + fun:strlen + fun:_dl_signal_cerror + fun:_dl_lookup_symbol_internal + fun:*dlsym +} + +# +# X library errors +# + +{ + libXft(Cond) + MemCheck:Cond + obj:/usr/X11R6/lib/libXft.so.1.1 + obj:/usr/X11R6/lib/libXft.so.1.1 +} + +{ + write(buf)/libc/libICE + Memcheck:Param + write(buf) + fun:__GI___libc_write + fun:_IceTransWrite + fun:_IceWrite + fun:IceFlush +} + +{ + write(buf)/libc/libX11 + Memcheck:Param + write(buf) + fun:__GI___libc_write + fun:_X11TransWrite + fun:_XFlushInt + fun:_XFlush +} + +{ + write(buf)/libc/libX11 + Memcheck:Param + write(buf) + fun:__GI___libc_write + fun:_X11TransWrite + fun:_XFlushInt + fun:_XReply +} + +{ + writev(vector[...]) + Memcheck:Param + writev(vector[...]) + fun:*writev + obj:libX11.so.* + fun:_X11TransWritev + fun:_XSend +} + +# +# SSL errors +# + +{ + various1/libcrypto + Memcheck:Value4 + obj:*libcrypto.so.0.9.7 +} + +{ + various2/libcrypto + Memcheck:Cond + obj:*libcrypto.so.0.9.7 +} + +{ + ssl3_read_bytes1/libssl + Memcheck:Cond + fun:memcpy + fun:ssl3_read_bytes +} + +{ + ssl3_read_bytes2/libssl + Memcheck:Cond + fun:ssl3_read_bytes +} + +{ + ssl3_get_message/libssl + Memcheck:Cond + fun:ssl3_get_message +} diff --git a/scripts/kdedoc b/scripts/kdedoc new file mode 100755 index 00000000..0dc20a66 --- /dev/null +++ b/scripts/kdedoc @@ -0,0 +1,48 @@ +#!/bin/sh +# Run from command line, to open a kde help page in kfm/konqueror +# Argument : The classname (case sensitive !). +# Both doxygen and kdoc docs are supported. + +# You can edit this line to set the directory holding your KDE docs, or you +# can use the environment variable KDEDOCS to avoid future conflicts with this +# file if the default changes. +KDEDOCS=${KDEDOCS:-"$KDEDIR/share/doc/HTML/en/kdelibs-apidocs"} + +if [ $# = 1 ]; then + if [ -e "$KDEDOCS/doxygen.css" ]; then + # Docs are laid out in doxygen style. + if [ -f "$KDEDOCS/class$1.html" ]; then + kfmclient exec "$KDEDOCS/class$1.html" + elif [ -f "$KDEDOCS"/*/html/"class$1.html" ]; then + kfmclient exec "$KDEDOCS"/*/html/"class$1.html" + else + classstring=`echo "$1" | sed -e 's/::/_1_1/'` + if [ -f "$KDEDOCS/class$classstring.html" ]; then + kfmclient exec "$KDEDOCS/class$classstring.html" + elif [ -f "$KDEDOCS"/*/html/"class$classstring.html" ]; then + kfmclient exec "$KDEDOCS"/*/html/"class$classstring.html" + elif [ -f "$KDEDOCS"/class*_1_1"$1.html" ]; then + kfmclient exec "$KDEDOCS"/class*_1_1"$1.html" + elif [ -f "$KDEDOCS"/*/html/class*_1_1"$1.html" ]; then + kfmclient exec "$KDEDOCS"/*/html/class*_1_1"$1.html" + else + echo "No class $1 in $KDEDOCS/*" + exit 1 + fi + fi + elif [ -e "$KDEDOCS/kdecore/index.html" ]; then + # Docs are laid out in kdoc style. + if [ -f "$KDEDOCS"/*/"$1.html" ]; then + kfmclient exec "$KDEDOCS"/*/"$1.html" + else + echo "No class $1 in $KDEDOCS/*" + exit 1 + fi + else + echo "$KDEDOCS does not appear to contain your KDE docs." + exit 1 + fi +else + echo "Usage : $0 <classname>" + exit 1 +fi diff --git a/scripts/kdekillall b/scripts/kdekillall new file mode 100755 index 00000000..deb5aef5 --- /dev/null +++ b/scripts/kdekillall @@ -0,0 +1,28 @@ +#! /bin/sh + +case $1 in + -*) signal=$1; shift;; +esac +if [ $# = 0 ]; then + echo "Usage: $0 [-<signal>] <process>" + echo 'Kills the process "kdeinit: <process> with signal <signal>"' + echo "if <signal> is not specified, it defaults to SIGTERM," + echo "see kill -l for a list of possible signals" +else + list=$(ps auwx | grep $USER | awk "/[k]deinit: $1/ {print \$2}") + if test -z "$list"; then + # on newer Linux kernels (>= 2.6.10) KDE is able to use + # prctl(PR_SET_NAME) to change the process name... + list=$(ps auwx | grep $USER | awk "/\[kdeinit\] $1/ {print \$2}") + fi + if test -z "$list"; then + # with KDE 3.4 we changed the view again... + list=$(ps auwx | grep $USER | awk "/$1 \[kdeinit\]/ {print \$2}") + fi + if test -n "$list"; then + kill $signal $list + else + echo 'No process killed' + exit 1 + fi +fi diff --git a/scripts/kdelnk2desktop.py b/scripts/kdelnk2desktop.py new file mode 100755 index 00000000..9d96d87c --- /dev/null +++ b/scripts/kdelnk2desktop.py @@ -0,0 +1,21 @@ +#! /usr/bin/env python + +import os, sys, string + +def help(): + print "Usage: %s <filename>.kdelnk ..." + +if len(sys.argv) < 2: + help() + sys.exit() + +for fn in sys.argv[1:]: + print "Doing %s ..." % fn + f = open(fn, 'r').readlines() + + if string.find(f[0], "# KDE Config") == 0: + p = open(fn, 'w') + p.writelines(f[1:]) + p.close() + + os.rename(fn, fn[:-6]+'desktop') diff --git a/scripts/kdemangen.pl b/scripts/kdemangen.pl new file mode 100755 index 00000000..69951c88 --- /dev/null +++ b/scripts/kdemangen.pl @@ -0,0 +1,250 @@ +#! /usr/bin/env perl + +# kdemangen.pl +# Copyright (C) 2003 Dominique Devriese <devriese@kde.org> + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + + +# Here's a little explanation about this script: +# In order to fix long-standing Debian bug #116485, I've written a +# script that takes a KDE app, and generates a nice man page.. It uses +# the app's "--author" and "--help-all" output, along with a description +# from Debian's control file to get the data. I think the script works +# great, the man pages look almost hand-written ;) I encourage you all +# to try this out, and very much welcome any feedback, especially as to +# how to integrate this into either the Debian KDE packaging system or +# the KDE build system.. + +# The idea to do this with a script allows us to easily keep the man +# pages up to date, and is generally very low-trouble for the +# developer... + +# The script is attached at the bottom.. + +# USAGE: +# Suppose you wanted to generate a man page for the KDE-Edu program +# kalzium.. Then you would +# 1 cd to /path/to/kde/srcs/kdeedu/debian ( necessary so the script +# finds the Debian control file.. ) +# 2 run "/path/to/kdemangen.pl $(which kstars) > kstars.1" +# 3 run "man ./kstars.1" to check out the generated page.. + +# PROBLEMS: +# Only works for full KDE applications that use KCmdLineArgs ( +# inherent to my approach, but most KDE apps fulfill this requirement +# ) + +use warnings; +use strict; + +sub optionstonroff + { + my $options = shift; + my $ret = ""; + foreach( split /\n/, $options ) + { + if( /^ (--?[[:alpha:]]+, )?(--[[:alpha:]-]*|-[[:alpha:]])( <[[:alpha:] ]*>| [[:alpha:]]*)? *(.*)$/ ) + { + my $short; + my $long; + my $arg; + my $desc; + if( $1 ) { $short = $1; } else { $short = ""; }; + if( $2 ) { $long = $2; } else { $long = ""; }; + if( $3 ) { $arg = $3; } else { $arg = ""; }; + if( $4 ) { $desc = $4; } else { $desc = ""; }; + $short =~ s/-/\\-/g; + $long =~ s/-/\\-/g; + $arg =~ s/-/\\-/g; + $ret .= ".TP\n"; + $ret .= ".B $short $long $arg\n"; + $ret .= "$desc\n"; + } + elsif( /^ ([[:alpha:]]+) +(.*)$/ ) + { + $ret .= ".TP\n"; + $ret .= ".B $1\n"; + $ret .= "$2\n"; + } + elsif( /^ +(.*)$/ ) + { + $ret .= "$1\n"; + } + elsif( /^(.*)$/ ) + { + $ret .= ".SS $1\n"; + # this means a header like "Qt Options:" I'm wondering + # what to do with this, I don't know enough nroff to + # format it nicely, I'm affraid.. + } + } + return $ret; + }; + +sub sortoptionsfromnroff { + # Zack Cerza + + # Rather than redo Dominique's optionstonroff(), I decided + # to make this function to sort the options sections created + # by his function. + + # What it does is read line-by-line and first determine which + # section it's looking at via the ".SS <SECTION>" lines. Once + # it knows, it sets a "$in_<SECTION>" variable to "1" and + # begins to write the section data into $<SECTION>. When it + # gets to a line that contains only ".SS ", it sets + # $in_<SECTION> to "0" and continues. + + # It's a little messy, but it's the only way I could + # get it to work with what little knowledge I had. + + # This is the first time I've used Perl. Be kind. + + my $options = shift; + my $ret=""; + + my $in_gen_opts = "0"; + my $gen_opts = ""; + my $in_qt_opts = "0"; + my $qt_opts = ""; + my $in_kde_opts = "0"; + my $kde_opts = ""; + my $in_opts = "0"; + my $opts = ""; + my $in_args = "0"; + my $args = ""; + + foreach ( split /\n/, $options ) { + if( $in_gen_opts == "1" ) { + if( /^(\.SS )$/ ) { $in_gen_opts = "0"; } + $gen_opts .= $_; + $gen_opts .= "\n"; + } + if( /^(\.SS.+Generic options:)$/ ) + { $in_gen_opts = "1"; $gen_opts .= $1; $gen_opts .= "\n"; } + + if( $in_qt_opts == "1" ) { + if( /^(\.SS )$/ ) { $in_qt_opts = "0"; } + $qt_opts .= $_; + $qt_opts .= "\n"; + } + if( /^(\.SS.+Qt options:)$/ ) + { $in_qt_opts = "1"; $qt_opts .= $1; $qt_opts .= "\n"; } + + if( $in_kde_opts == "1" ) { + if( /^(\.SS )$/ ) { $in_kde_opts = "0"; } + $kde_opts .= $_; + $kde_opts .= "\n"; + } + if( /^(\.SS.+KDE options:)$/ ) + { $in_kde_opts = "1"; $kde_opts .= $1; $kde_opts .= "\n"; } + + if( $in_opts == "1" ) { + if( /^(\.SS )$/ ) { $in_opts = "0"; } + $opts .= $_; + $opts .= "\n"; + } + if( /^(\.SS.+Options:)$/ ) + { $in_opts = "1"; $opts .= $1; $opts .= "\n"; } + + if( $in_args == "1" ) { + if( /^(\.SS )$/ ) { $in_args = "0"; } + $args .= $_; + $args .= "\n"; + } + if( /^(\.SS.+Arguments:)$/ ) + { $in_args = "1"; $args .= ".SS\n"; $args .= $1; $args .= "\n"; } + } + $ret .= $args; + $ret .= $opts; + $ret .= $gen_opts; + $ret .= $kde_opts; + $ret .= $qt_opts; + return $ret; + }; + +sub usage + { + print "This script generates a nice manual page for a KDE app which uses KCmdLineArgs..\n"; + print "USAGE: $0 app\n"; + print "There's more information about how to use this script in the comments at the front of the source..\n" + }; + +if( $#ARGV < 0 ){ + usage(); + exit 1; +} + +my $runapp = "$ARGV[0]"; +if ( ! -x $runapp ) + { + print "Error: $runapp is not executable.\n"; + exit 1; + } +else { $runapp = "KDE_LANG=en_US $runapp"; }; + +my $shortdescription = `$runapp --help | sed -ne '3p'`; +chomp $shortdescription; + +my $synopsis = `$runapp --help | sed -n '1p' | sed -e 's/[^:]*: //'`; +chomp $synopsis; +$synopsis =~ s/-/\\-/g; +my $appname = $synopsis; +$appname =~ s/ .*$//; +my $ucappname = uc $appname; + +my $options = `$runapp --help-all | sed -e '1,4d'`; +$options = optionstonroff( $options ); +$options = sortoptionsfromnroff( $options ); + +my $timespec = ucfirst `date '+%b %G'`; +chomp $timespec; + +my $description = $shortdescription; +if( -r "control" ) + { + $description = `cat control | sed -ne '/^Description:/,/^\$/p' | egrep -v '^\\w*:.*\$' | sed -e 's/^ //' | sed -e 's/^\\.//'`; +# leads to problems in some cases :( +# $description =~ s/KDE ?/\n.SM KDE\n/g; + } + +my $authors = `$runapp --author | sed -ne '2,\$p' | sed -e '\$d' | sed -e 's/^ *//'`; +$authors =~ s/\n/\n.br\n/g; + +print <<EOF; +.\\\" This file was generated by kdemangen.pl +.TH $ucappname 1 \"$timespec\" \"K Desktop Environment\" \"$shortdescription\" +.SH NAME +$appname +\\- $shortdescription +.SH SYNOPSIS +$synopsis +.SH DESCRIPTION +$description +.SH OPTIONS +$options +.SH SEE ALSO +Full user documentation is available through the KDE Help Center. You can also enter the URL +.BR help:/$appname/ +directly into konqueror or you can run +.BR "`khelpcenter help:/$appname/'" +from the command-line. +.br +.SH AUTHORS +.nf +$authors +EOF diff --git a/scripts/kdesvn-build b/scripts/kdesvn-build new file mode 100755 index 00000000..fcd3970b --- /dev/null +++ b/scripts/kdesvn-build @@ -0,0 +1,4286 @@ +#!/usr/bin/perl -w + +#Pod documentation: + +=head1 NAME + +=over + +=item B<kdesvn-build> - automate the kde svn build process + +=back + +=head1 SYNOPSIS + +=over + +=item B<kdesvn-build> I<[options]...> I<[modules]...> + +=back + +=head1 DESCRIPTION + +The B<kdesvn-build> script is used to automate the download, build, +and install process for KDE (using Subversion). + +It is recommended that you first setup a F<.kdesvn-buildrc> file +in your home directory. Please refer to B<kdesvn-build> help file +in KDE help for information on how to write F<.kdesvn-buildrc>, +or consult the sample file which should have been included +with this program. If you don't setup a F<.kdesvn-buildrc>, a +default set of options will be used, and a few modules will be +built by default. + +After setting up F<.kdesvn-buildrc>, you can run this program from +either the command-line or from cron. It will automatically +download the modules from Subversion, create the build +system, and configure and make the modules you tell it to. +You can use this program to install KDE as well, +if you are building KDE for a single user. Note that B<kdesvn-build> +will try to install the modules by default. + +If you DO specify a package name, then your settings will still be +read, but the script will try to build / install the package +regardless of F<.kdesvn-buildrc> + +kdesvn-build reads options in the following order: + +=over + +=item 1. From the command line. + +=item 2. From the file F<kdesvn-buildrc> in the current directory. Note that + the file is not a hidden file. + +=item 3. From the file F<~/.kdesvn-buildrc>. + +=item 4. From a set of internal options. + +=back + +This utility is part of the KDE Software Development Kit. + +=head1 OPTIONS + +=over + +=item B<--quiet>, B<-q> + +With this switch kdesvn-build will only output a general overview of the build +process. Progress output is still displayed if available. + +=item B<--really-quiet> + +With this switch only warnings and errors will be output. + +=item B<--verbose>, B<-v> + +Be very detailed in what is going on, and what actions kdesvn-build is taking. +Only B<--debug> is more detailed. + +=item B<--no-svn> + +Skip contacting the Subversion server. + +=item B<--no-build> + +Skip the build process. + +=item B<--no-install> + +Don't automatically install after build. + +=item B<--svn-only> + +Update from Subversion only (Identical to B<--no-build> at this point). + +=item B<--build-only> + +Build only, do not perform updates or install. + +=item B<--rc-file=E<lt>filenameE<gt>> + +Read configuration from filename instead of default. + +=item B<--debug> + +Activates debug mode. + +=item B<--pretend>, B<-p> + +Do not contact the Subversion server, run make, or create / delete files +and directories. Instead, output what the script would have done. + +=item B<--nice=E<lt>valueE<gt>> + +Allow you to run the script with a lower priority. The default value is +10 (lower priority by 10 steps). + +=item B<--prefix=/kde/path> + +This option is a shortcut to change the setting for kdedir from the +command line. It implies B<--reconfigure>. + +=item B<--color> + +Add color to the output. + +=item B<--no-color> + +Remove color from the output. + +=item B<--resume> + +Tries to resume the make process from the last time the script was run, +without performing the Subversion update. + +=item B<--resume-from=E<lt>pkgE<gt>> + +Starts building from the given package, without performing the Subversion +update. + +=item B<--revision=E<lt>revE<gt>>, B<-r=E<lt>revE<gt>> + +Forces update to revision <rev> from Subversion. + +=item B<--refresh-build> + +Start the build from scratch. This means that the build directory for the +module B<will be deleted> before make -f Makefile.cvs is run again. You can +use B<--recreate-configure> to do the same thing without deleting the module +build directory. + +=item B<--reconfigure> + +Run configure again, but don't clean the build directory or re-run +make -f Makefile.cvs. + +=item B<--recreate-configure> + +Run make -f Makefile.cvs again to redo the configure script. The build +directory is not deleted. + +=item B<--no-rebuild-on-fail> + +Do not try to rebuild a module from scratch if it failed building. Normally +kdesvn-build will try progressively harder to build the module before giving +up. + +=item B<--build-system-only> + +Create the build infrastructure, but don't actually perform the build. + +=item B<--install> + +Try to install the packages passed on the command line, or all packages in +F<~/.kdesvn-buildrc> that don't have manual-build set. Building and +Subversion updates are not performed. + +=item B<--E<lt>optionE<gt>=> + +Any unrecognized options are added to the global configuration, overriding +any value that may exist. + +For example, B<--svn-server=http://path.to.svn.server/> would change the +setting of the global B<svn-server> option for this instance of kdesvn-build. + +=item B<--E<lt>moduleE<gt>,E<lt>optionE<gt>=> + +Likewise, allow you to override any module specific option from the +command line. + +Example: B<--kdelibs,use-unsermake=false> would disable unsermake for the +kdelibs module. + +=item B<--help> + +Display the help and exit. + +=item B<--author> + +Output the author(s)'s name. + +=item B<--version> + +Output the program version. + +=back + +=head1 EXAMPLES + +=over + +=item B<kdesvn-build> + +=item B<kdesvn-build> I<--no-svn kdelibs> + +=item B<kdesvn-bulid> I<--refresh-build> I<kdebase> + +=back + +=head1 BUGS + +Since kdesvn-build doesn't generally save information related to the build and +prior settings, you may need to manually re-run kdesvn-build with a flag like +B<--recreate-configure> if you change some options, including B<use-unsermake>. + +Please use KDE bugzilla at http://bugs.kde.org for information and +reporting bugs. + +=head1 SEE ALSO + +You can find additional information at B<kdesvn-build> home page, +F<http://kdesvn-build.kde.org/>, or using kdesvn-build +docbook documentation, using the help kioslave, F<help:/kdesvn-build>. + +=head1 AUTHOR + +Michael Pyne <michael.pyne@kdemail.net> + +Man page written by: +Carlos Leonhard Woelz <carlos.woelz@kdemail.net> + +=cut + +# Script to handle building KDE from Subversion. All of the configuration is +# stored in the file ~/.kdesvn-buildrc. +# +# Please also see the documentation that should be included with this program, +# in doc.html +# +# Copyright (c) 2003, 2004, 2005 Michael Pyne. <michael.pyne@kdemail.net> +# Home page: http://kdesvn-build.kde.org/ +# +# You may use, alter, and redistribute this software under the terms +# of the GNU General Public License, v2 (or any later version). +# +# TODO: It would be better to have lockfiles in each directory as it's +# being updated, instead of having one big lock for the script. + +use strict; +use warnings; +use Fcntl; # For sysopen constants +use POSIX 'strftime'; +use File::Find; # For our lndir reimplementation. +use Errno qw(:POSIX); + +# Debugging level constants. +use constant { + DEBUG => 0, + WHISPER => 1, + INFO => 2, + NOTE => 3, + WARNING => 4, + ERROR => 5, +}; + +# Some global variables +# Remember kids, global variables are evil! I only get to do this +# because I'm an adult and you're not! :-P +# Options that start with a # will replace values with the same name, +# if the option is actually set. +my %package_opts = ( + 'global' => { + "apidox" => "", + "apply-qt-patches" => "", + "binpath" => "/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin", + "branch" => "", + "build-dir" => "build", + "build-system-only" => "", + "checkout-only" => "", + "configure-flags" => "--enable-debug", + "colorful-output" => 1, # Use color by default. + "cxxflags" => "-pipe", + "debug" => "", + "debug-level" => INFO, + "dest-dir" => '${MODULE}', # single quotes used on purpose! + "disable-agent-check" => 0, # If true we don't check on ssh-agent + "do-not-compile" => "", + "email-address" => "", + "email-on-compile-error" => "", + "install-after-build" => "1", # Default to true + "inst-apps" => "", + "kdedir" => "$ENV{HOME}/kde", + "libpath" => "", + "log-dir" => "log", + "make-install-prefix" => "", # Some people need sudo + "make-options" => "-j2", + "manual-build" => "", + "manual-update" => "", + "module-base-path" => "", # Used for tags and branches + "niceness" => "10", + "no-svn" => "", + "no-rebuild-on-fail" => "", + "override-url" => "", + "prefix" => "", # Override installation prefix. + "pretend" => "", + "qtdir" => "$ENV{HOME}/kdesvn/build/qt-copy", + "reconfigure" => "", + "recreate-configure" => "", + "refresh-build" => "", + "remove-after-install"=> "none", # { none, builddir, all } + "revision" => 0, + "set-env" => { }, # Hash of environment vars to set + "source-dir" => "$ENV{HOME}/kdesvn", + "stop-on-failure" => "", + "svn-server" => "svn://anonsvn.kde.org/home/kde", + "tag" => "", + "unsermake-options" => "--compile-jobs=2 -p", + "unsermake-path" => "unsermake", + "use-unsermake" => "1", # Default to true now, we may need a blacklist + } +); + +# This is a hash since Perl doesn't have a "in" keyword. +my %ignore_list; # List of packages to refuse to include in the build list. + +# update and build are lists since they support an ordering, which can't be +# guaranteed using a hash unless I want a custom sort function (which isn't +# necessarily a horrible way to go, I just chose to do it this way. +my @update_list; # List of modules to update/checkout. +my @build_list; # List of modules to build. + +# Dictionary of lists of failed modules, keyed by the name of the operation +# that caused the failure (e.g. build). Note that output_failed_module_lists +# uses the key name to display text to the user so it should describe the +# actual category of failure. You should also add the key name to +# output_failed_module_lists since it uses its own sorted list. +my @fail_display_order = qw/build update install/; +my %fail_lists = ( + 'build' => [ ], + 'install' => [ ], + 'update' => [ ], +); + +my $install_flag; # True if we're in install mode. +my $BUILD_ID; # Used by logging subsystem to create a unique log dir. +my $LOG_DATE; # Used by logging subsystem to create logs in same dir. +my @rcfiles = ("./kdesvn-buildrc", "$ENV{HOME}/.kdesvn-buildrc"); +my $rcfile; # the file that was used; set by read_options + +# Colors +my ($RED, $GREEN, $YELLOW, $NORMAL, $BOLD) = ("") x 5; + +# Subroutine definitions + +# I swear Perl must be the only language where the docs tell you to use a +# constant that you'll never find exported without some module from CPAN. +use constant PRIO_PROCESS => 0; + +# I'm lazy and would rather write in shorthand for the colors. This sub +# allows me to do so. Put it right up top to stifle Perl warnings. +sub clr($) +{ + my $str = shift; + + $str =~ s/g\[/$GREEN/g; + $str =~ s/]/$NORMAL/g; + $str =~ s/y\[/$YELLOW/g; + $str =~ s/r\[/$RED/g; + $str =~ s/b\[/$BOLD/g; + + return $str; +} + +# Subroutine which returns true if pretend mode is on. Uses the prototype +# feature so you don't need the parentheses to use it. +sub pretending() +{ + return get_option('global', 'pretend'); +} + +# Subroutine which returns true if debug mode is on. Uses the prototype +# feature so you don't need the parentheses to use it. +sub debugging() +{ + return get_option('global', 'debug-level') <= DEBUG; +} + +# The next few subroutines are used to print output at different importance +# levels to allow for e.g. quiet switches, or verbose switches. The levels are, +# from least to most important: +# debug, whisper, info (default), note (quiet), warning (very-quiet), and error. +# +# You can also use the pretend output subroutine, which is emitted if, and only +# if pretend mode is enabled. +# +# clr is automatically run on the input for all of those functions. +# Also, the terminal color is automatically reset to normal as well so you don't +# need to manually add the ] to reset. + +# Subroutine used to actually display the data, calls clr on each entry first. +sub print_clr(@) +{ + print clr $_ foreach (@_); + print clr "]\n"; +} + +sub debug(@) +{ + print_clr @_ if debugging; +} + +sub whisper(@) +{ + print_clr @_ if get_option('global', 'debug-level') <= WHISPER; +} + +sub info(@) +{ + print_clr @_ if get_option('global', 'debug-level') <= INFO; +} + +sub note(@) +{ + print_clr @_ if get_option('global', 'debug-level') <= NOTE; +} + +sub warning(@) +{ + print_clr @_ if get_option('global', 'debug-level') <= WARNING; +} + +# This sub has the additional side effect of printing the errno value if it +# is set. +sub error(@) +{ + print STDERR (clr $_) foreach (@_); + print " $!\n" if $!; +} + +sub pretend(@) +{ + print_clr @_ if pretending; +} + +# Subroutine to handle removing the lock file upon receiving a signal +sub quit_handler +{ + note "Signal received, terminating."; + finish(5); +} + +# Subroutine that returns the path of a file used to output the results of the +# build process. It accepts one parameter, which changes the kind of file +# returned. If the parameter is set to 'existing', then the file returned is +# the latest file that exists, or undef if no log has been created yet. This +# is useful for the --resume mode. All other values will return the name if a +# file that does not yet exist. +# +# All files will be stored in the log directory. +sub get_output_file +{ + my $logdir; + my $mode; + $mode = shift or $mode = ''; + my $fname; + + debug "get_output_file in mode $mode"; + + if ($mode eq 'existing') + { + # There's two ways of finding the old file. Searching backwards with + # valid combinations of the date and build id, or just reading in the + # name from a known file or location. Since the latter option is much + # easier, that's what I'm going with. Note that this depends on the + # latest symlink being in place. + $logdir = get_subdir_path ('global', 'log-dir'); + $fname = "$logdir/latest/build-status"; + + debug "Old build status file is $fname"; + + # The _ at the end returns the cached file stats to avoid multiple + # stat() calls. + return "" if not -e $fname or not -r _; + + return $fname; + } + + # This call must follow the test above, because it changes the 'latest' + # symlink leading to failures later. + $logdir = get_log_dir('global'); + + $fname = "$logdir/build-status"; + debug "Build status file is $fname"; + + return $fname; +} + +# Subroutine to retrieve a subdirecty path for the given module. +# First parameter is the name of the module, and the second +# parameter is the option key (e.g. build-dir or log-dir). +sub get_subdir_path +{ + my $module = shift; + my $option = shift; + my $dir = get_option($module, $option); + + # If build-dir starts with a slash, it is an absolute path. + return $dir if $dir =~ /^\//; + + # If it starts with a tilde, expand it out. + if ($dir =~ /^~/) + { + $dir =~ s/^~/$ENV{'HOME'}/; + } + else + { + # Relative directory, tack it on to the end of $kdesvn. + my $kdesvndir = get_kdesvn_dir(); + $dir = "$kdesvndir/$dir"; + } + + return $dir; +} + +# Subroutine to return the name of the destination directory for the checkout +# and build routines. Based on the dest-dir option. The return value will be +# relative to the src/build dir. The user may use the '$MODULE' or '${MODULE}' +# sequences, which will be replaced by the name of the module in question. +# +# The first parameter should be the module name. +sub get_dest_dir +{ + my $module = shift; + my $dest_dir = get_option($module, 'dest-dir'); + + $dest_dir =~ s/(\${MODULE})|(\$MODULE\b)/$module/g; + + return $dest_dir; +} + +# Convienience subroutine to get the source root dir. +sub get_kdesvn_dir +{ + return get_option ('global', 'source-dir'); +} + +# Function to work around a Perl language limitation. +# First parameter is the list to search. +# Second parameter is the value to search for. +# Returns true if the value is in the list +sub list_has(\@$) +{ + my ($list_ref, $value) = @_; + return scalar grep ($_ eq $value, @{$list_ref}); +} + +# Subroutine to return the branch prefix. i.e. the part before the branch name +# and module name. +# +# The first parameter is the module in question. +# The second parameter should be 'branches' if we're dealing with a branch or +# 'tags' if we're dealing with a tag. +# +# Ex: 'kdelibs' => 'branches/KDE' +# 'kdevelop' => 'branches/kdevelop' +sub branch_prefix +{ + my $module = shift; + my $type = shift; + + # These modules seem to have their own subdir in /tags. + my @tag_components = qw/arts koffice amarok kst qt taglib/; + + # The map call adds the kde prefix to the module names because I don't feel + # like typing them all in. kdevelop and konstruct are special cases. + my @kde_module_list = ((map {'kde' . $_} qw/-i18n -common accessibility + addons admin artwork base bindings edu games graphics libs + multimedia network nonbeta pim sdk toys utils webdev/), 'kdevelop', + 'konstruct'); + + # KDE proper modules seem to use this pattern. + return "$type/KDE" if list_has(@kde_module_list, $module); + + # If we doing a tag just return 'tags' because the next part is the actual + # tag name, which is added by the caller, unless the module has its own + # subdirectory in /tags. + return "$type" if $type eq 'tags' and not list_has(@tag_components, $module); + + # Everything else. + return "$type/$module"; +} + +# Subroutine to return a module URL for a module using the 'branch' option. +# First parameter is the module in question. +# Second parameter is the type ('tags' or 'branches') +sub handle_branch_tag_option +{ + my ($module, $type) = @_; + my $svn_server = get_option($module, 'svn-server'); + my $branch = branch_prefix($module, $type); + my $branchname = get_option($module, 'tag'); + + if($type eq 'branches') + { + $branchname = get_option($module, 'branch'); + } + + # Remove trailing slashes. + $svn_server =~ s/\/*$//; + + return "$svn_server/$branch/$branchname/$module"; +} + +# Subroutine to return the appropriate SVN URL for a given module, based on +# the user settings. For example, 'kdelibs' -> https://svn.kde.org/home/kde/trunk/KDE/kdelibs +sub svn_module_url +{ + my $module = shift; + my $svn_server = get_option($module, 'svn-server'); + my $branch = get_option($module, 'module-base-path'); + + # Allow user to override normal processing of the module in a few ways, + # to make it easier to still be able to use kdesvn-build even when I + # can't be there to manually update every little special case. + if(get_option($module, 'override-url')) + { + return get_option($module, 'override-url'); + } + + if(get_option($module, 'tag')) + { + return handle_branch_tag_option($module, 'tags'); + } + + if(get_option($module, 'branch')) + { + return handle_branch_tag_option($module, 'branches'); + } + + # The following modules are in /trunk, not /trunk/KDE. There are others, + # but there are the important ones. The hash is associated with the value + # 1 so that we can do a boolean test by looking up the module name. + my @non_trunk_modules = qw(extragear kdenonbeta kdesupport koffice + playground qt-copy valgrind KDE kdereview www l10n); + + my $module_root = $module; + $module_root =~ s/\/.*//; # Remove everything after the first slash + + if (not $branch) + { + $branch = 'trunk/KDE'; + $branch = 'trunk' if list_has(@non_trunk_modules, $module_root); + } + + $branch =~ s/^\/*//; # Eliminate / at beginning of string. + $branch =~ s/\/*$//; # Likewise at the end. + + # Remove trailing slashes. + $svn_server =~ s/\/*$//; + + return "$svn_server/$branch/$module"; +} + +# Convienience subroutine to return the build directory for a module. Use +# this instead of get_subdir_path because this special-cases modules for you, +# such as qt-copy. +# TODO: From what I hear this hack is no longer necessary. Investigate this. +sub get_build_dir +{ + my $module = shift; + + # It is the responsibility of the caller to append $module! + return get_kdesvn_dir() if ($module eq 'qt-copy') and not get_option('qt-copy', 'use-qt-builddir-hack'); + return get_subdir_path($module, 'build-dir'); +} + +# Subroutine to return a list of the different log directories that are used +# by the different modules in the script. +sub get_all_log_directories +{ + my @module_list = keys %package_opts; + my %log_dict; + + # A hash is used to track directories to avoid duplicate entries. + unshift @module_list, "global"; + $log_dict{get_subdir_path($_, 'log-dir')} = 1 foreach @module_list; + + debug "Log directories are ", join (", ", keys %log_dict); + return keys %log_dict; +} + +# Subroutine to determine the build id for this invocation of the script. The +# idea of a build id is that we want to be able to run the script more than +# once in a day and still retain each set of logs. So if we run the script +# more than once in a day, we need to increment the build id so we have a +# unique value. This subroutine sets the global variable $BUILD_ID and +# $LOG_DATE for use by the logging subroutines. +sub setup_logging_subsystem +{ + my $min_build_id = "00"; + my $date = strftime "%F", localtime; # ISO 8601 date + my @log_dirs = get_all_log_directories(); + + for (@log_dirs) + { + my $id = "01"; + $id++ while -e "$_/$date-$id"; + + # We need to use a string comparison operator to keep + # the magic in the ++ operator. + $min_build_id = $id if $id gt $min_build_id; + } + + $LOG_DATE = $date; + $BUILD_ID = $min_build_id; +} + +# Convienience subroutine to return the log directory for a module. +# It also creates the directory and manages the 'latest' symlink. +# +# Returns undef on an error, or the name of the directory otherwise. +sub get_log_dir +{ + my $module = shift; + my $logbase = get_subdir_path($module, 'log-dir'); + my $logpath = "$logbase/$LOG_DATE-$BUILD_ID/$module"; + + $logpath = "$logbase/$LOG_DATE-$BUILD_ID" if $module eq 'global'; + + debug "Log directory for $module is $logpath"; + + if (not -e $logpath and not pretending and not super_mkdir($logpath)) + { + error "Unable to create log directory r[$logpath]"; + return undef; + } + + # Add symlink to the directory. + # TODO: This probably can result in a few dozen unnecessary calls to + # unlink and symlink, fix this. + if (not pretending) + { + unlink("$logbase/latest") if -l "$logbase/latest"; + symlink("$logbase/$LOG_DATE-$BUILD_ID", "$logbase/latest"); + } + + return $logpath; +} + +# This function returns true if the given option doesn't make sense with the +# given module. +# blacklisted($module, $option) +sub blacklisted +{ + my ($module, $option) = @_; + + # Known to not work. + my @unsermake_ban_list = qw/valgrind kde-common qt-copy kdebindings/; + + return list_has(@unsermake_ban_list, $module) if ($option eq 'use-unsermake'); + return 0; +} + +# This subroutine returns an option value for a given module. Some +# globals can't be overridden by a module's choice. If so, the +# module's choice will be ignored, and a warning will be issued. +# +# Option names are case-sensitive! +# +# First parameter: Name of module +# Second paramenter: Name of option +sub get_option +{ + my $module = shift; + my $option = shift; + my $global_opts = $package_opts{'global'}; + my $defaultQtCopyArgs = '-qt-gif -plugin-imgfmt-mng -thread -no-exceptions -debug -dlopen-opengl -plugin-sql-sqlite'; + my @lockedOpts = qw(source-dir svn-server qtdir libpath binpath kdedir + pretend disable-agent-check); + + # These options can't override globals + if (list_has(@lockedOpts, $option) or $module eq 'global') + { + return ${$global_opts}{"#$option"} if exists ${$global_opts}{"#$option"}; + return ${$global_opts}{$option}; + } + + # Don't even try this + return 0 if blacklisted($module, $option); + + my $ref = $package_opts{$module}; + + # Check for a sticky option + return $$ref{"#$option"} if exists $$ref{"#$option"}; + + # Next in order of precedence + if (defined ${$global_opts}{"#$option"} and not + ($module eq 'qt-copy' and $option eq 'configure-flags')) + { + return ${$global_opts}{"#$option"}; + } + + # No sticky options left. + # Configure flags and CXXFLAGS are appended to the global option + if (($module ne 'qt-copy' && $option eq 'configure-flags') + || $option eq 'cxxflags') + { + my $value = ${$global_opts}{$option}; + + if(defined $$ref{$option}) + { + my $modvalue = $$ref{$option}; + $value .= " $modvalue"; + } + + return $value; + } + + # As always qt-copy has to be difficult + if ($module eq 'qt-copy' and $option eq 'configure-flags') + { + return $defaultQtCopyArgs if not defined $$ref{$option}; + return $$ref{$option}; + } + + # Everything else overrides the global, unless of course it's not set. + # If we're reading for global options, we're pretty much done. + return $$ref{$option} if defined $$ref{$option}; + return ${$global_opts}{$option}; +} + +# Subroutine used to handle the checkout-only option. It handles +# updating subdirectories of an already-checked-out module. +# First parameter is the module, all remaining parameters are subdirectories +# to check out. +# +# Returns 0 on success, non-zero on failure. +sub update_module_subdirectories +{ + my $module = shift; + my $result; + + # If we have elements in @path, download them now + for my $dir (@_) + { + info "\tUpdating g[$dir]"; + $result = run_svn($module, "svn-up-$dir", [ 'svn', 'up', $dir ]); + return $result if $result; + } + + return 0; +} + +# Returns true if a module has a base component to their name (e.g. KDE/, +# extragear/, or playground). Note that modules that aren't in trunk/KDE +# don't necessary meet this criteria (e.g. kdereview is a module itself). +sub has_base_module +{ + my $module = shift; + + return $module =~ /^(extragear|playground|KDE)(\/[^\/]+)?$/; +} + +# Subroutine to return the directory that a module will be stored in. +# NOTE: The return value is a hash. The key 'module' will return the final +# module name, the key 'path' will return the full path to the module. The +# key 'fullpath' will return their concatenation. +# For example, with $module == 'KDE/kdelibs', and no change in the dest-dir +# option, you'd get something like: +# { +# 'path' => '/home/user/kdesvn/KDE', +# 'module' => 'kdelibs', +# 'fullpath' => '/home/user/kdesvn/KDE/kdelibs' +# } +# If dest-dir were changed to e.g. extragear-multimedia, you'd get: +# { +# 'path' => '/home/user/kdesvn', +# 'module' => 'extragear-multimedia', +# 'fullpath' => '/home/user/kdesvn/extragear-multimedia' +# } +# First parameter is the module. +# Second parameter is either source or build. +sub get_module_path_dir +{ + my $module = shift; + my $type = shift; + my $destdir = get_dest_dir($module); + my $srcbase = get_kdesvn_dir(); + $srcbase = get_build_dir($module) if $type eq 'build'; + + my $combined = "$srcbase/$destdir"; + + # Remove dup // + $combined =~ s/\/+/\//; + + my @parts = split(/\//, $combined); + my %result = (); + $result{'module'} = pop @parts; + $result{'path'} = join('/', @parts); + $result{'fullpath'} = "$result{path}/$result{module}"; + + return %result; +} + +sub get_fullpath +{ + my ($module, $type) = @_; + my %pathinfo = get_module_path_dir($module, $type); + + return $pathinfo{'fullpath'}; +} + +# Checkout a module that has not been checked out before, along with any +# subdirectories the user desires. +# The first parameter is the module to checkout (including extragear and +# playground modules), all remaining parameters are subdirectories of the +# module to checkout. +# Returns 0 on success, non-zero on failure. +sub checkout_module_path +{ + my ($module, @path) = @_; + my %pathinfo = get_module_path_dir($module, 'source'); + my $result; + my @args; + + if (not -e $pathinfo{'path'} and not super_mkdir($pathinfo{'path'})) + { + error "Unable to create path r[$pathinfo{path}]!"; + return 1; + } + + chdir($pathinfo{'path'}); + + push @args, ('svn', 'co'); + push @args, '-N' if scalar @path; + push @args, svn_module_url($module); + push @args, $pathinfo{'module'}; + + note "Checking out g[$module]"; + $result = run_svn($module, 'svn-co', \@args); + return $result if $result; + + chdir($pathinfo{'module'}) if scalar @path; + + return update_module_subdirectories($module, @path); +} + +# Update a module that has already been checked out, along with any +# subdirectories the user desires. +# The first parameter is the module to checkout (including extragear and +# playground modules), all remaining parameters are subdirectories of the +# module to checkout. +# Returns 0 on success, non-zero on failure. +sub update_module_path +{ + my ($module, @path) = @_; + my $fullpath = get_fullpath($module, 'source'); + my $result; + my @args; + + chdir $fullpath; + + push @args, ('svn', 'up'); + push @args, '-N' if scalar @path; + + note "Updating g[$module]"; + + $result = run_svn($module, 'svn-up', \@args); + + if($result) # Update failed, try svn cleanup. + { + info "\tUpdate failed, trying a cleanup."; + $result = safe_system('svn', 'cleanup'); + + return $result if $result; + + info "\tCleanup complete."; + # Now try again. + + $result = run_svn($module, 'svn-up-2', \@args); + } + + return $result if $result; + + # If the admin dir exists and is a soft link, remove it so that svn can + # update it if need be. The link will automatically be re-created later + # in the process if necessary by the build functions. + unlink ("$fullpath/admin") if -l "$fullpath/admin"; + + return update_module_subdirectories($module, @path); +} + +# Subroutine to run a command with redirected STDOUT and STDERR. First parameter +# is name of the log file (relative to the log directory), and the +# second parameter is a reference to an array with the command and +# its arguments +sub log_command +{ + my $pid; + my $module = shift; + my $filename = shift; + my @command = @{(shift)}; + my $logdir = get_log_dir($module); + + debug "log_command(): Module $module, Command: ", join(' ', @command); + + if (pretending) + { + pretend "\tWould have run g[", join (' ', @command); + return 0; + } + + if ($pid = fork) + { + # Parent + waitpid $pid, 0; + + # If the module fails building, set an internal flag in the module + # options with the name of the log file containing the error message. + my $result = $?; + set_error_logfile($module, "$filename.log") if $result; + + # If we are using the alias to a kdesvn-build function, it should have + # already printed the error message, so clear out errno (but still + # return failure status). + if ($command[0] eq 'kdesvn-build') + { + $! = 0; + } + + return $result; + } + else + { + # Child + if (not defined $logdir or not -e $logdir) + { + # Error creating directory for some reason. + error "\tLogging to std out due to failure creating log dir."; + } + + # Redirect stdout and stderr to the given file. + if (not debugging) + { +# Comment this out because it conflicts with make-install-prefix +# open (STDIN, "</dev/null"); + open (STDOUT, ">$logdir/$filename.log") or do { + error "Error opening $logdir/$filename.log for logfile."; + # Don't abort, hopefully STDOUT still works. + }; + } + else + { + open (STDOUT, "|tee $logdir/$filename.log") or do { + error "Error opening pipe to tee command."; + # Don't abort, hopefully STDOUT still works. + }; + } + + # Make sure we log everything. If the command is svn, it is possible + # that the client will produce output trying to get a password, so + # don't redirect stderr in that case. + open (STDERR, ">&STDOUT") unless $command[0] eq 'svn'; + + # Call internal function, name given by $command[1] + if($command[0] eq 'kdesvn-build') + { + debug "Calling $command[1]"; + + my $cmd = $command[1]; + splice (@command, 0, 2); # Remove first two elements. + + no strict 'refs'; # Disable restriction on symbolic subroutines. + if (not &{$cmd}(@command)) # Call sub + { + exit EINVAL; + } + + exit 0; + } + + # External command. + exec (@command) or do { + my $cmd_string = join(' ', @command); + error <<EOF; +r[b[Unable to execute "$cmd_string"]! + $! + +Please check your binpath setting (it controls the PATH used by kdesvn-build). +Currently it is set to g[$ENV{PATH}]. +EOF + # Don't use return, this is the child still! + exit 1; + }; + } +} + +# Subroutine to mark a file as being the error log for a module. This also +# creates a symlink in the module log directory for easy viewing. +# First parameter is the module in question. +# Second parameter is the filename in the log directory of the error log. +sub set_error_logfile +{ + my ($module, $logfile) = @_; + my $logdir = get_log_dir($module); + + return unless $logfile; + + set_option($module, '#error-log-file', "$logdir/$logfile"); + + # Setup symlink in the module log directory pointing to the appropriate + # file. Make sure to remove it first if it already exists. + unlink("$logdir/error.log") if -l "$logdir/error.log"; + + if(-e "$logdir/error.log") + { + # Maybe it was a regular file? + error "r[b[ * Unable to create symlink to error log file]"; + return 0; + } + + symlink "$logdir/$logfile", "$logdir/error.log"; +} + +# Subroutine to run make/unsermake with redirected STDOUT and STDERR, +# and to process the percentage in unsermake (-p). First parameter +# is name of the log file (relative to the log directory), and the +# second parameter is a reference to an array with the command and +# its arguments. +# +# TODO: This is a fork of log_command(). Find a way to re-merge them. +# Returns 0 on success, non-zero on failure. +sub run_make_command +{ + my $pid; + my $module = shift; + my $filename = shift; + my @command = @{(shift)}; + my $logdir = get_log_dir($module); + my $isunsermake = $command[0] =~ 'unsermake'; + + # Don't print ANSI characters if we're not on a tty. Also, automake + # doesn't support printing output status. Finally, we output the whole + # log to screen when debugging which makes this useless. + if (!$isunsermake or not -t STDERR or debugging) + { + return log_command($module, $filename, \@command); + } + + # Make sure -p is in the unsermake flags, it's the whole reason for using + # this function. + if (!(grep /^(-p)|(--print-progress)$/, @command)) + { + # Add in front of element 1, deleting 0 elements. + splice @command, 1, 0, '-p'; + } + + if (pretending) + { + pretend "\tWould have run g[", join (' ', @command); + return 0; + } + + $pid = open(CHILD, '-|'); + if ($pid) + { + my $last = -1; + + while (<CHILD>) + { + chomp; + + # Update terminal (\e[K clears the line) if the percentage + # changed. + if (/([0-9]+)% (creating|compiling|linking)/) + { + print STDERR "\r$1% \e[K" unless ($1 == $last); + $last = $1; + } + } + + close(CHILD); + print STDERR "\r\e[K"; + + # If the module fails building, set an internal flag in the module + # options with the name of the log file containing the error message. + my $result = $?; + set_error_logfile($module, "$filename.log") if $result; + + return $result; + } + else + { + # Child + if (not defined $logdir or not -e $logdir) + { + # Error creating directory for some reason. + error "\tLogging to standard output due to failure creating log dir."; + } + + open (STDOUT, "|tee $logdir/$filename.log") or do { + error "Error opening pipe to tee command." + }; + + # Make sure we log everything. + open (STDERR, ">&STDOUT"); + + exec (@command) or do { + my $cmd_string = join(' ', @command); + error <<EOF; +r[b[Unable to execute "$cmd_string"]! + $! + +Please check your binpath setting (it controls the PATH used by kdesvn-build). +Currently it is set to g[$ENV{PATH}]. +EOF + # Don't return, we're still in the child! + exit 1; + }; + } +} + +# Subroutine to determine if the given subdirectory of a module can actually be +# built or not. For instance, /admin can never be built, and the /kalyptus subdir +# of kdebindings can't either. +sub is_subdir_buildable +{ + my ($module, $dir) = @_; + + return 0 if $dir eq 'admin'; + return 0 if $dir eq 'kalyptus' and $module eq 'kdebindings'; + return 1; +} + +# Subroutine to return the path to the given executable based on the current +# binpath settings. e.g. if you pass make you could get '/usr/bin/make'. If +# the executable is not found undef is returned. +# +# This assumes that the module environment has already been updated since +# binpath doesn't exactly correspond to $ENV{'PATH'}. +sub path_to_prog +{ + my $prog = shift; + my @paths = split(/:/, $ENV{'PATH'}); + + # If it starts with a / the path is already absolute. + return $prog if $prog =~ /^\//; + + for my $path (@paths) + { + return "$path/$prog" if (-x "$path/$prog"); + } + + return undef; +} + +# Subroutine to run the make command with the arguments given by the passed +# list. The first argument of the list given must be the module that we're +# making. The second argument is the "try number", used in creating the log +# file name. +# +# Returns 0 on success, non-zero on failure (shell script style) +sub safe_make (@) +{ + my ($module, $trynumber, $apidox, @args) = @_; + my $opts; + my $logdir = get_log_dir($module); + my $checkout_dirs = get_option($module, "checkout-only"); + my @dirs = split(' ', $checkout_dirs); + my $installing = $trynumber eq 'install'; + my $make = 'make'; + + if (get_option($module, 'use-unsermake')) + { + $make = get_option('global', 'unsermake-path'); + $opts = get_option($module, 'unsermake-options'); + } + else + { + $opts = get_option($module, 'make-options'); + } + + # Convert the path to an absolute path since I've encountered a sudo that + # is apparently unable to guess. Maybe it's better that it doesn't guess + # anyways from a security point-of-view. + $make = path_to_prog($make) unless pretending; + + if(not defined $make) + { + # Weird, we can't find make, you'd think configure would have + # noticed... + error " r[b[*] Unable to find the g[make] executable!"; + + # Make sure we don't bother trying again, this is a more serious + # error. + set_option($module, "#was-rebuilt", 1); + return 1; + } + + # Add make-options to the given options, as long as we're not installing + # If we are installing, unsermake seems to assume that the options are a + # make target, and parallel builds don't help with installing anyways. + unshift (@args, split(' ', $opts)) unless $installing; + + my $description; + + # Check if we're installing + if($installing) + { + debug "Prepending install options, apidox: $apidox."; + + $description = $apidox ? "API Documentation" : clr "g[$module]"; + unshift @args, $make, $apidox ? 'install-apidox' : 'install'; + unshift @args, split(' ', get_option ($module, 'make-install-prefix')); + + info "\tInstalling $description."; + } + else + { + $description = "Building API Documentation"; + $description = "Compiling, attempt $trynumber" unless $apidox; + + push @args, 'apidox' if $apidox; + unshift @args, $make; + + info "\t$description..."; + } + + push (@dirs, "") if scalar @dirs == 0; + for my $subdir (@dirs) + { + # Some subdirectories shouldn't have make run within them. + next unless is_subdir_buildable($module, $subdir); + + my $logname = "build-$trynumber"; + if ($installing) + { + $logname = $apidox ? 'install-apidox' : 'install'; + } + + if ($subdir ne '') + { + $logname = $installing ? "install-$subdir" : "build-$subdir-$trynumber"; + next if $apidox; # Don't built apidox in a subdirectory + + info $installing ? "\tInstalling " : "\tBuilding ", "subdirectory g[$subdir]"; + } + + my %pathinfo = get_module_path_dir($module, 'build'); + my $builddir = "$pathinfo{fullpath}/$subdir"; + $builddir =~ s/\/*$//; + + chdir ($builddir); + + my $result = run_make_command ($module, $logname, \@args ); + return $result if $result; + }; + + return 0; +} + +# Subroutine to add a variable to the environment, but ONLY if it +# is set. First parameter is the variable to set, the second is the +# value to give it. +sub setenv +{ + my ($var, $val) = @_; + + return unless $val; + + pretend "\tWould have set g[$var]=y[$val]."; + + $ENV{$var} = $val; +} + +# Display a message to the user regarding their relative lack of +# ~/.kdesvn-buildrc, and point them to some help. We will continue using a +# default set of options. +sub no_config_whine +{ + my $searched = join("\n ", @rcfiles); + my $homepage = "http://kdesvn-build.kde.org/"; + + note <<"HOME"; +Unable to open configuration file! +We looked for: + $searched + +kdesvn-build will continue using a default set of options. These options may +not apply to you, so feel free to visit the kdesvn-build homepage + +b[g[$homepage] + +and use the configuration file generator to guide you through the process of +creating a config file to customize your kdesvn-build process. + +HOME +} + +# This subroutine assigns the appropriate options to %package_opts and the +# update and build lists to build a default set of modules. +sub setup_default_modules() +{ + @update_list = qw(qt-copy arts kdesupport kdelibs kdebase kdeartwork + kdemultimedia kdepim kdeutils kdegraphics kdegames + kdetoys kdeedu kdeaddons); + @build_list = @update_list; + + for my $i (@update_list) { + if (not exists $package_opts{$i}) + { + $package_opts{$i} = { }; # Set up defaults + $package_opts{$i}{'set-env'} = { }; + } + } + + # Setup default options for qt-copy + $package_opts{'qt-copy'} = { + 'conf-flags' => q(-system-zlib -qt-gif -system-libjpeg -system-libpng + -plugin-imgfmt-mng -thread -no-exceptions -debug + -dlopen-opengl), + 'apply-qt-patches' => 'true', + +# See setup_kde35_hack() for why this option is here. + 'module-base-path' => 'branches/qt/3.3', + + 'use-qt-builddir-hack' => 'true', + 'use-unsermake' => 0, + 'set-env' => { }, + }; + + # That handy q() construct above kept the newlines, I don't want them. + $package_opts{'qt-copy'}{'conf-flags'} =~ s/\s+/ /gm; +} + +# Reads in the options from the config file and adds them to the option store. +# The first parameter is a reference to the file handle to read from. +# The second parameter is 'global' if we're reading the global section, or +# 'module' if we should expect an end module statement. +sub parse_module +{ + my ($fh, $module) = @_; + $module = 'global' unless $module; + + # Make sure we acknowledge that we read the module name in from the + # file. + if (not defined $package_opts{$module}) + { + $package_opts{$module} = { + 'set-env' => { } + }; + } + + # Read in each option + while (<$fh>) + { + # Handle line continuation + chomp; + + if(s/\\\s*$//) # Replace \ followed by optional space at EOL and try again. + { + $_ .= <$fh>; + redo unless eof($fh); + } + + s/#.*$//; # Remove comments + next if /^\s*$/; # Skip blank lines + + if($module eq 'global') + { + last if /^end\s+global/; # Stop + } + else + { + last if /^end\s+module/; # Stop + } + + # The option is the first word, followed by the + # flags on the rest of the line. The interpretation + # of the flags is dependant on the option. + my ($option, $value) = /^\s* # Find all spaces + ([-\w]+) # First match, alphanumeric, -, and _ + # (?: ) means non-capturing group, so (.*) is $value + # So, skip spaces and pick up the rest of the line. + (?:\s+(.*))?$/x; + + $value = "" unless defined $value; + + # Simplify this. + $value =~ s/\s+$//; + $value =~ s/^\s+//; + $value =~ s/\s+/ /; + + # Check for false keyword and convert it to Perl false. + $value = 0 if lc($value) =~ /^false$/; + + # Replace tildes with home directory. + 1 while ($value =~ s"(^|:|=)~/"$1$ENV{'HOME'}/"); + + set_option($module, $option, $value); + } +} + +# This subroutine reads in the settings from the user's configuration +# file. +sub read_options +{ + # The options are stored in the file $rcfile + my $success = 0; + my $global_opts = $package_opts{'global'}; + for my $file (@rcfiles) + { + if (open CONFIG, "<$file") + { + $success = 1; + $rcfile = $file; + last; + } + } + + if (not $success) + { + if(scalar @rcfiles == 1) + { + # This can only happen if the user uses --rc-file, if we fail to + # load the file, we need to fail to load. + error <<EOM; +Unable to open config file $rcfiles[0] + +Script stopping here since you specified --rc-file on the command line to +load $rcfiles[0] manually. If you wish to run the script with no configuration +file, leave the --rc-file option out of the command line. + +EOM + exit 1; + } + + no_config_whine(); + setup_default_modules(); + return; + } + + my ($option, $flags, $modulename); + + # FIXME: Make global settings optional if only tweaks needed are for + # modules. + + # Read in global settings + while (<CONFIG>) + { + s/#.*$//; # Remove comments + next if (/^\s*$/); # Skip blank lines + + # First command in .kdesvn-buildrc should be a global + # options declaration, even if none are defined. + if (not /^global\s*$/) + { + error "Invalid configuration file: $rcfile."; + error "Expecting global settings section!"; + exit 1; + } + + # Now read in each global option + parse_module(\*CONFIG, 'global'); + last; + } + + my $using_default = 1; + + # Now read in module settings + while (<CONFIG>) + { + s/#.*$//; # Remove comments + next if (/^\s*$/); # Skip blank lines + + # Get modulename (has dash, dots, slashes, or letters/numbers) + ($modulename) = /^module\s+([-\/\.\w]+)\s*$/; + + if (not $modulename) + { + warning "Invalid configuration file $rcfile!"; + warning "Expecting a start of module section."; + warning "Global settings will be retained."; + + $modulename = 'null'; # Keep reading the module section though. + } + + # Don't build default modules if user has their own wishes. + if ($using_default) + { + $using_default = 0; + @update_list = @build_list = ( ); + } + + parse_module(\*CONFIG, $modulename); + + next if ($modulename eq 'null'); + + # Done reading options, add this module to the update list + push (@update_list, $modulename) unless exists $ignore_list{$modulename}; + + # Add it to the build list, unless the build is only + # supposed to be done manually. + if (not get_option ($modulename, 'manual-build') and not exists $ignore_list{$modulename}) + { + push (@build_list, $modulename); + } + } + + close CONFIG; + + delete $package_opts{'null'}; # Just in case. + + # For the 3.5 edition we want to set the qt-copy option module-base-path + # to branches/qt/3.3 unless the user already has it set. + unless (exists $package_opts{'qt-copy'}{'module-base-path'}) + { + set_option ('qt-copy', 'module-base-path', 'branches/qt/3.3'); + } + + # If the user doesn't ask to build any modules, build a default set. + # The good question is what exactly should be built, but oh well. + setup_default_modules() if $using_default; +} + +# Subroutine to check if the given module needs special treatment to support +# srcdir != builddir. If this function returns true kdesvn-build will use a +# few hacks to simulate it, and will update e.g. configure paths appropriately +# as well. +sub module_needs_builddir_help +{ + my $module = shift; + my @module_help_list = qw/qt-copy kdebindings valgrind/; + + # qt-copy special case to support use-qt-builddir-hack. + if ($module eq 'qt-copy' and not get_option('qt-copy', 'use-qt-builddir-hack')) + { + return 0; + } + + return list_has(@module_help_list, $module); +} + +# This subroutine reads the set-env option for a given module and initializes +# the environment based on that setting. +sub setup_module_environment +{ + my $module = shift; + my ($key, $value); + + # Let's see if the user has set env vars to be set. + my $env_hash_ref = get_option($module, 'set-env'); + while (($key, $value) = each %{$env_hash_ref}) + { + setenv($key, $value); + } +} + +# Subroutine to initialize some environment variable for building +# KDE from Subversion. Change this section if a dependency changes later. +sub initialize_environment +{ + $ENV{"WANT_AUTOMAKE"} = "1.7"; + $ENV{"WANT_AUTOCONF_2_5"} = "1"; + $ENV{"PATH"} = get_option ('global', 'binpath'); + + my $svnserver = get_option ('global', 'svn-server'); + + my $pc_path = get_option('global', 'kdedir') . "/lib/pkgconfig"; + $pc_path .= ":" . $ENV{'PKG_CONFIG_PATH'} if ( exists $ENV{'PKG_CONFIG_PATH'} ); + $ENV{'PKG_CONFIG_PATH'} = $pc_path; + + if(-t STDOUT and get_option('global', 'colorful-output')) + { + $RED = "\e[31m"; + $GREEN = "\e[32m"; + $YELLOW = "\e[33m"; + $NORMAL = "\e[0m"; + $BOLD = "\e[1m"; + } + + # Set the process priority + setpriority PRIO_PROCESS, 0, get_option('global', 'niceness'); + + setup_module_environment ('global'); +} + +# Subroutine to get a list of modules to install, either from the command line +# if it's not empty, or based on the list of modules successfully built. +sub get_install_list +{ + my @install_list; + + if ($#ARGV > -1) + { + @install_list = @ARGV; + @ARGV = (); + } + else + { + # Get list of built items from $logdir/latest/build-status + my $logdir = get_subdir_path('global', 'log-dir'); + + if (not open BUILTLIST, "<$logdir/latest/build-status") + { + error "Can't determine what modules have built. You must"; + error "specify explicitly on the command line what modules to build."; + exit (1); # Don't finish, no lock has been taken. + } + + while (<BUILTLIST>) + { + chomp; + if (/Succeeded/) + { + # Clip to everything before the first colon. + my $module = (split(/:/))[0]; + push @install_list, $module; + } + } + + close BUILTLIST; + } + + return @install_list; +} + +# Print out an error message, and a list of modules that match that error +# message. It will also display the log file name if one can be determined. +# The message will be displayed all in uppercase, with PACKAGES prepended, so +# all you have to do is give a descriptive message of what this list of +# packages failed at doing. +sub output_failed_module_list($@) +{ + my ($message, @fail_list) = @_; + $message = uc $message; # Be annoying + + debug "Message is $message"; + debug "\tfor ", join(', ', @fail_list); + + if (scalar @fail_list > 0) + { + my $homedir = $ENV{'HOME'}; + my $logfile; + + warning "\nr[b[<<< PACKAGES $message >>>]"; + + for (@fail_list) + { + $logfile = get_option($_, '#error-log-file'); + $logfile = "No log file" unless $logfile; + $logfile =~ s|$homedir|~|; + + warning "r[$_] - g[$logfile]"; + } + } +} + +# This subroutine reads the fail_lists dictionary to automatically call +# output_failed_module_list for all the module failures in one function +# call. +sub output_failed_module_lists() +{ + for my $type (@fail_display_order) + { + my @failures = @{$fail_lists{$type}}; + output_failed_module_list("failed to $type", @failures); + } +} + +# This subroutine extract the value from options of the form --option=value, +# which can also be expressed as --option value. The first parameter is the +# option that the user passed to the cmd line (e.g. --prefix=/opt/foo), and +# the second parameter is a reference to the list of command line options. +# The return value is the value of the option (the list might be shorter by +# 1, copy it if you don't want it to change), or undef if no value was +# provided. +sub extract_option_value($\@) +{ + my ($option, $options_ref) = @_; + + if ($option =~ /=/) + { + my @value = split(/=/, $option); + shift @value; # We don't need the first one, that the --option part. + + return undef if (scalar @value == 0); + + # If we have more than one element left in @value it's because the + # option itself has an = in it, make sure it goes back in the answer. + return join('=', @value); + } + + return undef if scalar @{$options_ref} == 0; + return shift @{$options_ref}; +} + +# Utility subroutine to handle setting the environment variable type of value. +# Returns true (non-zero) if this subroutine handled everything, 0 otherwise. +# The first parameter should by the reference to the hash with the 'set-env' +# hash ref, second parameter is the exact option to check, and the third +# option is the value to set that option to. +sub handle_set_env +{ + my ($href, $option, $value) = @_; + + return 0 if $option !~ /^#?set-env$/; + + my ($var, @values) = split(' ', $value); + + $$href{$option} = ( ) unless exists $$href{$option}; + $$href{$option}{$var} = join(' ', @values); + + return 1; +} + +# Sets the option for the given module to the given value. If the data for the +# module doesn't exist yet, it will be defined starting with a default value. +# First parameter: module to set option for (or 'global') +# Second parameter: option name (Preceded by # for a sticky option) +# Third parameter: option value +# Return value is void +sub set_option +{ + my ($module, $option, $value) = @_; + + # Set module options + if (not exists $package_opts{$module}) + { + $package_opts{$module} = { + 'set-env' => { } + }; + } + + return if handle_set_env($package_opts{$module}, $option, $value); + $package_opts{$module}{$option} = $value; +} + +# Subroutine to process the command line arguments. Any arguments so +# processed will be removed from @ARGV. +# The arguments are generally documented in doc.html now. +# NOTE: Don't call finish() from this routine, the lock hasn't been obtained. +# NOTE: The options have not been loaded yet either. Any option which +# requires more than rudimentary processing should set a flag for later work. +sub process_arguments +{ + my $arg; + my $version = "kdesvn-build 0.97.6 (KDE 3.5 Edition)"; + my $author = <<DONE; +$version was written (mostly) by: + Michael Pyne <michael.pyne\@kdemail.net> + +Many people have contributed code, bugfixes, and documentation. + +Please report bugs using the KDE Bugzilla, at http://bugs.kde.org/ +DONE + + my @argv; + + while ($_ = shift @ARGV) + { + SWITCH: { + /^(--version)$/ && do { print "$version\n"; exit; }; + /^--author$/ && do { print $author; exit; }; + /^(-h)|(--?help)$/ && do { + print <<DONE; +$version + +This script automates the download, build, and install process for KDE (using +Subversion). + +It is recommended that you first setup a .kdesvn-buildrc file in your home +directory. Please visit http://kdesvn-build.kde.org/ for +information on how to write the file, or consult the sample file which should +have been included with this program. If you don't setup a .kdesvn-buildrc, +a default set of options will be used, which a few modules to be built by +default. + +After setting up .kdesvn-buildrc, you can run this program from either the +command-line or from cron. It will automatically download the modules from +Subversion, create the build system, and configure and make the modules you +tell it to. If you\'d like, you can use this program to install KDE as well, +if you\'re building KDE for a single user. Note that kdesvn-build will try +by default to install the modules. + +Basic synopsis, after setting up .kdesvn-buildrc: +\$ kdesvn-build [package names] (Download, build, and install KDE) + +If you don\'t specify any particular package names, then your settings +in .kdesvn-buildrc will be used. If you DO specify a package name, then +your settings will still be read, but the script will try to build/install +the package regardless of .kdesvn-buildrc + +Copyright (c) 2003, 2004, 2005 $author +The script is distributed under the terms of the GNU General Public License +v2, and includes ABSOLUTELY NO WARRANTY!!! + +Options: + --no-svn Skip contacting the Subversion server. + --no-build Skip the build process. + --no-install Don't automatically install after build. + + --svn-only Update from Subversion only (Identical to --no-build + at this point). + --build-only Build only, don't perform updates or install. + + --pretend (or -p) Don't actually contact the Subversion server, run make, + or create/delete files and directories. Instead, + output what the script would have done. + --quiet (or -q) Be less descriptive of the build process, without + printing each little substep kdesvn-build is + performing. + --really-quiet Only warnings and errors will be displayed. + --verbose (or -v) Be *very* descriptive of the build process. Only + --debug outputs more. + --debug Activates debug mode. + --color + --no-color Add (or remove) color from the output. + + --rc-file=<filename> Read configuration from filename instead of default. + --nice=<value> Allows you to run the script with a lower priority + The default value is 10 (lower priority by 10 steps). + --prefix=/kde/path This option is a shortcut to change the setting for + kdedir from the command line. It implies + --reconfigure. + + --resume Tries to resume the make process from the last time + the script was run, without performing the Subversion + update. + --resume-from=<pkg> Starts building from the given package, without + performing the Subversion update. + --revision (or -r)=<rev> Forces update to revision <rev> from Subversion. + + --refresh-build Start the build from scratch. + --reconfigure Run configure again, but don't clean the build + directory or re-run make -f Makefile.cvs. + --recreate-configure Run make -f Makefile.cvs again to redo the configure + script. + --no-rebuild-on-fail Don't try to rebuild a module from scratch if it + failed building and we didn't already try to build it + from scratch. + --build-system-only Create the build infrastructure, but don't actually + perform the build. + --install Try to install the packages passed on the command + line, or all packages in ~/.kdesvn-buildrc that don't + have manual-build set. Building and Subversion + updates are not performed. + + --<option>= Any unrecognized options are added to the global + configuration, overriding any value that may exist. + --<module>,<option>= Likewise, this allows you to override any module + specific option from the command line. + + --help You\'re reading it. :-) + --author Output the author(s)\'s name. + --version Output the program version. + +You can get more help by reading the included HTML documentation, or going +online to http://kdesvn-build.kde.org/ +DONE + # We haven't done any locking... no need to finish() + # Avoids log-dir errors due to having not performed. + # read_options() and setup_logging_subsystem(). + exit 0; + }; + + /^--install$/ && do { + $install_flag = 1; + last SWITCH; + }; + + /^--no-svn$/ && do { + set_option('global', '#no-svn', 1); + last SWITCH; + }; + + /^--no-install$/ && do { + set_option('global', '#install-after-build', 0); + last SWITCH; + }; + + /^(-v)|(--verbose)$/ && do { + set_option('global', '#debug-level', WHISPER); + last SWITCH; + }; + + /^(-q)|(--quiet)$/ && do { + set_option('global', '#debug-level', NOTE); + last SWITCH; + }; + + /^--really-quiet$/ && do { + set_option('global', '#debug-level', WARNING); + last SWITCH; + }; + + /^--debug$/ && do { + set_option('global', 'debug-level', DEBUG); + last SWITCH; + }; + + /^--reconfigure$/ && do { + set_option('global', '#reconfigure', 1); + last SWITCH; + }; + + /^--recreate-configure$/ && do { + set_option('global', '#recreate-configure', 1); + last SWITCH; + }; + + /^--color$/ && do { + set_option('global', '#colorful-output', 1); + last SWITCH; + }; + + /^--no-color$/ && do { + set_option('global', '#colorful-output', 0); + last SWITCH; + }; + + /^--no-build$/ && do { + set_option('global', '#manual-build', 1); + last SWITCH; + }; + + # Although equivalent to --no-build at this point, someday the + # script may interpret the two differently, so get ready now. + /^--svn-only$/ && do { # Identically to --no-build + set_option('global', '#manual-build', 1); + last SWITCH; + }; + + # Don't run Subversion or install + /^--build-only$/ && do { + set_option('global', '#no-svn', 1); + set_option('global', '#install-after-build', 0); + last SWITCH; + }; + + /^--build-system-only$/ && do { + set_option('global', '#build-system-only', 1); + last SWITCH; + }; + + /^--rc-file=?/ && do { + my $rcfile = extract_option_value($_, @ARGV); + if (not $rcfile) + { + print "You must specify a filename to use as the config file!\n"; + exit 8; + } + + @rcfiles = ( $rcfile ); + + last SWITCH; + }; + + /^--prefix=?/ && do { + my $prefix = extract_option_value($_, @ARGV); + if (not $prefix) + { + print "No prefix selected with the --prefix option.\n"; + exit 8; + } + + set_option('global', '#kdedir', $prefix); + set_option('global', '#reconfigure', 1); + + last SWITCH; + }; + + /^--no-rebuild-on-fail$/ && do { + set_option('global', '#no-rebuild-on-fail', 1); + last SWITCH; + }; + + /^--nice=?/ && do { + my $niceness = extract_option_value($_, @ARGV); + + if($niceness) + { + set_option('global', '#niceness', $niceness); + } + else + { + print "You need to specify a value for the --nice option\n"; + exit 8; + } + + last SWITCH; + }; + + /^--ignore-modules$/ && do { + # We need to keep read_options() from adding these modules to + # the build list, taken care of by ignore_list. We then need + # to remove the modules from the command line, taken care of + # by the @ARGV = () statement; + my @options = (); + foreach (@ARGV) + { + if (/^-/) + { + push @options, $_; + } + else + { + $ignore_list{$_} = 1; + + # the pattern match doesn't work with $_, alias it. + my $module = $_; + @argv = grep (!/^$module$/, @argv); + } + } + @ARGV = @options; + + last SWITCH; + }; + + /^(--dry-run)|(--pretend)|(-p)$/ && do { + set_option('global', '#pretend', 1); + last SWITCH; + }; + + /^--refresh-build$/ && do { + set_option('global', '#refresh-build', 1); + last SWITCH; + }; + + /^(--revision|-r)=?/ && do { + my $revision = extract_option_value($_, @ARGV); + if (not $revision) + { + print "No revision selected with the --revision option.\n"; + exit 8; + } + + set_option('global', '#revision', $revision); + + last SWITCH; + }; + + /^--resume-from=?/ && do { + $_ = extract_option_value($_, @ARGV); + if (not $_) + { + print "You must pass a module to resume from to the --resume-from option!\n"; + exit 7; + } + + if (defined $package_opts{'global'}{'#resume'}) + { + print "WARNING: Don't pass both --resume and --resume-from\n"; + delete $package_opts{'global'}{'#resume'}; + } + + set_option('global', '#resume-from', $_); + set_option('global', '#no-svn', 1); + last SWITCH; + }; + + /^--resume$/ && do { + if (defined $package_opts{'global'}{'#resume'}) + { + print "WARNING: Don't pass both --resume and --resume-from\n"; + delete $package_opts{'global'}{'#resume-from'}; + } + + set_option('global', '#resume', 1); + set_option('global', '#no-svn', 1); + last SWITCH; + }; + + /^--/ && do { + # First let's see if they're trying to override a global option. + my ($option) = /^--([-\w\d\/]+)/; + my $value = extract_option_value($_, @ARGV); + + if (exists $package_opts{'global'}{$option}) + { + # Global option + set_option('global', "#$option", $value); + } + else + { + # Module specific option. The module options haven't been + # read in, so we'll just have to assume that the module the + # user passes actually does exist. + my ($module, $option) = /^--([\w\/-]+),([-\w\d\/]+)/; + + if (not $module) + { + print "Unknown option $_\n"; + exit 8; + } + + set_option($module, "#$option", $value); + } + + last SWITCH; + }; + + /^-/ && do { print "WARNING: Unknown option $_\n"; last SWITCH; }; + + # Strip trailing slashes. + s/\/*$//; + push @argv, $_; # Reconstruct correct @ARGV + } + } + + @ARGV = @argv; +} + +# Subroutine to try to get a lock on the script's lockfile to prevent +# more than one script from updating KDE Subversion at once. +# The value returned depends on the system's open() call. Normally 0 +# is failure and non-zero is success (e.g. a file descriptor to read). +# TODO: This could be improved to not fight over the lock when the scripts are +# handling separate tasks. +sub get_lock +{ + my $lockfile = "$ENV{HOME}/.kdesvn-lock"; + sysopen LOCKFILE, $lockfile, O_WRONLY | O_CREAT | O_EXCL; + my $errorCode = $!; # Save for later testing. + + # Install signal handlers to ensure that the lockfile gets closed. + # There is a race condition here, but at worst we have a stale lock + # file, so I'm not *too* concerned. + $SIG{'HUP'} = \&quit_handler; + $SIG{'INT'} = \&quit_handler; + $SIG{'QUIT'} = \&quit_handler; + $SIG{'ABRT'} = \&quit_handler; + $SIG{'TERM'} = \&quit_handler; + $SIG{'PIPE'} = \&quit_handler; + + # Note that we can use color codes at this point since get_lock is called + # after read_options (which sets up the color). + if($errorCode == EEXIST) + { + # Path already exists, read the PID and see if it belongs to a + # running process. + open PIDFILE, "<$lockfile" or do + { + # Lockfile is there but we can't open it?!? Maybe a race + # condition but I have to give up somewhere. + warning " WARNING: Can't open or create lockfile r[$lockfile]"; + return 1; + }; + + my $pid = <PIDFILE>; + close PIDFILE; + + if($pid) + { + # Recent kdesvn-build; we wrote a PID in there. + chomp $pid; + + # See if something's running with this PID. + if (kill(0, $pid) == 1) + { + # Something *is* running, likely kdesvn-build. Don't use error, + # it'll scan for $! + print clr " r[*y[*r[*] kdesvn-build appears to be running. Do you want to:\n"; + print clr " (b[Q])uit, (b[P])roceed anyways?: "; + + my $choice = <STDIN>; + chomp $choice; + + if(lc $choice ne 'p') + { + print clr " y[*] kdesvn-build run canceled.\n"; + exit 1; + } + + # We still can't grab the lockfile, let's just hope things + # work out. + print clr " y[*] kdesvn-build run in progress by user request.\n"; + return 1; + } + + # If we get here, then the program isn't running (or at least not + # as the current user), so allow the flow of execution to fall + # through below and unlink the lockfile. + } # pid + + # No pid found, optimistically assume the user isn't running + # twice. + warning " y[WARNING]: stale kdesvn-build lockfile found, deleting."; + unlink $lockfile; + sysopen LOCKFILE, $lockfile, O_WRONLY | O_CREAT | O_EXCL and do + { + print LOCKFILE "$$\n"; + close LOCKFILE; + }; + return 1; # Hope the sysopen worked. + } + + print LOCKFILE "$$\n"; + close LOCKFILE; + + # Even if we fail it's generally better to allow the script to proceed + # without being a jerk about things, especially as more non-CLI-skilled + # users start using kdesvn-build to build KDE. + return 1; +} + +# Subroutine to free the lock allocated by get_lock() +sub close_lock +{ + my $lockfile = "$ENV{HOME}/.kdesvn-lock"; + + close LOCKFILE; + unlink $lockfile; +} + +sub adjust_update_list +{ + my $list_ref = shift; + my $build_ref = shift; + + # Check to see if the user has requested for one of the modules to be + # built is using unsermake. If so, we need to check if kdenonbeta is + # already supposed to be checked out. If so, we need to make sure that + # unsermake is present in any checkout-only directives, and if not, we need + # to add kdenonbeta/unsermake to the checkout list. + my $unsermake_needed = grep (get_option ($_, 'use-unsermake'), @{$build_ref}); + + # If the user has told us that they will manage unsermake then we don't + # need to do anything. + $unsermake_needed = 0 if get_option('global', 'use-unsermake') eq 'self'; + + # If the user has set manual-update, don't second-guess them. + $unsermake_needed = 0 if get_option('kdenonbeta', 'manual-update'); + + debug "Do we update unsermake? ", ($unsermake_needed ? 'yes' : 'no'); + + if ($unsermake_needed) + { + if (not list_has(@{$list_ref}, 'kdenonbeta')) + { + whisper "Adding kdenonbeta/unsermake to build."; + + # kdenonbeta isn't being downloaded by the user. + unshift (@{$list_ref}, 'kdenonbeta'); + $package_opts{'kdenonbeta'} = { + 'manual-build' => 'true', + 'checkout-only' => 'unsermake', + '#suppress-auto-admin' => 1, + }; + } + else + { + my $checkouts = get_option('kdenonbeta', 'checkout-only'); + + if ($checkouts !~ /\bunsermake\b/) + { + # kdenonbeta is being checked out, but the user has + # excluded unsermake. + set_option('kdenonbeta', 'checkout-only', "$checkouts unsermake"); + set_option('kdenonbeta', '#suppress-auto-admin', 1); + } + } + } +} + +# Subroutine to get the list of Subversion modules to update. Returned +# as a list. Parse the command-line arguments first. +sub get_update_list +{ + return @ARGV unless $#ARGV == -1; + + my @return_list; + for (@update_list) + { + push @return_list, $_ if not get_option($_, "manual-update"); + } + + return @return_list; +} + +# Subroutine to get the list of Subversion modules to build. Returned +# as a list. A module will not be built if manual-build is set +# in the module's options. The command-line arguments should have been +# parsed first. +# +# This subroutine will handle the --resume and --resume-from options. +sub get_build_list +{ + my $resume_point; + my $autoresuming; + + # We check explicity for sticky options here since they can only be + # set from the command line. + if (get_option('global', '#manual-build')) + { + if (get_option('global', '#resume') || get_option('global', + '#resume-from')) + { + warning "I'm confused, you enabled y[--no-build] and y[--resume]."; + warning "Skipping the build process."; + } + + return (); + } + + if (get_option ('global', '#resume')) + { + if (scalar @ARGV > 0) + { + warning "Ignoring modules specified on command line because y[--resume] was set."; + } + + # Try to determine location of last existing status file. + my $status_fname = get_output_file('existing'); + if (not $status_fname) + { + error "Unable to open status file from last run, can't resume!"; + return (); + } + + my ($line, $oldline); + open STATUS_FILE, "<$status_fname" or do { + error "Can't open $status_fname, so I can't resume!"; + return (); + }; + + while ($line = <STATUS_FILE>) + { + $oldline = $line; + } + + close STATUS_FILE; + + if (not defined $oldline) + { + # Hmm, empty file? + error <<"EOF"; +Unable to read information from resume status file. +It's probably empty, but there's no way to resume! +EOF + return (); + } + + chomp $oldline; + debug "The last success line is $oldline"; + + ($resume_point = $oldline) =~ s/^([^:]+):.*/$1/; + whisper "Resuming at $resume_point"; + } + elsif (get_option ('global', '#resume-from')) + { + $resume_point = get_option ('global', '#resume-from'); + $autoresuming = 1; + } + + if ($resume_point) + { + my $resume_found = 0; + + # Pop stuff off of the list until we hit the resume point. + while (scalar @build_list > 0 and not $resume_found) + { + $resume_found = 1 if $build_list[0] eq $resume_point; + + # If we're doing an auto resume, pop off the last package read + # from the file. If we're doing resume from on the other hand, + # I'm assuming the user intends to start with building that + # package. + shift @build_list unless $resume_found and $autoresuming; + } + + return @build_list; + } + + return @ARGV unless $#ARGV == -1; + + my @list; + for (@build_list) + { + push @list, $_ unless get_option($_, 'manual-update'); + } + + return @list; +} + +# Used to sort module names. 'global' always starts first, modules with / +# sort last. +sub module_sort +{ + # This is always true. + return 0 if $a eq $b; + + # Look for global modules. + return -1 if $a eq 'global'; + return 1 if $b eq 'global'; + + # If both have /, use a normal sort. + return $a cmp $b if $a =~ /\// and $b =~ /\//; + + # If left has slash, it's < $b (and vice versa) + return 1 if $a =~ /\//; + return -1 if $b =~ /\//; + + # Normal sort. + return $a cmp $b; +} + +# Helper subroutine for debugging purposes. Dumps all of the +# options which have been read in to %global_opts and %package_opts. +sub dump_options +{ + my ($item, $ref_item, $ref); + my @keys = sort module_sort keys %package_opts; + my $c; # $c is a color variable to be used with clr() + + # Now dump the options for each module + foreach $item (@keys) + { + debug "\nOptions for module g[$item]:"; + my $ref = $package_opts{$item}; + + foreach $ref_item (sort keys %{$package_opts{$item}}) + { + # Put the first bracket in here, otherwise it breaks on some + # Perl systems. + $c = $ref_item =~ /^#/ ? 'r[' : 'g['; + + if($ref_item !~ /^#?set-env$/) + { + next unless defined $$ref{$ref_item}; + debug " ${c}$ref_item] is \"y[", $$ref{$ref_item}, clr ']"'; + } + else + { + # Dump the environment variables that will be set. + my $setref = $$ref{$ref_item}; + + foreach my $envitem (keys %{$setref}) + { + debug " Set env variable ${c}$envitem] to y[", $$setref{$envitem}; + } + } + } + } +} + +# Subroutine to unlink the given symlink if global-pretend isn't set. +sub safe_unlink +{ + if (pretending) + { + pretend "\tWould have unlinked ", shift, "."; + return 1; # Return true + } + + return unlink (shift); +} + +# Subroutine to execute the system call on the given list if the pretend +# global option is not set. +sub safe_system(@) +{ + if (not pretending) + { + info "\tExecuting g[", join(" ", @_); + return system (@_) >> 8; + } + + pretend "\tWould have run g[", join(' ', @_); + return 0; # Return true +} + +# Helper subroutine to create a directory, including any parent +# directories that may also need created. +# Returns 0 on failure, non-zero on success +sub super_mkdir +{ + my $pathname = shift; + my $temp; + my @parts = split (/\//, $pathname); + + if (pretending) + { + pretend "\tWould have created g[$pathname]"; + return 1; + } + + foreach (@parts) + { + $temp .= "$_/"; + + next if -e $temp; + return 0 if not mkdir ($temp); + } + + return 1; +} + +# Subroutine to remove a package from the package build list. This +# is for use when you've detected an error that should keep the +# package from building, but you don't want to abort completely. +sub dont_build +{ + my $module = shift; + + whisper "Not building $module"; + + # Weed out matches of the module name + @build_list = grep (!/^$module$/, @build_list); + + push @{$fail_lists{'update'}}, $module; +} + +# Subroutine to split a url into a protocol and host +sub split_url +{ + my $url = shift; + my ($proto, $host) = ($url =~ m|([^:]*)://([^/]*)/|); + + return ($proto, $host); +} + +# This subroutine checks if we are supposed to use ssh agent by examining the +# environment, and if so checks if ssh-agent has a list of identities. If it +# doesn't, we run ssh-add (with no arguments) and inform the user. This can +# be controlled with the disable-agent-check parameter. +sub check_for_ssh_agent +{ + my $agent_running = 0; + my $server = get_option('global', 'svn-server'); + my ($proto, $host) = split_url($server); + + # Don't bother with all this if the user isn't even using SSH. + return 1 if($proto !~ /ssh/) or get_option('global', 'disable-agent-check'); + + # We're using ssh to download, see if ssh-agent is running. + return 1 unless exists $ENV{'SSH_AGENT_PID'}; + + my $pid = $ENV{'SSH_AGENT_PID'}; + + # It's supposed to be running, let's see if there exists the program with + # that pid. + # PORTABILITY NOTE: I'm not sure if this works under *BSD or Solaris. + if (not -e "/proc/$pid") + { + warning "r[ *] SSH Agent is enabled, but y[doesn't seem to be running]."; + warning "Since SSH is used to download from Subversion you may want to see why"; + warning "SSH Agent is not working, or correct the environment variable settings."; + + return 0; + } + + # The agent is running, but does it have any keys? We can't be more specific + # with this check because we don't know what key is required. + my $keys = `ssh-add -l 2>/dev/null`; + if ($keys =~ /no identities/) + { + # Use print so user can't inadvertently keep us quiet about this. + print clr <<EOF; +b[y[*] SSH Agent does not appear to be managing any keys. This will lead to you + being prompted for every module update for your SSH passphrase. So, we're + running g[ssh-add] for you. Please type your passphrase at the prompt when + requested, (or simply Ctrl-C to abort the script). +EOF + my $result = system('ssh-add'); + if ($result) # Run this code for both death-by-signal and nonzero return + { + print "\nUnable to add SSH identity, aborting.\n"; + print "If you don't want kdesvn-build to check in the future,\n"; + print clr "Set the g[disable-agent-check] option to g[true] in your $rcfile.\n\n"; + + return 0; + } + } + + return 1; +} + +# Subroutine to update a list of Subversion modules. The first +# parameter is a reference of a list of the modules to update. +# If the module has not already been checkout out, this subroutine +# will do so for you. +# +# Returns 0 on success, non-zero on error. +sub handle_updates +{ + my $update_ref = shift; + my $kdesvn = get_kdesvn_dir(); + my $svnroot = get_option ('global', 'svn-server'); + my $result = 0; + my $module; + + # No reason to print out the text if we're not doing anything. + return 0 if get_option ('global', 'no-svn'); + return 0 if scalar @$update_ref == 0; + + return 1 if (not check_for_ssh_agent()); + + note "<<< Updating Subversion Directories >>>"; + info " "; # Add newline for aesthetics unless in quiet mode. + + if (not -e $kdesvn) + { + whisper "KDE Subversion download directory doesn't exist, creating.\n"; + if (not super_mkdir ($kdesvn)) + { + error "Unable to make directory r[$kdesvn]!"; + @build_list = (); # Clear out the build list, since we can't build. + $install_flag = 0; # Can't install either. + return 1; + } + } + + foreach $module (@{$update_ref}) + { + my $fullpath = get_fullpath($module, 'source'); + + if (not exists $package_opts{$module}) + { + warning "Unknown module y[$module], configure it in $rcfile."; + + # Continue in case the user just needs default options, hopefully + # it isn't a misspelling. + $package_opts{$module} = { 'set-env' => { } }; + } + + next if get_option($module, 'no-svn'); + + my @options = split(' ', get_option($module, 'checkout-only')); + if (-e "$fullpath/.svn") + { + # Warn user if the current repo URL is different than expected. + check_module_validity($module); + $result = update_module_path($module, @options); + } + else + { + $result = checkout_module_path($module, @options); + } + + if ($result) + { + error "Error updating r[$module], removing from list of packages to build."; + dont_build ($module); + } + + print "\n"; + } + + info "<<< Update Complete >>>\n"; + return $result; +} + +# Subroutine to run the qt-copy apply_patches script. +# Returns 0 on success, non-zero on failure. +sub safe_apply_patches +{ + my %pathinfo = get_module_path_dir('qt-copy', 'build'); + my $builddir = "$pathinfo{fullpath}"; + + if (pretending) + { + pretend "\tWould have run g[./apply_patches]"; + return 0; + } + + info "\tg[Applying recommended Qt patches]."; + chdir ("$builddir"); + return (log_command('qt-copy', 'apply-patches', [ "./apply_patches" ])); +} + +# Subroutine to run and log the configure command. First parameter is the +# path to the configure script to run, the second parameter is a scalar +# containing all of the configure flags to apply +sub safe_configure +{ + my $module = shift; + my $fullpath = get_fullpath($module, 'source'); + my $script = "$fullpath/configure"; + + my @commands = split (/\s+/, get_option($module, 'configure-flags')); + + # Get the user's CXXFLAGS + my $cxxflags = get_option ($module, 'cxxflags'); + setenv ('CXXFLAGS', $cxxflags); + setenv ('DO_NOT_COMPILE', get_option ($module, 'do-not-compile')); + + if ($module ne 'qt-copy') + { + my $kdedir = get_option ('global', 'kdedir'); + my $prefix = get_option ($module, 'prefix'); + + $prefix = $kdedir unless $prefix; + + push @commands, "CXXFLAGS=$cxxflags" if $cxxflags; + push @commands, "--prefix=$prefix"; + + # We're special casing these modules because we're using the lndir + # hack for them. + if (module_needs_builddir_help($module)) + { + $script = get_fullpath($module, 'build') . "/configure"; + } + } + else + { + my $qtdir = get_fullpath('qt-copy', 'build'); + + if(not pretending) + { + # Copy the configure script to accept the GPL license. + open CONFIG, "<$script"; + open NEWCONFIG, ">$qtdir/configure.new"; + while(<CONFIG>) + { + s/read acceptance/acceptance=yes/; + print NEWCONFIG $_; + } + close NEWCONFIG; + close CONFIG; + chmod 0755, "$qtdir/configure.new"; + } + + $script = "$qtdir/configure.new"; + + note "\tb[r[GPL license selected for Qt]. See $fullpath/LICENSE.GPL"; + } + + info "\tRunning g[configure]..."; + unshift @commands, $script; + + return log_command($module, "configure", \@commands); +} + +# Subroutine to try and see if we've already tried to update kde-common +sub has_updated_kdecommon +{ + # Test fast case first. + return 1 if get_option('global', '#has-checked-for-admin'); + + # Double check that it wasn't in the update list. + if (grep(/^(KDE\/)?kde-common$/, @update_list)) + { + set_option('global', '#has-checked-for-admin', 1); + return 1; + } + + return 0; +} + +# Subroutine to automatically create an admir dir for a module if it doesn't +# have one. The first parameter is the module name. It is assumed that we +# are already in the source directory, the current directory will not be +# changed. +# +# Returns boolean true on success, boolean false on failure. +# +# NOTE: This subroutine might try to call an svn update, as long as #no-svn +# isn't set. +sub create_admin_dir +{ + my $module = shift; + my $fullpath = get_fullpath($module, 'source'); + + # Don't bother if it's qt-copy, or if we've already got an admin + # directory. + return 1 if $module eq 'qt-copy'; + return 1 if -e "$fullpath/admin"; + + # Find kde-common + my $admindir = get_fullpath('kde-common', 'source') . '/admin'; + if (not -e $admindir) + { + $admindir = get_fullpath('KDE/kde-common', 'source') . '/admin'; + } + + if (not -e $admindir) + { + # Can't find kde-common, it's apparently not installed. + if (not has_updated_kdecommon()) + { + # We haven't tried downloading it, now would be a good time. + note "Can't find y[kde-common], going to try downloading it."; + + if (get_option('global', 'no-svn')) + { + # Not allowed to update. + error "r[!!] Updating has been blocked, can't get y[kde-common]."; + return 0; + } + + # Checkout the directory. + $admindir = get_fullpath('kde-common', 'source') . '/admin'; + if (pretending) + { + pretend "Would have checked out g[kde-common]\n"; + } + elsif (checkout_module_path('kde-common', 'admin') != 0) + { + return 0; + } + } + } + + chdir ($fullpath); + + whisper "\tCreating symbolic link to g[/admin directory]."; + + return symlink $admindir, "$fullpath/admin"; +} + +# Subroutine to recursively symlink a directory into another location, in a +# similar fashion to how the XFree/X.org lndir() program does it. This is +# reimplemented here since some systems lndir doesn't seem to work right. +# +# As a special exception to the GNU GPL, you may use and redistribute this +# function however you would like (i.e. consider it public domain). +# +# The first parameter is the directory to symlink from. +# The second parameter is the destination directory name. +# +# e.g. if you have $from/foo and $from/bar, lndir would create $to/foo and +# $to/bar. +# +# All intervening directories will be created as needed. In addition, you +# may safely run this function again if you only want to catch additional files +# in the source directory. +# +# Note that this function will unconditionally output the files/directories +# created, as it is meant to be a close match to lndir. +# +# RETURN VALUE: Boolean true (non-zero) if successful, Boolean false (0, "") +# if unsuccessful. +sub safe_lndir +{ + my ($from, $to) = @_; + + # Create destination directory. + if (not -e $to) + { + print "$to\n"; + mkdir ($to) unless pretending; + } + + # Create closure callback subroutine. + my $wanted = sub { + my $dir = $File::Find::dir; + my $file = $File::Find::fullname; + $dir =~ s/$from/$to/; + + # Ignore the .svn directory and files. + return if $dir =~ m,/\.svn,; + + # Create the directory. + if (not -e $dir) + { + print "$dir\n"; + + if (not pretending) + { + mkdir ($dir) or die "Couldn't create directory $dir: $!"; + } + } + + # Symlink the file. Check if it's a regular file because File::Find + # has no qualms about telling you you have a file called "foo/bar" + # before pointing out that it was really a directory. + if (-f $file and not -e "$dir/$_") + { + print "$dir/$_\n"; + + if (not pretending) + { + symlink $File::Find::fullname, "$dir/$_" or + die "Couldn't create file $dir/$_: $!"; + } + } + }; + + # Recursively descend from source dir using File::Find + eval { + find ({ 'wanted' => $wanted, + 'follow_fast' => 1, + 'follow_skip' => 2}, + $from); + }; + + if ($@) + { + $! = 0; # sub error will use $! to display error message. + error "Unable to symlink $from to $to: $@"; + return 0; + } + + return 1; +} + +# Subroutine to link a source directory into an alternate directory in order +# to fake srcdir != builddir for modules that don't natively support it. +# The first parameter is the module to prepare. +# +# The return value is true (non-zero) if it succeeded, and 0 (false) if it +# failed. +# +# On return from the subroutine the current directory will be in the build +# directory, since that's the only directory you should touch from then on. +# +# You may safely call this subroutine for modules that don't need it, they +# will automatically be ignored. +sub prepare_fake_builddir +{ + my $module = shift; + my $builddir = get_fullpath($module, 'build'); + my $srcdir = get_fullpath($module, 'source'); + + # List reference, not a real list. The initial kdesvn-build does *NOT* + # fork another kdesvn-build using exec, see sub log_command() for more + # info. + my $args = [ 'kdesvn-build', 'safe_lndir', $srcdir, $builddir ]; + + # Skip modules that don't need special treatment. + return 1 unless module_needs_builddir_help($module); + + # Backwards compatibility hack. + # kdesvn-build 0.97 and earlier would physically copy the Qt source + # directory to the build directory. kdesvn-build versions after that use + # the lndir program that is used for kdebindings and valgrind for + # portability reasons. This will break for users who have a real copy of + # Qt, so check here if the qt-copy configure script file is a real file + # (not a symlink), and if so, use the old method (since presumably it + # worked earlier). + if ($module eq 'qt-copy' and -e "$builddir/configure" and not -l "$builddir/configure") + { + whisper "Using deprecated qt-copy builddir faking method."; + + # Use old method of copying. + $args = [ 'cp', '-af', $srcdir, $builddir ]; + } + + # Use an internal routine to complete the directory symlinking (or the + # alternate routine in the case of old qt-copy). + if (log_command ($module, 'create-builddir', $args)) + { + warning "\tUnable to setup special build system for r[$module]."; + return 0; + } + + return 1; # Success +} + +# Subroutine to create the build system for a module. This involves making +# sure the directory exists and then running make -f Makefile.cvs. This +# subroutine assumes that the module is already downloaded. +sub safe_create_build_system +{ + my $module = shift; + my $fullpath = get_fullpath($module, 'source'); + my $builddir = get_fullpath($module, 'build'); + my $instapps = get_option($module, 'inst-apps'); + + if (pretending) + { + pretend "\tWould have created g[$module]\'s build system."; + return 0; + } + + chdir ($fullpath); # Run make -f Makefile.cvs in srcdir. + + # These modules will run make -f Makefile.cvs in (fake) builddir to keep + # srcdir clean. Except for qt-copy when not using qt-builddir-hack. + if(module_needs_builddir_help($module)) + { + chdir ($builddir); + } + + return 0 if $module eq 'qt-copy'; # since 3.3.6 + + if ($instapps) + { + open (INSTAPPS, ">inst-apps") or do { + error "\tUnable to create inst-apps file for r[$module]!"; + return 1; + }; + + print INSTAPPS "$instapps\n"; + close INSTAPPS; + } + else + { + unlink ("$fullpath/inst-apps"); + } + + my $cmd_ref = [ 'make', '-f', 'Makefile.cvs' ]; + $cmd_ref = [ './autogen.sh' ] if $module eq 'valgrind'; + + if (log_command ($module, "build-system", $cmd_ref)) + { + error "\tUnable to create build system for r[$module]"; + return 1; + } + + return 0; +} + +# Subroutine to determine if a given module needs to have the build system +# recreated from scratch. +# If so, it returns boolean true. +sub needs_refreshed +{ + my $module = shift; + my $builddir = get_fullpath($module, 'build'); + my $conf_file_key = "Makefile"; # File that exists after configure is run + + # Use a different file to indicate configure has been run for qt-copy + $conf_file_key = "src/tools/qconfig.cpp" if $module eq 'qt-copy'; + + if (debugging) + { + debug "Build directory not setup for $module." if not -e "$builddir"; + debug ".refresh-me exists for $module." if -e "$builddir/.refresh-me"; + debug "refresh-build option set for $module." if get_option($module, 'refresh-build'); + debug "Can't find configure key file for $module." if not -e "$builddir/$conf_file_key"; + } + + return 1 if ((not -e "$builddir") || + (-e "$builddir/.refresh-me") || + get_option($module, "refresh-build") || + (not -e "$builddir/$conf_file_key")); + + return 0; +} + +# Run the svn command. This is a special subroutine so that we can munge the +# generated output to see what files have been added, and adjust the build +# according. +# First parameter is the module we're building. +# Second parameter is the filename to use for the log file. +# Third parameter is a reference to a list, which is the command ('svn') and all +# of its arguments. +sub run_svn +{ + my ($module, $logfilename, $arg_ref) = @_; + my %hash_count; + my $result; + my $force_refresh = 0; + my $conflict = 0; + my $logdir = get_log_dir($module); + + my $revision = get_option('global', 'revision'); + if ($revision ne '0') + { + my @tmp = @{$arg_ref}; + + # Insert after first two entries, deleting 0 entries from the + # list. + splice @tmp, 2, 0, '-r', $revision; + $arg_ref = \@tmp; + } + + # Do svn update. + $result = log_command($module, $logfilename, $arg_ref); + + # There will be no result if we're pretending, so don't even + # bother. + return 0 if pretending; + + $logfilename = "$logdir/$logfilename.log"; + + # We need to open the file and try to determine what the Subversion process + # did. + open SVN_LOG, "<$logfilename"; + while (<SVN_LOG>) + { + # The check for capitalized letters in the second column is because + # svn can use the first six columns for updates (the characters will + # all be uppercase), which makes it hard to tell apart from normal + # sentences (like "At Revision foo" + + # Count updates and patches together. + $hash_count{'updated'}++ if /^U[ A-Z]/; + $hash_count{'updated'}++ if /^P[ A-Z]/; + $hash_count{'deleted'}++ if /^D[ A-Z]/; + $hash_count{'added'}++ if /^A[ A-Z]/; + $hash_count{'removed'}++ if /^R[ A-Z]/; + $hash_count{'merged'}++ if /^G[ A-Z]/; + $hash_count{'modified'}++ if /^M[ A-Z]/; + $hash_count{'conflicted'}++ if /^C[ A-Z]/; + + # Check if we need to force a refresh. + $force_refresh = 1 if /^A[ A-Z]/ and /Makefile\.am/; + $force_refresh = 1 if /^[PAMGU][ A-Z]/ and /configure\.in\.in/; + + $conflict = 1 if /^C[ A-Z]/; + } + + close SVN_LOG; + + my %endings = ( + 'updated' => 'files were updated', + '1updated' => 'file was updated', + 'added' => 'files were added', + '1added' => 'file was added', + 'removed' => 'files were removed', + '1removed' => 'file was removed', + 'modified' => 'files were modified', + '1modified' => 'file was modified', + 'conflicted' => 'files had conflicts', + '1conflicted' => 'file had conflicts', + 'deleted' => 'files were deleted', + '1deleted' => 'file was deleted', + 'merged' => 'files had changes merged', + '1merged' => 'file had changes merged', + ); + + my ($key, $value); + while (($key, $value) = each %hash_count) + { + next unless $value > 0; + my $ending_key = $value > 1 ? $key : ('1' . $key); + my $ending = $endings{$ending_key}; + info "\t$value $ending."; + } + + if ($conflict) + { + warning "Source code conflict exists in r[$module], this module will not"; + warning "build until it is resolved."; + dont_build($module); + + return $result; + } + + if ($force_refresh and -e get_fullpath($module, 'build')) + { + info "File(s) related to the build system were updated, forcing a refresh."; + set_option($module, 'refresh-build', 1); + set_option($module, '#cancel-clean', 1); + } + + return $result; +} + +# Subroutine to clean the build system for the given module. Works by +# recursively deleting the directory and then recreating it. Returns +# 0 for failure, non-zero for success. +sub clean_build_system +{ + my $module = shift; + my $moduledir = get_fullpath($module, 'source'); + my $builddir = get_fullpath($module, 'build'); + + if (pretending) + { + pretend "\tWould have cleaned build system for g[$module]"; + return 1; + } + + if (not -e $moduledir) + { + warning "\tUnable to clean build system for r[$module], it's not been checked out!"; + return 0; + } + + # Clean qt-copy separately + if ($module eq 'qt-copy' and not get_option('qt-copy', 'use-qt-builddir-hack')) + { + chdir ("$builddir"); + + if (log_command ('qt-copy', 'clean', ['make', 'clean'])) + { + warning "\tr[WARNING]: Error cleaning r[qt-copy]."; + } + + unlink ("$builddir/.qmake.cache"); + + return 1; + } + + if (-e "$builddir") + { + if(safe_system ('rm', '-rf', "$builddir")) + { + # Remove build directory for normal module. + error "\tUnable to clean r[$builddir]."; + return 0; # False for this function. + } + + # Let users know we're done so they don't wonder why rm -rf is taking so + # long and oh yeah, why'd my HD so active?... + info "\tOld build system cleaned, starting new build system."; + } + + # Now create the directory + if (not super_mkdir ("$builddir")) + { + error "\tUnable to create directory r[$builddir]."; + return 0; + } + + return 1; +} + +# Subroutine to setup the build system in a directory. The first parameter +# is the module name. Returns boolean true on success, boolean false (0) +# on failure. +sub setup_build_system +{ + my $module = shift; + my $fullpath = get_fullpath($module, 'source'); + my $builddir = get_fullpath($module, 'build'); + my $do_configure = get_option ($module, 'reconfigure'); + my $do_makeconf = get_option ($module, 'recreate-configure'); + + if (needs_refreshed($module)) + { + # The build system needs created, either because it doesn't exist, or + # because the user has asked that it be completely rebuilt. + info "\tPreparing build system for y[$module]."; + + # Define this option to tell later functions that we tried to rebuild + # this module. + set_option($module, '#was-rebuilt', 1); + + # Check to see if we're actually supposed to go through the cleaning + # process. + if (not get_option($module, '#cancel-clean') and + not clean_build_system($module)) + { + warning "\tUnable to clean r[$module]!"; + return 0; + } + + $do_makeconf = 1; + } + + # Symlink source directory to build directory if module doesn't support + # srcdir != builddir. If it's qt-copy only do so if use-qt-builddir-hack + # is on (true by default). Note that module_needs_builddir_help() already + # takes care of that test. + if (module_needs_builddir_help($module)) + { + whisper "\tFaking builddir for g[$module]"; + if (not prepare_fake_builddir($module)) + { + error "Error creating r[$module] build system!"; + return 0; + } + } + + # Check for admin dir, if it doesn't exist, create a softlink + if (not create_admin_dir($module)) + { + warning "Unable to find /admin directory for y[$module], it probably"; + warning "won't build."; + # But continue anyways, because in this case I'm just not sure that it + # won't work in the future. ;) + } + + my $confpath = module_needs_builddir_help($module) ? $builddir : $fullpath; + + if ($do_makeconf or not -e "$confpath/configure") + { + whisper "\ty[Recreating configure script]."; + + # Update the PATH and other important environment variables. + update_module_environment ($module); + + if (safe_create_build_system ($module)) + { + error "\tUnable to create configure system from checkout."; + return 0; + } + + $do_configure = 1; + + if ($module eq "qt-copy" and get_option($module, 'apply-qt-patches')) + { + # Run apply-patches script + return 0 if safe_apply_patches (); + } + + # Check to see if we're supposed to stop here + return 1 if get_option ($module, 'build-system-only'); + } + + # File which exists after configure has been run. + my $conf_key_file = "$builddir/Makefile"; + $conf_key_file = "$builddir/src/tools/qconfig.cpp" if $module eq 'qt-copy'; + + if ($do_configure or not -e $conf_key_file) + { + if (not -e "$builddir" and not super_mkdir("$builddir")) + { + error "\tUnable to create build directory for r[$module]!!"; + return 0; + } + + # Now we're in the checkout directory + # So, switch to the build dir. + # builddir is automatically set to the right value for qt-copy + chdir ("$builddir"); + + # configure the module (sh script return value semantics) + if (safe_configure ($module)) + { + error "\tUnable to configure r[$module]!"; + return 0; + } + } + + return 1; +} + +# Subroutine to setup the environment for a module. First parameter is the name of +# the module to set the environment for +sub update_module_environment +{ + my $module = shift; + my $kdedir = get_option ($module, 'kdedir'); + my $qtdir = get_option ($module, 'qtdir'); + my $path = join(':', "$qtdir/bin", "$kdedir/bin", get_option ($module, 'binpath')); + my $libdir = join(':', "$qtdir/lib", "$kdedir/lib", get_option ($module, 'libpath')); + + # Set up the children's environment. We use setenv since it + # won't set an environment variable to nothing. (e.g, setting + # QTDIR to a blank string might confuse Qt or KDE. + + # Remove leading and trailing colons, just in case. + # Also remove more than one colon. + for ($path, $libdir) + { + s/:+/:/; + s/^:*//; + s/:*$//; + } + + # Everyone loves unsermake. It's a pity that not every module will compile with it. + # Benjamin Meyer has an excellent article about speeding up distributed builds using + # unsermake. You should notice a much faster build using distcc, and + # a slightly faster build even with only one CPU. + if (get_option ($module, "use-unsermake")) + { + my $kdenonbeta = get_fullpath('kdenonbeta', 'source'); + $path = "$kdenonbeta/unsermake:$path"; + } + else + { + setenv ("UNSERMAKE", "no"); + } + + setenv ('LD_LIBRARY_PATH', $libdir); + setenv ('PATH', $path); + setenv ('KDEDIR', $kdedir); + setenv ('QTDIR', $qtdir); + + # Qt has several defines of its own. Special case qt-copy for this + # reason. + setenv ("YACC", 'byacc -d') if ($module eq "qt-copy"); + + # Read in user environment defines + setup_module_environment ($module); +} + +# Subroutine to make sure the build directory for a module is setup. +# The module to setup is the first parameter. +# +# Returns boolean true on success, boolean false on failure. +sub setup_build_directory +{ + my $module = shift; + my $builddir = get_build_dir($module); + + if (not -e "$builddir") + { + whisper "\ty[$builddir] doesn't exist, creating."; + if (not super_mkdir ("$builddir")) + { + error "\tUnable to create r[$builddir]!"; + return 0; + } + } + + return 1; +} + +# Subroutine to return a string suitable for displaying an elapsed time, (like +# a stopwatch) would. The first parameter is the number of seconds elapsed. +sub prettify_seconds +{ + my $elapsed = $_[0]; + my $str = ""; + my ($days,$hours,$minutes,$seconds,$fraction); + + $fraction = int (100 * ($elapsed - int $elapsed)); + $elapsed = int $elapsed; + + $seconds = $elapsed % 60; + $elapsed = int $elapsed / 60; + + $minutes = $elapsed % 60; + $elapsed = int $elapsed / 60; + + $hours = $elapsed % 24; + $elapsed = int $elapsed / 24; + + $days = $elapsed; + + $seconds = "$seconds.$fraction" if $fraction; + + my @str_list; + + for (qw(days hours minutes seconds)) + { + # Use a symbolic reference without needing to disable strict refs. + # I couldn't disable it even if I wanted to because these variables + # aren't global or localized global variables. + my $value = eval "return \$$_;"; + my $text = $_; + $text =~ s/s$// if $value == 1; # Make singular + + push @str_list, "$value $text" if $value or $_ eq 'seconds'; + } + + # Add 'and ' in front of last element if there was more than one. + push @str_list, ("and " . pop @str_list) if (scalar @str_list > 1); + + $str = join (", ", @str_list); + + return $str; +} + +# Subroutine to determine if a given module can run make apidox. Returns +# boolean true if make apidox can be run. +sub make_apidox_supported +{ + my $module = shift; + + return $module =~ /^(KDE\/)?(kde(base|games|graphics|libs|pim|velop)|koffice)$/; +} + +# Subroutine to build a given module. The module to build is the first +# parameter. The second and third paramaters is the ordinal number of the +# module being built (1 == first module, 2 == second, etc.), and the total +# number of modules being built respectively. +# +# Returns boolean false on failure, boolean true on success. +sub build_module +{ + my $module = shift; + my $cur_module_num = shift; + my $total_module_num = shift; + my $apidox = shift; + my $builddir = get_fullpath($module, 'build'); + my $trynumber = 1; + + # Do some tests to make sure we're ready to build. + if (not exists $package_opts{$module}) + { + warning "Unknown module y[$module], configure it in $rcfile."; + $package_opts{$module} = { 'set-env' => { } }; + } + + update_module_environment($module); + + if($module eq 'qt-copy' and $builddir ne get_option('global', 'qtdir')) + { + my $qtpath = $builddir; + $qtpath =~ s/$ENV{HOME}/~/; + warning <<EOF; + +b[y[!!] You're building qt-copy, but QTDIR isn't set to use qt-copy! +b[y[!!] Please set your qtdir variable in the global section of your +b[y[!!] $rcfile to g[$qtpath] + +EOF + } + + my $start_time = time; + while (not defined $package_opts{$module}->{'#was-rebuilt'}) + { + note "Building g[$module] ($cur_module_num/$total_module_num)"; + return 0 if not setup_build_directory($module); + return 0 if not setup_build_system($module); + return 1 if (get_option ($module, 'build-system-only')); + + if (safe_make ($module, $trynumber)) + { + # Build failed + # There are several reasons why the build could fail. If we're + # using unsermake for this module, then perhaps we just need to + # run make again. After that, we can re-run make -f Makefile.cvs + # and etc and then try make again. If that STILL doesn't work, we + # can try rm -rf $builddir/$module and rebuild. + + my $elapsed = prettify_seconds (time - $start_time); + my $was_rebuilt = defined $package_opts{$module}{'#was-rebuilt'}; + $start_time = time; + + ++$trynumber; + + if ($trynumber > 3 or $was_rebuilt or get_option ($module, 'no-rebuild-on-fail')) + { + # Well we tried, but it isn't going to happen. + note "\n\tUnable to build y[$module]!"; + info "\tTook g[$elapsed]."; + return 0; + } + + if ($trynumber == 2) + { + # Just try again + info "\n\ty[Couldn't build, going to try again just in case]."; + info "\tTook g[$elapsed]."; + next; + } + + # Don't remove the old modules, but re-run make -f + # Makefile.cvs and configure. + info "\n\tStill couldn't build, recreating build system (builddir is safe)."; + info "\tTook g[$elapsed] of time."; + + set_option($module, '#cancel-clean', 1); + set_option($module, 'refresh-build', 1); + + # Loop again + } + else + { + # Build succeeded, build docs if necessary + my $apidox_result = 0; + my $build_apidox = make_apidox_supported($module) && get_option($module, 'apidox'); + if ($build_apidox) + { + $apidox_result = safe_make ($module, $trynumber, 1); + error "\tCouldn't build API Documentation" if $apidox_result; + } + + my $elapsed = prettify_seconds (time - $start_time); + my $do_install = get_option($module, 'install-after-build'); + + info "\tBuild done after g[$elapsed]."; + if ($do_install) + { + handle_install($module, 0); + handle_install($module, 1) if $build_apidox and $apidox_result == 0; + } + else + { + info "\tSkipping install for y[$module]"; + } + + last; # Don't forget to exit the loop! + } + } + + return 1; +} + +# Subroutine to handle the build process. +# First parameter is a reference of a list containing the packages +# we are to build. +# If the packages are not already checked-out and/or updated, this +# subroutine WILL NOT do so for you. +# +# This subroutine assumes that the $kdesvn directory has already been +# set up. It will create $builddir if it doesn't already exist. +# +# If $builddir/$module/.refresh-me exists, the subroutine will +# completely rebuild the module. +# +# Returns 0 for success, non-zero for failure. +sub handle_build +{ + my @build_done; + my $build_ref = shift; + my $kdesvn = get_kdesvn_dir(); + my $svnroot = get_option ('global', 'svn-server'); + my $module; + my @modules = grep (!/^(KDE\/)?kde-common$/, @{$build_ref}); + my $result; + my $outfile = get_output_file (); + + # No reason to print building messages if we're not building. + return 0 if scalar @modules == 0; + + note "<<< Build Process >>>"; + + # Save the environment to keep module's env changes from affecting other + # modules. + my %env_backup = %ENV; + + if (pretending) + { + pretend "\tWould have opened status file g[$outfile]."; + $outfile = undef; # Don't actually try it though. + } + + if ($outfile) + { + open STATUS_FILE, ">$outfile" or do { + error <<EOF; + Unable to open output status file r[b[$outfile] + You won't be able to use the g[--resume] switch next run.\n"; +EOF + $outfile = undef; + }; + } + + my $num_modules = scalar @modules; + my $i = 1; + + while ($module = shift @modules) + { + my $start_time = time; + + if (build_module ($module, $i, $num_modules)) + { + my $elapsed = prettify_seconds(time - $start_time); + print STATUS_FILE "$module: Succeeded after $elapsed.\n" if $outfile; + + info "\tOverall time for g[$module] was g[$elapsed]."; + push @build_done, $module; + } + else + { + my $elapsed = prettify_seconds(time - $start_time); + print STATUS_FILE "$module: Failed after $elapsed.\n" if $outfile; + + info "\tOverall time for r[$module] was g[$elapsed]."; + push @{$fail_lists{'build'}}, $module; + + if (get_option($module, 'stop-on-failure')) + { + note "\n$module didn't build, stopping here."; + return 1; # Error + } + } + + print "\n"; + %ENV = %env_backup; + $i++; + } + + # If we have packages that failed to update we should probably mention them + # in the build-status file as well. + if ($outfile) + { + for my $failure (@{$fail_lists{'update'}}) + { + print STATUS_FILE "$failure: Failed on update.\n"; + } + + close STATUS_FILE; + } + + info "<<< Build Done >>>\n"; + info "\n<<< g[PACKAGES SUCCESSFULLY BUILT] >>>" if scalar @build_done > 0; + + if (not pretending) + { + # Print out results, and output to a file + open BUILT_LIST, ">$kdesvn/successfully-built"; + foreach $module (@build_done) + { + info "$module"; + print BUILT_LIST "$module\n"; + } + close BUILT_LIST; + } + else + { + # Just print out the results + info 'g[', join ("]\ng[", @build_done), ']'; + } + + info " "; # Add newline for aesthetics if not in quiet mode. + return scalar @{$fail_lists{'build'}}; +} + +# Subroutine to exit the script cleanly, including removing any +# lock files created. If a parameter is passed, it is interpreted +# as an exit code to use +sub finish +{ + my $exitcode = shift; + my $logdir = get_log_dir('global'); + $exitcode = 0 unless $exitcode; + + close_lock() unless pretending; + + note "Your logs are saved in y[$logdir]"; + exit $exitcode; +} + +# Subroutine to determine the current repository URL for the current working +# directory. +sub get_repo_url +{ + my $output = `svn info | grep URL`; + $output =~ s/URL: (.*)$/$1/; + chomp $output; + + return $output; +} + +# Subroutine to determine whether or not the given module has the correct +# URL. If not, a warning is printed out. +# First parameter: module to check. +# Return: Nothing. +sub check_module_validity +{ + # This test reads the HD so don't bother during pretend. + return if pretending; + + my $module = shift; + my $source_dir = get_fullpath($module, 'source'); + my $module_expected_url = svn_module_url($module); + + chdir($source_dir); # Required for get_repo_url + my $module_actual_url = get_repo_url(); + + if($module_actual_url ne $module_expected_url) + { + warning <<EOF; + y[!!] + y[!!] g[$module] seems to be checked out from somewhere other than expected. + y[!!] + +kdesvn-build expects: y[$module_expected_url] +The module is actually from: y[$module_actual_url] + +If the module location is incorrect, you can fix it by either deleting the +g[b[source] directory, or by changing to the source directory and running + svn switch $module_expected_url + +If the module is fine, please update your configuration file. +EOF + } +} + +# Subroutine to handle the installation process. Simply calls +# 'make install' in the directory. +sub handle_install +{ + my $apidox = pop; # Take parameter off end of list (@_). + my @no_install_modules = qw/qt-copy kde-common/; + my $result = 0; + + for my $module (@_) + { + if (list_has(@no_install_modules, $module)) + { + info "\tg[$module] doesn't need to be installed."; + next; + } + + my $builddir = get_fullpath($module, 'build'); + + if (not exists $package_opts{$module}) + { + warning "\tUnknown module y[$module], configure it in $rcfile."; + $package_opts{$module} = { 'set-env' => { } }; + next; + } + + if (not -e "$builddir/Makefile") + { + warning "\tThe build system doesn't exist for r[$module]."; + warning "\tTherefore, we can't install it. y[:-(]."; + next; + } + + # Just in case, I guess. + update_module_environment ($module); + + # The /admin directory is needed for install as well, make sure it's + # there. + if (not create_admin_dir($module)) + { + warning "Unable to find /admin directory for y[$module], it probably"; + warning "won't install."; + # But continue anyways, because in this case I'm just not sure that it + # won't work in the future. ;) + } + + # safe_make() evilly uses the "install" parameter to use installation + # mode instead of compile mode. This is so we can get the subdirectory + # handling for free. + if (safe_make ($module, "install", $apidox)) + { + error "\tUnable to install r[$module]!"; + $result = 1; + push @{$fail_lists{'install'}}, $module; + + if (get_option($module, 'stop-on-failure')) + { + note "y[Stopping here]."; + return 1; # Error + } + } + + if (pretending) + { + pretend "\tWould have installed g[$module]"; + next; + } + + next if $result != 0; # Don't delete anything if the build failed. + + my $remove_setting = get_option($module, 'remove-after-install'); + + # Possibly remove the srcdir and builddir after install for users with + # a little bit of HD space. + if($remove_setting eq 'all') + { + # Remove srcdir + my $srcdir = get_fullpath($module, 'source'); + note "\tRemoving b[r[$module source]."; + system ('rm', '-rf', $srcdir); + } + + if($remove_setting eq 'builddir' or $remove_setting eq 'all') + { + # Remove builddir + note "\tRemoving b[r[$module build directory]."; + system ('rm', '-rf', $builddir); + } + } + + return $result; +} + +# This subroutine goes and makes sure that any entries in the update and build +# lists that have a directory separator are faked into using the checkout-only +# feature. This doesn't really work for install mode though. +sub munge_lists +{ + debug "Munging update and build list"; + my $cleared = 0; + + for my $list_ref ( ( \@update_list, \@build_list) ) { + my @temp; + + while ($_ = shift @$list_ref) { + # Split at directory separators. + my ($modulename, @dirs) = split(/\//); + + # For these modules, the first part of the directory separator + # actually belongs with the module name. + if (has_base_module($modulename)) + { + $modulename .= "/" . shift @dirs; + } + + if (scalar @dirs > 0) + { + # Only build the specified subdirs + if (not $cleared) + { + debug "Clearing checkout-only option."; + + $cleared = 1; + set_option($modulename, 'checkout-only', ''); + } + + # The user has included a directory separator in the module name, so + # let's fake the svn partial checkout + $_ = $modulename; + + # Don't automatically add the /admin dir for this module now. + set_option($_, '#suppress-auto-admin', 1); + + my $checkout_str = join ("/", @dirs); + + debug "Adding $checkout_str to checkout-only for $_"; + + if (get_option($_, 'checkout-only') !~ /$checkout_str/) + { + $package_opts{$_}{'checkout-only'} .= " $checkout_str"; + } + else + { + debug print "\tOption was already present."; + } + } + else + { + debug "Skipping $_ in munge process."; + } + + # Don't add the modulename to the list twice. + push @temp, $_ if not list_has(@temp, $_); + } + + @$list_ref = @temp; + } +} + +# Subroutine to try an intelligently determine what caused the module to fail +# to build/update/whatever. The first parameter is the name of the module, +# and the return value is the best guess at the error. If no error is detected +# the last 30 lines of the file are returned instead. +sub whats_the_module_error +{ + my $module = shift; + my $file = get_option($module, '#error-log-file'); + + open ERRORFILE, "<$file" or return "Can't open logfile $file.\n"; + + my @lastlines; # Used to buffer last lines read. + my @errors; # Tracks errors and the file they were found in. + my $lastfile = ''; # Tracks last filename read in error log. + my $errorCount = 0; + my $output; + + # TODO: This code is tested for gcc and GNU ld, as, etc, I'm not sure how + # effective it is at parsing the error output of other build toolchains. + while (<ERRORFILE>) + { + # Keep last 30 lines. + push @lastlines, $_; + shift @lastlines if scalar @lastlines > 30; + + my ($file, $line, $msg) = /^([^:]*):(\d+):\s*(.*)$/; + + next unless ($file and $line and $msg); + next if $msg =~ /warn/i; + next if $msg =~ /^in file included from/i; + next if $msg =~ /^\s*$/ or $file =~ /^\s*$/; + $msg =~ s/^error: ?//i; + + if ($file eq $lastfile) + { + $errorCount++; + push @errors, $msg if $errorCount < 5; + } + else + { + # Check is because we print info on the last file read, so there + # should be a last file. ;) + if ($lastfile) + { + my $error = $errorCount == 1 ? "error" : "errors"; + $output .= "$errorCount $error in $lastfile\n"; + $output .= "Error: $_\n" foreach (@errors); + $output .= "\t<clipped>\n" if $errorCount > 5; + $output .= "\n"; + } + + $errorCount = 1; + @errors = ($msg); + } + + $lastfile = $file; + } + + close ERRORFILE; + + if (not $lastfile) + { + # Print out last lines read, hopefully a more descriptive error + # message is in there. + $output .= "Can't find errors, last " . scalar @lastlines . " line(s) of the output are:\n"; + $output .= $_ foreach (@lastlines); + return $output; + } + + # Don't forget to display info on last file read since it won't be done in + # the loop. + my $error = $errorCount == 1 ? "error" : "errors"; + $output .= "$errorCount $error in $lastfile\n"; + $output .= "Error: $_\n" foreach (@errors); + $output .= "\t<clipped>\n" if $errorCount > 5; + + return $output; +} + +# Subroutine to get the e-mail address to send e-mail from. +# It is pulled from the global email-address option by default. +# The first parameter is a default e-mail address to use (may be left off, in +# which case this function will create a default of its own if necessary.) +sub get_email_address +{ + my $email = get_option('global', 'email-address'); + my $default = shift; + + # Use user's value if set. + return $email if $email; + + # Let's use the provided default if set. + return $default if $default; + + # Let's make a default of our own. It's likely to suck, so oh well. + use Sys::Hostname; + my $username = getpwuid($>); + my $hostname = hostname; # From Sys::Hostname + + debug "User has no email address, using $username\@$hostname"; + + return "$username\@$hostname"; +} + +# Subroutine to look through the various failed lists, and send an email to the +# given email address with a description of the failures. If the user has +# selected no email address the subroutine does nothing. +sub email_error_report +{ + my $email_addy = get_option('global', 'email-on-compile-error'); + my $from_addy = get_email_address($email_addy); + + return unless $email_addy; + + # Initial e-mail header. + my $email_body = <<EOF; +The following errors were detected in the kdesvn-build run just completed. + +EOF + + # Loop through modules trying to find out what caused the errors. + my $had_error = 0; + for my $type (@fail_display_order) + { + for my $module (@{$fail_lists{$type}}) + { + $email_body .= "$module failed to $type:\n"; + $email_body .= "-------------------------------\n\n"; + $email_body .= whats_the_module_error($module); + $email_body .= "-------------------------------\n\n"; + + $had_error = 1; + } + } + + return unless $had_error; + + # Detect Mail::Mailer. + my $mailer; + eval { + require Mail::Mailer; + + $mailer = new Mail::Mailer; + } or do { + error " y[*] Can't open y[b[Mail::Mailer] module, so e-mailing is disabled."; + debug "Error was $@"; + return; + }; + + # Sendeth the email. + $mailer->open({ + 'From' => $from_addy, + 'To' => $email_addy, + 'Subject' => 'KDE Subversion build compile error', + }); + + print $mailer $email_body; + $mailer->close; +} + +# This subroutine sets up or removes the default branch option for a few +# modules in order to build KDE 3.5 by default. branch options in the +# configuration file will still override these settings. +sub setup_kde35_hack +{ + my @branched_modules = qw/kde-common kdeaccessibility kdeaddons kdeadmin + kdeartwork kdebase kdebindings kdeedu kdegames kdegraphics kdelibs + kdemultimedia kdenetwork kdepim kdesdk kdetoys kdeutils kdevelop + kdewebdev/; + + # arts uses a different versioning scheme. + set_option('arts', 'branch', '1.5'); + + # koffice 1.5 is the last KDE 3 compatible release. + set_option('koffice', 'branch', '1.5'); + + # qt-copy is in branches/qt/3.3. Due to the default option handling the + # handling is done in setup_default_modules(). + # set_option('qt-copy', 'module-base-path', 'branches/qt/3.3'); + + for my $module (@branched_modules) + { + # Default to downloading from KDE 3.5 instead of KDE 4. + set_option($module, 'branch', '3.5'); + } +} + +# Script starts. + +# Use some exception handling to avoid ucky error messages +eval +{ + # Note to self: Quit changing the order around. + process_arguments(); # Process --help, --install, etc. first. + setup_kde35_hack(); # Add 'branch' options as appropriate. + read_options(); # If we're still here, read the options + initialize_environment(); # Initialize global env vars. + + setup_logging_subsystem(); # Setup logging directories. + + dump_options() if debugging; +}; + +if ($@) +{ + # We encountered an error. + print "Encountered an error in the execution of the script.\n"; + print "The error reported was $@\n"; + print "Please submit a bug against kdesvn-build on http://bugs.kde.org/\n"; + + # Don't finish, because we haven't attained the lock yet. + exit 99; +} + +if (not pretending and not get_lock()) +{ + print "$0 is already running!\n"; + exit 0; # Don't finish(), it's not our lockfile!! +} + +# Now use an exception trapping loop that calls finish(). +my $result; +eval +{ + my $time = localtime; + info "Script started processing at g[$time]"; + + @update_list = get_update_list(); + @build_list = get_build_list(); + + debug "Update list is ", join (', ', @update_list); + debug "Build list is ", join (', ', @build_list); + + # Do some necessary adjusting. Right now this is used for supporting + # the command-line option shortcut to where you can enter e.g. + # kdelibs/khtml, and the script will only try to update that part of + # the module. + munge_lists(); + + # Make sure unsermake is checked out automatically if needed + adjust_update_list(\@update_list, \@build_list); + + if (not $install_flag) + { + # No packages to install, we're in build mode + $result = handle_updates (\@update_list); + $result = handle_build (\@build_list) || $result; + } + else + { + # Installation mode (no apidox) + $result = handle_install (get_install_list(), 0); + } + + output_failed_module_lists(); + email_error_report(); + + $time = localtime; + my $color = ''; + $color = 'r[' if $result; + + info "${color}Script finished processing at g[$time]"; +}; + +if ($@) +{ + # We encountered an error. + print "Encountered an error in the execution of the script.\n"; + print "The error reported was $@\n"; + print "Please submit a bug against kdesvn-build on http://bugs.kde.org/\n"; + + $result = 99; +} + +finish($result); + +# vim: set et sw=4 ts=4: diff --git a/scripts/kdesvn-buildrc-sample b/scripts/kdesvn-buildrc-sample new file mode 100644 index 00000000..a19e13da --- /dev/null +++ b/scripts/kdesvn-buildrc-sample @@ -0,0 +1,246 @@ +# Sample configuration file for kdesvn-build. (Applies to KDE 3.5) +# +# To use this sample configuration file, copy it to ~/.kdesvn-buildrc, and then +# edit it to suit your desires. + +# Global settings go in this section. They apply to every module unless +# overridden later. +global + +# binpath controls the value of the PATH environment variable during +# compilation. If you have unusual tools that need to be in the path to build +# KDE, add them here. KDE's and Qt's programs are automatically added. + binpath /bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin +# binpath /usr/lib/ccache/bin:/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin + +# This is the directory that your KDE sources are downloaded to. This +# directory also holds the build and log directories by default. +# source-dir ~/kdesvn + +# This is the Qt installation to use to build KDE. The default is qt-copy +# from Subversion. + qtdir ~/kdesvn/build/qt-copy + +# You might want to use your system's built-in Qt already (3.3 or greater, not +# 4.x). If so, assign the qtdir option appropriately. +# qtdir /path/to/system/qt + +# This is the Subversion server to download the KDE sources from. Developers: +# Don't forget to add your username to the URL if necessary! +# svn-server svn://anonsvn.kde.org/home/kde + +# This controls the configure flags passed to every module (except qt-copy) by +# default. If you have module-specific configure flags, they will be placed +# after these flags to allow the module setting to override the global setting. + configure-flags --enable-debug + +# These are the compilation flags to use by default when compiling KDE. +# gcc supports a -march option in order to generate specific code for pentium4, athlon-xp, +# etc. See the gcc man page for more information. + cxxflags -pipe + +# These are the default options passed to the make command. The default tries +# to build with 2 parallel compiles. If you are using distcc or have SMP, you +# should experiment with setting this value higher for best performance. +# make-options -j2 + +# These are the default options passed to unsermake, which supports some +# options not present with make. The default tries to run 2 compile jobs +# in parallel. The -p option is used to display progress information. +# unsermake-options --compile-jobs=2 -p + +# This option is used to decide whether to use the unsermake build system, which +# is usually faster and more efficient than the standard automake-based build +# system. It is generally stable enough to use, so it defaults to on. You +# can disable this on a module-by-module basis if it gives you problems. +# use-unsermake true + +# This directory is where everything gets built before it is installed. By +# default it is relative to the value for source-dir. You can specify an +# absolute path if you'd like (begin the path with a slash). +# build-dir build + +# This is the directory that KDE will end up installed at. The default is +# appropriate for a single-user installation of KDE, which requires no root +# permissions. If you'd like, you can install and use the sudo program to +# install KDE anywhere on your system, in conjunction with the +# make-install-prefix option. +# kdedir ~/kde +# +# You can overwrite the installation directory for a given module using +# the per-module "prefix" option. Note that when doing this you need to +# set KDEDIRS, PATH and LD_LIBRARY_PATH to point to both directories, +# and that you should use separate test users or KDEHOME values to separate +# the ksycoca databases. Only set prefix if you know what you're doing. + +# If you would like install KDE to the system (DO NOT INSTALL *over* a prior +# installation!), then you'll probably need to use sudo to install everything. +# make-install-prefix sudo + +# You can use the set-env option to add values to the build environment. + set-env LDFLAGS -Wl,-O1 # Optimize the linker, takes longer. + +# If you use software which requires pkg-config, and you need to add entries +# to your pkg-config path, you can also use set-env for that. Some broken +# systems require you to set this to find e.g. glib. +# set-env PKG_CONFIG_PATH /opt/gnome/lib/pkgconfig +end global + +# qt-copy is a copy of Trolltech's Qt, optionally with some bugfixes and +# optimizations added. It is the easiest way to get Qt if you don't already +# have it (and you don't want to use your distro's tools to install it.) +module qt-copy + configure-flags -system-zlib -qt-gif -system-libjpeg -system-libpng \ + -plugin-imgfmt-mng -thread -no-exceptions -debug \ + -fast -dlopen-opengl + apply-qt-patches true + use-qt-builddir-hack true + + # trunk's qt-copy is 4.x now. + module-base-path branches/qt/3.3 +end module + +# arts is the KDE sound library. +module arts +end module + +# kdesupport contains taglib and QCA. taglib is required for JuK, amarok, and +# the meta info reader for music files in Konqueror. +module kdesupport +end module + +# kdelibs are the base KDE libraries needed by all KDE applications. +module kdelibs + configure-flags --enable-sendfile --enable-mitshm + +# If you're a programmer you may want to build the API docs. Note that +# it takes some time. :( +# apidox true +end module + +# kdebase contains useful general-purpose programs, normally people would +# expect a usable desktop to have these. +module kdebase + configure-flags --with-pam --with-shadow +end module + +# kdemultimedia contains JuK, noatun, Kaboodle, and other KDE multimedia +# applications. It does not include amarok, which is in extragear/multimedia +module kdemultimedia +end module + +# kdesdk is a useful module for software developers. It is where kdesvn-build +# is developed. +module kdesdk +end module + +# kdenetwork has Kopete and other useful applications for the Internet and +# other networks. +module kdenetwork +end module + +# kdeadmin has system administration tools for your computer. +module kdeadmin + configure-flags --with-shadow --with-pam=yes +end module + +# kdebindings is useful for software developers, and for those who wish to run +# some KDE programs that don't use C++. The python bindings are not included +# by default as they never build for me. If you'd like to build all the +# bindings, comment out the checkout-only option below. +module kdebindings + checkout-only admin dcopc kalyptus smoke qtruby korundum kjsembed dcoppython + +# kdebindings will probably need to use the following option to install +# successfully. You must configure the sudo program first to allow for +# passwordless operation. +# make-install-prefix sudo + use-unsermake false +end module + +# kdepim contains KMail, Kontact, KOrganizer, and other insanely useful +# programs that help you keep track of things. +module kdepim + configure-flags --disable-exchange +end module + +# kdeutils has miscellaneous programs which can be useful. You probably won't +# die if you remove this from the config file though. +module kdeutils +end module + +# kdegraphics contains various programs useful for graphics editing. It +# doesn't include Krita, which is part of KOffice, but it is worth it just for +# KolourPaint. +module kdegraphics +end module + +# kdeaddons are nifty additions to some programs in other KDE modules. For +# example, there are addons for Konqueror, extra Kicker applets, and Noatun +# plugins. +module kdeaddons +end module + +# ... Well, they're games. ;) +module kdegames +# use-unsermake false +end module + +# Contains nifty diversions of time, which generally aren't games. +module kdetoys +end module + +# Educational programs. Some are actually quite fun even if you're not trying +# to learn anything. +module kdeedu +end module + +# The KDE Office Suite. Includes a pretty expansive collection of programs. +# It is rather large, so you can cut download and build times by removing it +# from this file. +module koffice + # branch 1.5 # KOffice /trunk is not compatible with KDE 3. +end module + +# The KDevelop IDE, useful for developing all kinds of programs. If you don't +# plan on being a software developer you can save time by removing this from +# your configuration. +module kdevelop + use-unsermake false +end module + +# Includes Quanta Plus and other web design tools. +module kdewebdev +end module + +# Modules in extragear and playground can also be added. +# To see what you can find in the various modules, browse +# http://websvn.kde.org/trunk/extragear and +# http://websvn.kde.org/trunk/playground + +# Includes various libraries needed by other applications in extragear. +module extragear/libs + +# If you don't like the default name that kdesvn-build gives modules on-disk, +# you can use dest-dir to change it. +# dest-dir extragear-libs +end module + +# Includes the popular K3B and Amarok programs. +module extragear/multimedia +end module + +# Includes various photo management applications. +module extragear/graphics + checkout-only digikamimageplugins digikam gwenview kimdaba +end module + +# module extragear/network +# # Options like checkout-only should work as before. +# checkout-only konversation +# end module + +# module playground/games +# end module + +# Add more modules as needed, they support the same options as before. diff --git a/scripts/kdesvn-buildrc.xml b/scripts/kdesvn-buildrc.xml new file mode 100644 index 00000000..08607889 --- /dev/null +++ b/scripts/kdesvn-buildrc.xml @@ -0,0 +1,152 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE language SYSTEM "language.dtd"> +<!-- This goes into $KDEDIR/share/apps/katepart/syntax, or + it can go to $KDEHOME/share/apps/katepart/syntax + --> +<language name="kdesvn-buildrc" version="0.2" kateversion="2.4" section="Configuration" extensions=".kdesvn-buildrc;kdesvn-buildrc" author="Michael Pyne <michael.pyne@kdemail.net>" license="LGPL"> + + <highlighting> + <list name="bools"> + <item>true</item> + <item>false</item> + <item>TRUE</item> + <item>FALSE</item> + <item>self</item> <!-- Only used by use-unsermake, don't feel like + forking a separate context for it though. --> + </list> + + <list name="setEnvOptions"> + <item>set-env</item> <!-- Handled separately for special syntax highlighting. --> + </list> + + <!-- These options should only have a boolean value passed to them. --> + <list name="boolOptions"> + <item>apidox</item> + <item>apply-qt-patches</item> + <item>build-system-only</item> + <item>colorful-output</item> + <item>debug</item> + <item>disable-agent-check</item> + <item>manual-build</item> + <item>manual-update</item> + <item>no-svn</item> + <item>no-rebuild-on-fail</item> + <item>pretend</item> + <item>reconfigure</item> + <item>recreate-configure</item> + <item>refresh-build</item> + <item>remove-after-install</item> + <item>stop-on-failure</item> + <item>use-unsermake</item> + <item>use-qt-builddir-hack</item> + </list> + + <list name="options"> + <item>binpath</item> + <item>branch</item> + <item>build-dir</item> + <item>checkout-only</item> + <item>configure-flags</item> + <item>cxxflags</item> + <item>debug-level</item> + <item>dest-dir</item> + <item>do-not-compile</item> + <item>email-address</item> + <item>email-on-compile-error</item> + <item>install-after-build</item> + <item>inst-apps</item> + <item>kdedir</item> + <item>libpath</item> + <item>log-dir</item> + <item>make-install-prefix</item> + <item>make-options</item> + <item>module-base-path</item> + <item>niceness</item> + <item>override-url</item> + <item>prefix</item> + <item>qtdir</item> + <item>revision</item> + <item>source-dir</item> + <item>svn-server</item> + <item>tag</item> + <item>unsermake-options</item> + <item>unsermake-path</item> + </list> + + <contexts> + <context name="Module" attribute="Normal Text" lineEndContext="#stay"> + <DetectSpaces/> + <RegExpr attribute="Comment" String="#.*$" context="#stay"/> + <RegExpr attribute="Global Declaration" context="Module Options" String="global" beginRegion="Global Options" firstNonSpace="true" /> + <RegExpr attribute="Module Declaration" context="Module Decl" String="module\s+" firstNonSpace="true" /> + </context> + + <context name="Module Decl" attribute="Module Name" lineEndContext="Module Options"> + <RegExpr String="[a-zA-Z0-9-]*" context="#stay" beginRegion="Module Options"/> + <RegExpr attribute="Comment" String="#.*$" context="#stay"/> + </context> + + <context name="Module Options" attribute="Normal Text" lineEndContext="#stay"> + <DetectSpaces/> + <RegExpr attribute="Comment" String="#.*$" context="#stay"/> + <keyword attribute="Option Name" context="Environment Name" String="setEnvOptions" /> + <keyword attribute="Option Name" context="Option Value" String="options"/> + <keyword attribute="Option Name" context="Bool Option Value" String="boolOptions"/> + + <RegExpr attribute="Module Declaration" context="Module" endRegion="Module Options" String="end module" firstNonSpace="true"/> + <RegExpr attribute="Module Declaration" context="Module" endRegion="Global Options" String="end global" firstNonSpace="true"/> + + <!-- No kdesvn-build options start with digits or a dash. --> + <RegExpr attribute="Possible Error" context="Option Value" String="[0-9-][a-zA-Z0-9-]+" /> + <RegExpr attribute="Unknown Option Name" context="Option Value" String="[a-zA-Z0-9-]+" /> + </context> + + <context name="Option Value" attribute="Normal Text" lineEndContext="#pop"> + <RegExpr attribute="Comment" String="#.*$" /> + <DetectSpaces/> + <RegExpr attribute="Variable" String="\$\{[a-zA-Z0-9-]+\}"/> + <RegExpr attribute="Option Value" String="[a-zA-Z:0-9,./+!=@-]*" context="#stay" /> + <LineContinue context="#stay"/> + <AnyChar attribute="Option Value" String="\\"/> + </context> + + <context name="Bool Option Value" attribute="Normal Text" lineEndContext="#pop"> + <keyword attribute="Option Value" context="#stay" String="bools"/> + <RegExpr attribute="Comment" String="#.*$" /> + <DetectSpaces/> + <RegExpr attribute="Possible Error" String="[^\\]*"/> + <LineContinue attribute="Possible Error" context="#stay"/> + <AnyChar attribute="Possible Error" String="\\"/> + </context> + + <context name="Environment Name" attribute="Environment Variable Name" lineEndContext="#pop"> + <RegExpr attribute="Comment" String="#.*$" /> + <DetectSpaces/> + <RegExpr attribute="Environment Variable Name" context="Option Value" String="[a-zA-Z0-9_-]+" /> + </context> + </contexts> + + <itemDatas> + <itemData name="Normal Text" defStyleNum="dsNormal" /> + <itemData name="Comment" defStyleNum="dsComment"/> + <itemData name="Boolean" defStyleNum="dsDecVal" bold="true" color="purple"/> + <itemData name="Option Name" defStyleNum="dsKeyword" bold="false" /> + <itemData name="Unknown Option Name" defStyleNum="dsKeyword" bold="false" color="#7D4C0B" /> + <itemData name="Environment Variable Name" defStyleNum="dsString" color="#EE6A50" /> + <itemData name="Option Value" defStyleNum="dsDecVal" /> + <itemData name="Variable" defStyleNum="dsOthers" /> + <itemData name="Module Declaration" defStyleNum="dsKeyword"/> + <itemData name="Module Name" defStyleNum="dsOthers" bold="true" /> + <itemData name="Global Declaration" defStyleNum="dsKeyword"/> + <itemData name="Possible Error" defStyleNum="dsError" /> + </itemDatas> + </highlighting> + + <general> + <comments> + <comment name="singleLine" start="#"/> + </comments> + <keywords weakDeliminator="-"/> + </general> + +</language> diff --git a/scripts/licensecheck b/scripts/licensecheck new file mode 100755 index 00000000..1640d9f5 --- /dev/null +++ b/scripts/licensecheck @@ -0,0 +1,63 @@ +#!/usr/bin/perl -w +# +# License checker for source files + +# This should kept in sync with kde-common/svn/hooks/post-commit.pl +sub checklicense($) +{ + my ($text) = @_; + + $text =~ y/\t\n\r/ /; + $text =~ y/ A-Za-z.,@1-9\(\)//cd; + $text =~ s/\s+/ /g; + + my ($gl, $qte, $license, $massave); + + $gl = ""; + $qte = ""; + $license = ""; + $massave = ""; + + $gl = " (v2)" if ($text =~ /version 2 as published by the Free Software Foundation/); + $gl = " (v2+)" if ($text =~ /either version 2 of the License, or .at your option. any later version/); + $gl = " (v2.1)" if ($text =~ /version 2\.1 as published by the Free Software Foundation/); + $gl = " (v2.1+)" if ($text =~ /either version 2\.1 of the License, or .at your option. any later version/); + $qte = " (+Qt exception)" if ($text =~ /([Pp]ermission is given|[pP]ermission is also granted|[pP]ermission) to link (the code of )?this program with (any edition of )?(Qt|the Qt library)/); + $massave = " (wrong address)" if ($text =~ /(?:675 Mass Ave|59 Temple Place|51 Franklin Steet|02139|02111-1307)/i); # "51 Franklin Street, 02110-1301" is the right FSF address + + $license="GENERATED FILE" if ($text =~ /(All changes made in this file will be lost|DO NOT EDIT|DO NOT delete this file|[Gg]enerated by)/); + $license="LGPL$gl$massave $license" if ($text =~ /is free software.? you can redistribute it and.?or modify it under the terms of the GNU (Library|Lesser) General Public License/); + $license="GPL$gl$qte$massave $license" if ($text =~ /is free software.? you can redistribute it and.?or modify it under the terms of the GNU General Public License/); + ### FIXME if the license matches the next regexp, it will probably match the following one too. + $license="QPL (part of Qt) $license" if ($text =~ /This file is part of the .*Qt GUI Toolkit. This file may be distributed under the terms of the Q Public License as defined/); + $license="QPL $license" if ($text =~ /may be distributed under the terms of the Q Public License as defined by Trolltech AS/); + $license="X11 (BSD like) $license" if($text =~ /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/); + $license="BSD $license" if ($text =~ /THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE/); + $license="MPL 1.1 $license" if ($text =~ /subject to the Mozilla Public License Version 1.1/); + $license="no copyright $license" if ($text !~ /copyright/i); + $license="UNKNOWN" if(!length($license)); + + $license =~ s/ $//; + + return "$license"; +} + +my $verbose = 0; +foreach my $arg (@ARGV) { + if ($arg eq "-v") { + $verbose = 1; + } else { + # For each file + if ($verbose) { + print "----- header -----\n"; + print `head -n 30 $arg| sed 's/ / /g;s/\$/ /g;s#//##g' | tr -d -c ' A-Za-z.,/\@1-9()'`."\n"; + print "--- end header ---\n"; + } + open(F, "<$arg") || die "Couldn't open $arg"; + my @c = <F>; + my $htxt = join '', @c[0.. ($#c > 29 ? 29 : $#c)]; + my $license = &checklicense($htxt); + close(F); + print "$arg: $license\n"; + } +} diff --git a/scripts/makeobj b/scripts/makeobj new file mode 100755 index 00000000..cc79c663 --- /dev/null +++ b/scripts/makeobj @@ -0,0 +1,96 @@ +#! /usr/bin/env bash + +# this is a script around make which basicly checks +# if it's in srcdir or in builddir and changes to +# the right directory for calling /usr/bin/make +# (C) Stephan Kulow + +# You may need to set OBJ_REPLACEMENT variable to get it to work. +# In the variable use the sed syntax to switch directories, for example +# export OBJ_REPLACEMENT="s:/home/zack/cvs/kde:/home/zack/build:" +# will assure that the builds are performed under /home/zack/build +# directory, when the cvs is held under /home/zack/cvs/kde. + +file=Makefile +dir=. +args=() + +while test $# -gt 0 ; do + case "${1}" in + -f) + shift + file="${1}" + shift + args=("${args[@]}" -f $file) + ;; + -C) + shift + dir="${1}" + shift ;; + *) + args=("${args[@]}" "$1") + shift + ;; + esac +done + +if test ! -f $dir/$file; then + if test -n "$OBJ_SUBDIR"; then + dir=$PWD + subdir=. + while test ! -f $dir/$OBJ_SUBDIR/$file; do + subdir=`basename $dir`"/$subdir" + dir=`dirname $dir` + if test "$dir" = "/"; then + # the case that someone puts the compile dir in / + # is very unlikely, so we better skip here ;) + echo "can't find $OBJ_SUBDIR above current dir" + exit 1 + fi + done + cd $dir/$OBJ_SUBDIR/$subdir + else + if test -n "$OBJ_REPLACEMENT"; then + pwd=`echo $PWD | sed -e "$OBJ_REPLACEMENT"` + if test ! -f $pwd/$dir/$file; then + # No objdir found. But if "make" will work in srcdir, then go ahead; might be a non-kde project. + test -f $dir/GNUmakefile && file=GNUmakefile + test -f $dir/makefile && file=makefile + test -f $dir/$file || file="" + if test -z "$file"; then + echo "no objdir found. Tried $pwd" + exit 1 + fi + fi + cd $pwd/$dir + fi + fi +else + cd $dir +fi + +echo "makeobj[0]: Entering directory \`$PWD'" +if test -z "$MAKE"; then + using_new_unsermake=0 + if head -n 1 $file | grep unsermake >/dev/null; then + using_new_unsermake=1 + fi + if head -n 1 $file | grep automake >/dev/null; then + using_new_unsermake=0 + fi + if test $using_new_unsermake -eq 1; then + MAKE=`type -p unsermake` + if test ! -x "$MAKE"; then + echo 'Makefile was created with unsermake, but there' + echo 'is no unsermake in $PATH' + exit 1 + fi + else + MAKE=/usr/bin/make + fi +fi +LANGUAGE=C $MAKE "${args[@]}" +retval=$? +echo "makeobj[0]: Leaving directory \`$PWD'" +exit $retval + diff --git a/scripts/noncvslist b/scripts/noncvslist new file mode 100755 index 00000000..69f5a591 --- /dev/null +++ b/scripts/noncvslist @@ -0,0 +1,127 @@ +#! /usr/bin/env perl + +# Offline check for extra in a checked-out +# CVS module. Sirtaj Singh Kang <taj@kde.org> May 2000. +# Usage: +# noncvsfiles <module dir>... + +@dirqueue = @ARGV; +%entries = (); +@files = (); + +sub processEntries +{ + my ( $dir ) = @_; + + open( ENTRIES, $dir."/CVS/Entries" ) + || warn "Couldn't read '$dir/CVS/Entries'"; + + while( <ENTRIES> ) { + if ( m#^\s*D/([^/]+)/# ) { + push ( @dirqueue, "$dir/$1" ); + $entries{ "$dir/$1" } = 1; + next; + } + + next unless m#^\s*/([^/]+)/([\d\.]*)/([^/]+)/#; + + $fname = $1; + $ver = $2; + $stamp = $3; + + $entries{ "$dir/$fname" } = $stamp; + } + + close( ENTRIES ); + + open( IGNORE, $dir."/.cvsignore" ) || return; + + while( <IGNORE> ) { + chomp; + s/^\s+//; + s/\s+$//; + $entries{ "$dir/$_" } = "ignored"; + } + + close( IGNORE ); +} + +# month assoc array for name -> index lookups +$mctr = 0; + +foreach $month ( @monthlist ) { + $months{ $month } = $mctr; + $mctr++; +} + +# Try current directory if none specified + +if( $#dirqueue < 0 ) { + push( @dirqueue, "." ); +} + +# process directory queue, filling entries hash +foreach $dir ( @dirqueue ) { + processEntries( $dir ); + + open( FILES, 'find "'.$dir.'" | grep -v "/CVS"|' ) + || die "Couldn't find files in $dir"; + + while( <FILES> ) { + chop; + next if $_ eq '.'; + next if m/\/\.#/; #ignore .#blah + push @files, $_; + } +} + +#foreach my $entry ( sort keys %entries ) +#{ +# print $entry,"\n"; +#} + +my $lastfile = ""; + +foreach my $file ( sort @files ) +{ + next if $file eq $lastfile; + $lastfile = $file; + + if ( !exists $entries{ $file } ) { + print $file,"\n"; + } +} + +=head1 NAME + +noncvslist -- List all files in a checked out CVS module that are not +known by the CVS server. + +=head1 SYNOPSIS + +When the current directory is a CVS module: + + noncvslist + +Checking checked out subdirectories: + + noncvslist [<dir>...] + +=head1 DESCRIPTION + +This script will list all files and directories in the module(s) that are +not listed in the CVS/Entries files. These may be files created during builds, +new un-added sources files etc. It is a useful housekeeping tool. + +=head1 EXAMPLES + +Assuming baseline/ has kdelibs/ and kdebase/ checked out within it: + + cd baseline/kdelibs; noncvslist + cd baseline; noncvslist kdelibs kdebase + +=head1 AUTHOR + +Sirtaj Singh Kang <taj@kde.org> + +=cut diff --git a/scripts/nonsvnlist b/scripts/nonsvnlist new file mode 100755 index 00000000..1a72a798 --- /dev/null +++ b/scripts/nonsvnlist @@ -0,0 +1,4 @@ +#!/bin/sh +# This script lists files not in the Subversion repository + +svn status $1 | sed '/^\?/{s/^.......//;p};d' diff --git a/scripts/package_crystalsvg b/scripts/package_crystalsvg new file mode 100755 index 00000000..1502da20 --- /dev/null +++ b/scripts/package_crystalsvg @@ -0,0 +1,185 @@ +#! /usr/bin/env bash +echo -n "Starting up..." +# +# Copyright (C) 2004 Frans Englich <frans.englich@telia.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# +# This little script assumes that in $PWD/ is a check out of various +# KDE modules, searches them for SVG files and packages them up in a tarball, +# all the files in the toplevel, together with this script and a list of the files(FILES) +# telling what KDE modules/path the svg files were copied from. +# This script is shipped with the kdesdk package. +# +# Author: Frans Englich <frans.englich@telia.com> + + +# In what directory we should search +SEARCH_DIR="$PWD" + + +# The name of the tar ball without extension. If you're not 110% sure +# the sources are up to date, remove the date tag' +PKGNAME="kde_crystalsvg-$(date '+%Y-%m-%d')" + + +# The path to where the package should be written +PKGPATH="$PWD/" + + +# What nice value to run find and tar with. find is too intensive.. +NICE=15 # Low.. + + +# Path to the LICENSE file +LICENSE="$SEARCH_DIR"/kdelibs/pics/LICENSE.crystalsvg + + +# You shouldn't need to edit anything below. + + + + + + +# Sanity checks +if [ ! -d "$SEARCH_DIR" ]; then + echo "$SEARCH_DIR is not an directory. Exiting." + exit 1; +fi + +if [ ! -r $LICENSE ]; then + echo "The file \"$LICENSE\" do not exist or is not readable. Exiting." + exit 1; +fi + +TMPDIR=$(mktemp -d "/tmp/kde_crystalsvg_packageXXXXXX") +PKGDIR="$TMPDIR/$PKGNAME" +mkdir "$PKGDIR" + +echo "done" # Startup + +# Find the SVGs +FILES="$PKGDIR/FILES" +echo -n "Searching for the SVG files..." +SVGFILES=$(find "$SEARCH_DIR" -name "cr*.svg*" -type f) +if [ $? -ne 0 ]; then + echo "There was an error when searching for the files. Exiting." + exit 1; +fi +echo "done" # Search + +echo -n "Generating README, FILES etc. files..." +# Fill the FILES file +echo "" >> "$FILES" +echo "README - contains general information about this package" >> "$FILES" +echo "FILES - this file" >> "$FILES" +echo "LICENSE - contains the license the SVG files are licensed under" >> "$FILES" +echo "" >> "$FILES" +echo "From the lines below, you can find out in what KDE package and where, the SVG are located" >> $FILES +echo "" >> "$FILES" +echo "$SVGFILES" | sed -e s,"$SEARCH_DIR",,g | sort >> "$FILES" + +cp "$LICENSE" "$PKGDIR/LICENSE" + +# Copy the SVG files +echo "$SVGFILES" | xargs cp --target-directory "$PKGDIR" + +# Fill the README file +README="$PKGDIR/README" +cat >> "$README" << EOF + +Crystal SVG sources from KDE CVS + +These are the Crystal SVG vector sources from KDE CVS. + +LOCATION +The "FILES" file gives information about the location they come from. + +Most come from: kdelibs/pics/crystalsvg You can visit this cvs directory using webcvs: +http://webcvs.kde.org/cgi-bin/cvsweb.cgi/kdelibs/pics/crystalsvg +Due to the naming the SVGs are at the end of the list. + +They are in the form of .svgz, which can be renamed to svg.gz and opened with gzip -d *.svg.gz + +Application icons may also be found with the application sources: /<kde_app_suite>/<kde_app_name>/pics e.g. /kdebase/konqueror/pics or /kdeedu/kmplot/pics + +The package_svg_files script collected the sources automatically. + +THE ART OF MAKING ICONS +If you want to make Crystal Icons, take a look at the Icon Guide. Here you will find information on icon making, submitting icons to kde, technical problems with svg icons, references, software and much more. +http://kde.ground.cz/tiki-index.php?page=Icon+Guide + +The smaller icons are hand-fixed after they are exported to pixels. Running the sources directly on your system will probably give poorer results than using the png version of the Crystal SVG set. + +The most up to date info for kde artists can be found at the wiki: +http://kde.ground.cz/tiki-index.php?page=KDE+Artists + +MISSING SOURCES +Most of the icons are made by Everaldo, initiator and visionairy of the set, while Torsten is highly productive too. Besides Everaldo and Torsten, other artists added icons to the Crystal icon set. For whatever reason, some of these sources are missing. If you ever made a Crystal SVG icon, and see the source is not in this archive, please send the vector source to: icons --at-- kde --dot-- org +If you want feedback on an icon you made: kde-artists --at-- kde --dot-- org +And of course, Everaldo too is interested in your Crystal icons: +"Everaldo" <everaldo --at--everaldo --dot-- com> + +Suse has published some Crystal Icons raw material. See the Icon Guide for more information about this. http://kde.ground.cz/tiki-index.php?page=Icon+Guide + +SOFTWARE +Many SVGs made with Illustrator will not open in Sodipodi. Karbon14 (KOffice-1.3) will open these SVG files made with AI. Sometimes it takes a while and sometimes it doesn't +get the gradients correct. However, if you then save the file from Karbon14, it will open in Sodipodi. You may also try Sketch, renamed to Skencil. + +BUGLIST +Inspired? Take a look at the buglist! +http://bugs.kde.org/buglist.cgi?short_desc_type=allwordssubstr&short_desc=&long_desc_type=allwordssubstr&long_desc=&product=artwork&component=general&version=unspecified&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bugidtype=include&bug_id=&votes=&emailassigned_to1=1&emailtype1=substring&email1=&emailassigned_to2=1&emailreporter2=1&emailcc2=1&emailtype2=substring&email2=&changedin=&chfieldfrom=&chfieldto=Now&chfieldvalue=&order=Reuse+same+sort+as+last+time&cmdtype=doit&newqueryname= + +LICENSE & QUESTIONS +License: see LICENSE.crystalsvg +Questions? Write an e-mail to kde-artists --at-- kde --dot-- org + +EOF +echo "done" # Generating + + + +# Package it +echo -n "Packaging the files..." + +nice -n$NICE tar --create --label 'Contains the SVG files used in KDE, extracted from the sources' \ + --directory "$TMPDIR" --bzip2 --file "$PKGPATH/$PKGNAME".tar.bz2 "$PKGNAME" 2> /dev/null + + + +#nice -n$NICE tar --create --label 'Contains the SVG files used in KDE, extracted from the sources' \ + #--bzip2 --file "$PKGPATH"/$(eval echo "$PKGNAME").tar.bz2 --files-from "$FILESTMP" \ + #$LICENSE $README 2> /dev/null +if [ $? -ne 0 ]; then + echo "There was an error while packaging the files. Exiting." + exit 1; +fi +echo "done" # Packaging + + + +# Clean up +rm -rf "$TMPDIR" + + + +# All done +echo "" +echo "Success - the package is called "$PKGNAME", located in $PKGPATH" +echo "" + +# EOF diff --git a/scripts/png2mng.pl b/scripts/png2mng.pl new file mode 100644 index 00000000..14ef58ae --- /dev/null +++ b/scripts/png2mng.pl @@ -0,0 +1,193 @@ +#! /usr/bin/perl + +## This script is based on cyclo.cgi, see http://homepage2.nifty.com/sophia0/ +## cyclo.cgi v0.3c (CYCLIC IMAGE) 2001.04.15 by techan + +# usage: png2mng <basename> <width> <height> + +$basename = $ARGV[0]; + +# Image Width Height +@w_h = ($ARGV[1], $ARGV[2]); + +# The number of repeats for base (integer > 1) +$b_repeat = 1; + +# Ticks per second +$tps = 20; + +## Main + +&InitCrcTable; + +$r = "NG\r\n\x1a\n"; +$sig_p = "\x89P".$r; +$sig_m = "\x8aM".$r; + +# Check File +@png = (); +$size = 1; +for ($i=0;$size > 0;) { + $file = $basename.sprintf('%04d.png', $i+1); + $size = -s $file; + if ($size > 0) + { + open(IN, "< $file") || &Error(1); + binmode(IN); + read(IN, $sig, 8); + if ($sig ne $sig_p) { close(IN); &Error(2); } + read(IN, $png[$i], $size-8); + close(IN); + $i++; + } +} +$number = $i; +$it = $number * $b_repeat; +$ti = $it; + +$|=1; +binmode(STDOUT); + +# Signature +print $sig_m; + +# MHDR +$data = 'MHDR'.pack("N7", + $w_h[0], # Width + $w_h[1], # Height + $tps, # Ticks per second + $number, # Layers + $ti, # Frames + $ti, # Time + 583); # Simplicity +&OutputData; + +# DEFI define objects of the number specified by $number +for ($i=0;$i<$number;$i++) { + $data = 'DEFI'.pack("n", + $i+1); # Object_id + # Do_not_show: 1 byte (unsigned integer) + # Concrete_flag: 1 byte (unsigned integer) + # X_location: 4 bytes (signed integer) + # Y_location: 4 bytes (signed integer) + # Left_cb: 4 bytes (signed integer) + # Right_cb: 4 bytes (signed integer) + # Top_cb: 4 bytes (signed integer) + # Bottom_cb: 4 bytes (signed integer) + &OutputData; + print $png[$i]; +} +undef(@png); + +# LOOP +$data = 'LOOP'.pack("CNC", + 0, # Nest_level + $it, # Iteration_count + 6); # Termination_condition: + # 1: Decoder discretion, not cacheable. + # 2: User discretion, not cacheable. + # *3: External signal, not cacheable. + # 4: Deterministic, cacheable. + # 5: Decoder discretion, cacheable. + # 6: User discretion, cacheable. + # *7: External signal, cacheable. + # Iteration_min: 4 bytes(unsigned integer) + # Iteration_max: 4 bytes (unsigned integer) + # Signal_number: 4 bytes (unsigned integer) + # Additional signal_number: 4 bytes (unsigned integer) +&OutputData; + +# SHOW +$data = 'SHOW'.pack("nnC", + 1, # First_image + $number, # Last_image + 6); # Show_mode: + # 0: Make the images potentially visible and display them. + # 1: Make the images invisible. + # 2: Display those that are potentially visible. + # 3: Mark images "potentially visible" but do not display + # them. + # 4: Display any that are potentially visible after toggling. + # 5: Do not display even if potentially visible after toggling. + # 6: Step through the images in the given range, making the + # next image potentially visible and display it. Jump to + # the beginning of the range when reaching the end of the + # range. Perform one step for each SHOW chunk (in reverse + # order if last_image < first_image). + # 7: Make the next image in the range (cycle) potentially + # visible but do not display it. +&OutputData; + +# ENDL +$data = "ENDL\0"; # Nest_level: 1 byte +&OutputData; + +# MEND +print "\0\0\0\0MEND! \xf7\xd5"; + +exit(0); + +sub Error +{ +my $e = $_[0]; + +$black = "\0\0\0"; +$red = "\xff\0\0"; +$white = "\xff\xff\xff"; + +if ($e == 1) { $plte = $white.$black; } +elsif ($e == 2) { $plte = $white.$red; } +else { $plte = $red.$white; } + +$plte = "PLTE".$plte; + +$p = $sig_p; +$p.="\0\0\0\rIHDR"; +$p.="\0\0\0\x1e\0\0\0\x0c\x01\x03\0\0\0"; +$p.="\x4f\xe0\x9f\x71"; +$p.="\0\0\0\x06".$plte.&CalcCrc($plte); +$p.="\0\0\0\x2eIDAT"; +$p.="\x78\x9c\x63\x60\x40\x05\xbf\xcf\xcb\x7c\x60\x68\xd2\x58\xd4\x01"; +$p.="\x21\x3e\x81\x88\xe6\xf3\x4a\x40\xb1\x2e\xa5\x05\x0c\x4d\x9e\x4a"; +$p.="\x13\x18\x7e\x69\xcc\xe9\0\xab\x05\0\xb0\x88\x10\xb8"; +$p.="\x57\x3a\0\xa1"; +$p.="\0\0\0\0IEND\xaeB`\x82"; + +$|=1; +# print "Content-type: $mime\n"; +# print "Content-length: 121\n\n"; +binmode(STDOUT); +print $p; +exit(1); +} + +sub InitCrcTable +{ +my $d; +@crc_table = (); +for (0 .. 255) { + $d = $_; + for (0 .. 7) { + if ($d & 1) { $d = 0xedb88320 ^ (($d >> 1) & 0x7fffffff); } + else { $d = ($d >> 1) & 0x7fffffff; } + } + $crc_table[$_] = $d; +} +} + +sub CalcCrc +{ +my $data = $_[0]; +my $c = 0xffffffff; +foreach (unpack("C*", $data)) { + $c = $crc_table[($c ^ $_) & 0xff] ^ (($c >> 8) & 0xffffff); +} +return(pack("N", ~$c)); +} + +sub OutputData +{ +print pack("N", length($data)-4).$data.&CalcCrc($data); +undef($data); +} +__END__ diff --git a/scripts/pruneemptydirs b/scripts/pruneemptydirs new file mode 100755 index 00000000..6f177a0f --- /dev/null +++ b/scripts/pruneemptydirs @@ -0,0 +1,46 @@ +#!/bin/sh +# Cleans up a local CVS/SVN tree, by removing directories containing +# remanants of old stuff which has been removed from CVS/SVN +# Those stale dirs often break compilation... + +# Works better with srcdir!=builddir (since it will not remove directories +# containing the old executable...) + +# NOTE: by default the script doesn't remove anything, just prints what to do +# Copy and paste, or use eval in scripts. +# Use '-f' to force it to happen (use with care, no warranties, etc.!) + +# David Faure <faure@kde.org>, script under public domain + +force=0; +if [ "$1" = "-f" ]; then force=1; fi + +# Look for toplevel dirs +files=`find . -type d | grep -v CVS\$ | grep -v admin\$ | grep -v .libs\$ | fgrep -v .svn` +toremove="rm -rf"; +for i in $files; do if test -d $i; then + # List their contents and filter out generated files + realfiles=`find $i -type f | egrep -v '.svn|CVS/|Makefile$|Makefile.in$|Makefile.rules.in$|Makefile.calls.in$|\.o$|\.lo$|\.rpo$|\.la$|\.moc|/\.#' ` + if [ -z "$realfiles" ]; then + toremove="$toremove '$i'" + fi +fi; done + +if [ "$toremove" != "rm -rf" ]; then + # Do the same in the builddir, if srcdir != builddir + if [ -n "$OBJ_REPLACEMENT" ]; then + bdir=`echo $PWD | sed -e "$OBJ_REPLACEMENT"` + if test -d $bdir; then + bdcmd="( cd $bdir ; $toremove )" + fi + fi + # Print it or do it + if [ $force -eq 1 ]; then + eval $toremove + eval $bdcmd + else + echo $toremove + echo $bdcmd + fi +fi + diff --git a/scripts/qtdoc b/scripts/qtdoc new file mode 100755 index 00000000..f92345d9 --- /dev/null +++ b/scripts/qtdoc @@ -0,0 +1,19 @@ +#!/bin/sh +# Run from command line, to open a qt help page in kfm/konqueror +# No argument => main page +# Classname (case insensitive) => page for this class + +if [ $# = 1 ]; then + fname=`echo $1 | tr '[A-Z]' '[a-z]'` + if [ -f $QTDIR/doc/html/$fname.html ]; then + kdeinit_wrapper kfmclient openProfile webbrowsing file:$QTDIR/doc/html/$fname.html + else + if [ -f /usr/doc/qt2/html/$fname.html ]; then + kdeinit_wrapper kfmclient openProfile webbrowsing file:/usr/doc/qt2/html/$fname.html + else + echo "No such file $fname.html" + fi + fi +else + kfmclient openURL file:$QTDIR/doc/html/index.html +fi diff --git a/scripts/rc2kcfgxt.pl b/scripts/rc2kcfgxt.pl new file mode 100644 index 00000000..4b015dee --- /dev/null +++ b/scripts/rc2kcfgxt.pl @@ -0,0 +1,95 @@ +#! /usr/bin/env perl +# +# rc2kcfgxt.pl version 4 by Adriaan de Groot +# +# This code is released to the Public Domain. +# + +# +# Usage: rc2kcfgtxt.pl < rcfile > xmlfile +# +# Reads an rcfile (say, kmailrc) and writes out an KConfigXT XML +# file that represents a reasonable guess for representing the +# rc file. No guarantees about well-formedness of the XML are made. +# + +# +# rc2kcfgxt.pl only guesses types Bool, UInt, and IntList. +# Everything else is a String. You may need to edit the various +# types. As of 4-1-2003, valid types are: +# +# type (String|StringList|Font|Rect|Size|Color| +# Point|Int|UInt|Bool|Double|DateTime| +# Int64|UInt64|IntList|Enum|Path) #REQUIRED +# + +$group="" ; +$key=""; + +print <<EOF; +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd"> +<kcfg> +EOF + +while(<>) +{ + chomp; + next unless $_; + if (/\[([-A-Za-z 0-9]+)\]/) + { + $grp = $1; + print " </group>\n" if ($group && (not $group =~ /^MainWindow/)); + $group=$grp; + next if ($group =~ /^MainWindow/); + print " <group name=\"$group\">\n"; + next; + } + + next if $group =~ /^MainWindow/ ; + + @l = split /=/; + $key = shift @l; + $value = join "=",@l; + $cfgkeyexpr = ""; + + # Escape value values that are special to XML + $value =~ s/</</; + $value =~ s/>/>/; + $value =~ s/"/"/; + + if ($key =~ /[ -,.<>;:!\]\[|}{]/) + { + $cfgkeyexpr = "key=\"$key\""; + @key_parts = split /[ -,.<>;:!\]\[|}{]/,$key; + $key = ""; + foreach $i (@key_parts) + { + next unless $i; + $i =~ /([a-zA-Z0-9_])([a-zA-Z0-9_]*)/; + $first = $1; + $second = $2; + $first =~ tr/a-z/A-Z/; + $key .= $first . $second; + } + } + + # Find key type + $type=""; + $type="Bool" if ( $value =~ /^(true|false|TRUE|FALSE)$/); + $type="UInt" if ( $value =~ /^[0-9]+$/); + $type="IntList" if ( ( not $type ) && ( $value =~ /^[0-9,]+$/ )); + $type="String" unless $type; + + print <<EOF; + <entry name="$key" $cfgkeyexpr type="$type"> + <label> + </label> + <default>$value</default> + </entry> +EOF +} + +print " </group>\n" if ($group && (not $group =~ /^MainWindow/)); + +print "\n</kcfg>\n"; diff --git a/scripts/svn-clean b/scripts/svn-clean new file mode 100755 index 00000000..3c698bd5 --- /dev/null +++ b/scripts/svn-clean @@ -0,0 +1,113 @@ +#! /usr/bin/env perl + +# +# This script recursively (beginning with the current directory) +# wipes out everything not registered in SVN. +# +# rewritten in perl by Oswald Buddenhagen <ossi@kde.org> +# based on bash version by Thiago Macieira <thiago@kde.org> +# inspired by cvs-clean, written by Oswald Buddenhagen <ossi@kde.org> +# inspired by the "old" cvs-clean target from Makefile.common +# +# This file is free software in terms of the BSD licence. That means +# that you can do anything with it except removing this license or +# the above copyright notice. There is NO WARRANTY of any kind. +# + +# Warning: +# This script processes the output from the SVN executable +# Do not run it along with colorsvn + +use File::Path; + +my $version = "svn-clean v1.0"; +my $heading = $version.": cleans up the Subversion working directory\n"; +my $usage = $heading. + "svn-clean [-h] [-n] [-q] [-i|-f] [dirname]\n\n". + "Where:\n". + " -h shows this help screen\n". + " -n dry-run: doesn't actually erase the files, just show their names\n". + " -i interactive: ask for confirmation before erasing the files\n". + " -f force: doesn't ask for confirmation before erasing\n". + " -q quiet: doesn't show output\n"; + + +my $dry_run = 0; +my $force = 0; +my $quiet = 0; + +sub check_confirm() +{ + return if ($force); + + open(TTY, "+< /dev/tty") or die "cannot open /dev/tty"; + + print TTY "This will erase files and directories that aren't in Subversion\n". + "Are you sure you want to continue? (y/n) "; + + if (<TTY> =~ /^[Yy]/) { + $force = 1; + close TTY; + return; + } + + # user cancelled + exit 0; +} + +# Parse arguments +my $rest = 0; +my @files = (); +foreach my $arg (@ARGV) { + if ($rest) { + push @files, $arg; + } else { + if ($arg eq '-h' || $arg eq '--help') { + print $usage; + exit (0); + } elsif ($arg eq '-n' || $arg eq '--dry-run') { + $dry_run = 1; + $force = 1; + } elsif ($arg eq '-f' || $arg eq '--force') { + $force = 1; + } elsif ($arg eq '-i' || $arg eq '--interactive') { + $force = 0; + } elsif ($arg eq '-q' || $arg eq '--quiet') { + $quiet = 1; + } elsif ($arg eq '--') { + $rest = 1; + } elsif ($arg =~ /^-/) { + print STDERR "svn-clean: unknown argument '".$arg."'\n\n".$usage; + exit (1); + } else { + push @files, $arg; + } + } +} +if (!@files) { + push @files, '.'; +} + +# Unset TERM just so that no colours are output +# in case $SVN points to colorsvn +delete $ENV{'TERM'}; + +#print($heading."\n") unless $quiet; + +foreach my $dir (@files) { + open SVN, "svn status --no-ignore \"".$dir."\"|"; + while (<SVN>) { + /^[I?] +(.*)$/ or next; + my $file = $1; + check_confirm(); + lstat $file; + if (-d _) { + print("D ".$file."\n") unless $quiet; + rmtree($file, 0, 0) unless $dry_run; + } else { + print("F ".$file."\n") unless $quiet; + unlink($file) unless $dry_run; + } + } + close SVN; +} diff --git a/scripts/svn2dist b/scripts/svn2dist new file mode 100755 index 00000000..eb7ef8d9 --- /dev/null +++ b/scripts/svn2dist @@ -0,0 +1,638 @@ +#! /usr/bin/env bash + +# This is svn2dist +# Based on cvs2dist by <jason@katzbrown.com>. + +# Original author (of cvs2pack.sh) was Sebastian Stein <seb.stein@hpfsc.de> +# Heavy, heavy modifications by Jason Katz-Brown <jason@katzbrown.com> +# Some modifications for i18n inclusion by Dominique Devriese <devriese@kde.org> +# Added --no-i18n-lang and --replace-files by Michael Buesch <mbuesch@freenet.de> +# License: GPL (http://www.gnu.org/) +# Last modification: 2005/01/08 + +echo >&2 "Warning: this script needs more testing!" +echo >&2 "" + +cmdline="$@" + +returndir=`pwd` +override="README ChangeLog INSTALL AUTHORS AUTHOR COPYING COPYING.LIB TODO COPYING-DOCS" +remove="config.cache config.log config.status Makefile configure inst-apps CVS acinclude.m4 aclocal.m4 libtool subdirs *.moc *.la .libs .deps .svn .cvsignore autom4te.cache {arch} .arch-ids *.lo *.o *.bbg *.da *.bb" +toplevelremove="configure.in.bot config.h config.h.bot config.h.in config.status config.log stamp-h stamp-h.in stamp-h1 subdirs configure.files " +# whitespace seperated list of languages to never include. +always_skip_languages="xx" + + +exit_cleanup() +{ + echo -n "Cleaning up... " + if [ -d $temp_dir ]; then + test -z "$debug" && rm -Rf $temp_dir + fi + echo "done." +} + +trap "exit_cleanup; exit 1" SIGINT SIGTERM + +test -e ~/.svn2distrc && extraoptions=`cat ~/.svn2distrc` + +# getopt usage from the getopt bash example +# --log has optional argument +TEMP=`getopt \ +-o v:n:r:e:a:B:dhmbgol \ +--long log::,version:,name:,required-header:,required-header-error-message:,make-unpackaged,help,no-bz2,no-bzip2,no-gzip,only-directory,remove-hidden,admin-dir:,branch:,no-i18n,no-i18n-lang:,svn-root:,i18n-module:,debug,replace-files: \ +-n svn2dist -- $extraoptions "$@"` + +if [ $? != 0 ]; then + echo "Aborted." >&2 + exit 1 +fi + +eval set -- "$TEMP" + +log="/dev/null" +calclog=0 +doi18n="yes" +noi18nlang="" +replace_files="" +i18nmodule="" +svnroot="" +debug= +branch="trunk" +version= + +while true; do + case "$1" in + -v|--version) version=$2; shift 2 ;; + -n|--name) name=$2; shift 2 ;; + -a|--admin-dir) admindir=$2; + if [ `echo $admindir | sed -e 's#^/##'` = $admindir ]; then + admindir="`pwd`/$admindir" + fi + shift 2 ;; + --debug) debug="non-empty"; shift 1 ;; + --svn-root) svnroot="$2"; shift 2 ;; + --i18n-module) i18nmodule="$2"; shift 2 ;; + -r|--required-header) requiredheader=$2; shift 2 ;; + --no-i18n) doi18n="no"; shift 1 ;; + --no-i18n-lang) noi18nlang="$2"; shift 2 ;; + -e|--required-header-error-message) requiredmsg=$2; shift 2 ;; + -m|--make-unpackaged) leavedir="non-empty"; shift 1 ;; + -h|--help) showhelp="non-empty"; shift 1 ;; + -b|--no-bz2|--no-bzip2) nobzip2="non-empty"; shift 1 ;; + -o|--only-directory) + nogzip="non-empty" + nobzip2="non-empty" + leavedir="non-empty" + shift 1 ;; + -g|--no-gzip) nogzip="non-empty"; shift 1 ;; + -d|--remove-hidden) removehidden="non-empty"; shift 1 ;; + -l) calclog=1; shift 1 ;; + --log) + case "$2" in + # no-argument case + "") calclog=1; shift 2 ;; + # something, should be a file + *) log=$2 + origlog=$log + if [ `echo $log | sed -e 's#^/##'` = $log ]; then + log="`pwd`/$log" + fi + + shift 2 ;; + esac ;; + --replace-files) replace_files="$2"; shift 2 ;; + --) shift + break ;; + *) echo "Aborted." + exit 1 ;; + esac +done + +count=0 +for arg do + test $count = 0 && module=$arg + test $count = 1 && directory=$arg + + if [ $count -ge 2 ]; then + modarg=$arg + if [ `echo $modarg | sed -e 's#^/##'` = $modarg ]; then + modarg="`pwd`/$modarg" + fi + addfiles="$addfiles $modarg" + fi + + let count count++ +done + +# test if a module and directory name was given +if [ ! -z $showhelp ] || [ -z $module ] || [ -z $directory ]; then + echo "Usage: svn2dist module directory [options] [addfile1] [addfile2] ..." + echo "" + echo " -n --name <name>" + echo " -v --version <version>" + echo " --svn-root <root> the value to use as svn root" + echo " variable. It is not necessary if you use --no-i18n." + echo " --admin-dir <dir> admin/ location (default is module/admin)" + echo " (symbolic links are OK.)" + echo " -B --branch <branch> use branch for i18n checkouts." + echo " --no-i18n don't try to automatically checkout the translations from svn." + echo " --no-i18n-lang <languages> exclude all languages in the given comma" + echo " seperated list. example:" + echo " --no-i18n-lang uk,de,en_GB" + echo " --i18n-module <name> i18n subdir" + echo " if not specified it is guessed" + echo " from module name by replacing \"/\" by \"-\"" + echo " --log=<logfile> If logfile unspecified, default file is used." + echo " (The '=' is essential and may not be ommited" + echo " when specifying the logfile.)" + echo " -l Log to default logfile." + echo " -m --make-unpackaged Also makes an unpacked distribution" + echo " in the current directory." + echo " -g --no-gzip Do not create gzip package." + echo " -b --no-bz2 Do not create bzip2 package." + echo " --no-bzip2 Alias for the above." + echo " -o --only-directory Alias for -mbg (no packages, only a directory.)" + echo " -r --required-header <header> Errors if header is not installed." + echo " -e --required-header-error-message <message>" + echo " Error message for above." + echo " -d --remove-hidden Remove hidden files/directories from packages" + echo " --replace-files <file-pair-list>" + echo " <file-pair-list> is a comma separated list of file pairs" + echo " which should be replaced in the final distribution package." + echo " Each element of a pair is separated by an @" + echo -n " Example: --replace-files take_this_file@and_move_it_here," + echo "configure.in.bot.dist@configure.in.bot" + echo " The filenames are all relative to your package root." + echo " Please be careful! Try to avoid the usage of .. in the path. It" + echo " may break stuff! There can not be blank characters in the paths." + echo " -h --help Show this help" + echo "" + echo " Name defaults to the last part of the directory." + echo "By default, creates name[-version].tar.gz if gzip is installed" + echo "and/or name[-version].tar.bz2 if bzip2 is installed in the current" + echo "directory. Removes all temporary files it creates. Produces" + echo "tarballs that are standard distribution tarballs with a" + echo "configure script." + echo " Unless --no-i18n is given, it automatically tries to check out " + echo "strings and documentation translation from svn." + echo " Arguments after the second are added to the toplevel directory" + echo "in the package. Short options can be combined, eg -dm to create" + echo "a directory and remove hidden files. ~/.svn2distrc is added to" + echo "the beginning of command line arguments if it exists." + echo " '--' signifies the end of options." + echo "" + echo "Example: svn2dist /sources/kdegames kolf/objects/picture \\" + echo " -n kolf-picture -v 0.9 -r \"kolf/game.h\" \\" + echo " --log ~/tmp/extra-file" + echo "" + echo " Creates packages of the kolf picture plugin, naming the" + echo " packages kolf-picture-0.9 and logging the process. For configure" + echo " to succeed, kolf/game.h must be installed or an error will occur." + echo " ~/tmp/extra-file is added to the packages." + echo "" + echo "Webpage: http://www.katzbrown.com/shiritsu/programming/svn2dist/" + echo "Authors: Jason Katz-Brown <jason@katzbrown.com>," + echo " Sebastian Stein <seb.stein@hpfsc.de>," + echo " Dominique Devriese <devriese@kde.org>" + exit 1 +fi + +if [ -z $i18nmodule ]; then + i18nmodule=`echo $module | sed -e 's#/#-##'` +fi + +# expand module +module=`echo $module | sed -e 's#/$##'` +if [ `echo $module | sed -e 's#^/##'` = $module ]; then + module="`pwd`/$module" +fi + +# test if the given module is a directory +test -d $module +if [ $? -ne 0 ]; then + echo "$module is not a directory." + echo "Aborted." + exit 1 +fi + +# go to our module +cd $module + +directory=`echo $directory | sed -e 's#^/##'` +pofiles="" + +for makefile in `find $directory -name Makefile.am`; do + cat $makefile | while read line; do echo $line; done | perl -e '$mes=0; while (<STDIN>) { if (/^messages:/) { $mes=1; next; } if ($_ !~ m/^[^\t ]/) { $mes=0; } if ($mes && /\$\(XGETTEXT\)/ && / -o/) { s,.*-o \$\(podir\)/([a-z._-]+).*$,$1, ; chomp $_; $_ =~ s/\.pot/.po/; print "pofiles=\"$_ \$pofiles\"\n" } }' > _tmppot + . _tmppot + rm -f _tmppot +done + +if [ -z $name ]; then + name=$directory + # get rid of trailing slash + name=`echo $name | sed -e 's#/$##'` + # leading slash + name=`echo $name | sed -e 's#^/##'` + + if [ `echo $name | sed -e 's#/##'` != $name ]; then + name=`echo $name | sed -e 's#^.*/##'` + fi +fi + +test $calclog = 1 && log="$returndir/svn2dist-$name.log" && origlog="svn2dist-$name.log" + +# test if the given name is a sub-directory +if [ ! -d "$directory" ]; then + echo "$directory is not a sub-directory of $module." + echo "Aborted." + exit 1 +fi + +test $log != "/dev/null" && echo "Logging to $log." + +echo "svn2dist log on "`date` > $log +echo -n "Module: $module; Directory: $directory; Name: $name; " >> $log +if [ -z $version ]; then + echo "Version unspecified." >> $log +else + echo "Version $version." >> $log +fi +echo $cmdline >> $log +echo "--------" >> $log + +if [ -z $version ]; then + filename=$name +else + filename="$name-$version" + VERSION=$version + export VERSION +fi + +if [ $doi18n = "yes" ]; then + # a little warning... + echo "Will try to fetch i18n files from KDE's SVN." + echo "If this doesn't work, use --no-i18n." + + if [ -z "$svnroot" ]; then + echo "No svn root specified, and --no-i18n option is not given.." >> $log + echo "Using anonymous svn.." >> $log + svnroot="svn://anonsvn.kde.org/home/kde/trunk" + fi +fi + +# the temporary directory +temp_dir="$module/svn2dist-tmp" +temp_dist="$temp_dir/$filename" + +echo "Temporary directory is $temp_dir." >> $log + +# make a temporary directory +test -d $temp_dir && rm -Rf $temp_dir + +mkdir $temp_dir +mkdir $temp_dist || (echo "failed to create $temp_dist"; exit 1; ) + +# check if we were able to create temp_dir +test -d $temp_dist +if [ $? -ne 0 ]; then + echo "Could not create temporary directory $temp_dist." + echo "$temp_dist could not be created." >> $log + echo "Aborted." + exit 1 +fi + +test -z "$requiredmsg" && requiredmsg="Install development package needed first! $requiredheader, for one, is missing." + +### configure.in.in +if [ ! -z $requiredheader ]; then + naiyou="KDE_CHECK_HEADER( +$requiredheader, +[], +[AC_MSG_ERROR(\"$requiredmsg\")] +)" + echo $naiyou > $temp_dir/configure.in.in + echo "configure.in.in contents: " >> $log + echo "--------" >> $log + echo $naiyou >> $log + appaddfiles="$appaddfiles $temp_dir/configure.in.in" +fi + +# copy all files of the module to temp_dir/name +cp -RL $module/$directory $temp_dist/$name + +echo "cp -R $module/$directory $temp_dist/$name" >> $log + +modulename="$module" +# get rid of trailing slash +modulename=`echo $modulename | sed -e 's#/$##'` +# get the last part +modulename=`echo $modulename | sed -e 's#^.*/##'` + +remove="$remove $modulename.lsm" + +# we check out kde-i18n/subdirs in temp_dir/kde-i18n.. +if [ $doi18n = "yes" ]; then + pushd $temp_dir + echo "Getting i18n subdirs" >> $log + i18nlangs_tmp=`svn cat "$svnroot/l10n-kde3/subdirs"` + skiplist="`echo $noi18nlang | sed -e 's/,/ /g'`" + skiplist="$skiplist $always_skip_languages" + for lang in $i18nlangs_tmp; do + must_skip="no" + for skip in $skiplist; do + if [ "$lang" = "$skip" ]; then + must_skip="yes" + fi + done + if [ "$must_skip" = "no" ]; then + i18nlangs="$i18nlangs $lang" + fi + done + echo "available languages: $i18nlangs (Pofiles to fetch: $pofiles)" >> $log + popd +fi + +# if a handbook exists, we also copy it to the directory +if [ -d $module/doc/$name ]; then + mkdir -p $temp_dist/doc/$name + cp -Rf $module/doc/$name $temp_dist/doc + find $module/doc/ -maxdepth 1 ! -xtype d | xargs --replace={} cp {} $temp_dist/doc + + if [ $doi18n = "yes" ]; then + pushd $temp_dir + for lang in $i18nlangs; do + echo -n "Checking for $lang/$name... " + test -d $temp_dist/doc/$lang && rm -Rf $temp_dist/doc/$lang + docdirname="l10n-kde3/$lang/docs/$i18nmodule/$name" + echo "svn export $svnroot/$docdirname $temp_dist/doc/$lang" >> $log + mkdir -p $temp_dist/doc + svn export "$svnroot/$docdirname" $temp_dist/doc/$lang >> $log 2>&1 + if [ ! -d "$temp_dist/doc/$lang" ]; then + echo "$lang's $name documentation does not exist." >> $log + echo "does not exist" + continue + fi + echo "KDE_LANG = $lang +KDE_DOCS = $name" > $temp_dist/doc/$lang/Makefile.am + + echo "done." + echo "$lang documentation included." >> $log + done + popd + fi +fi + +# clean up doc directory +if [ -d $temp_dist/doc/$name ]; then + pushd $temp_dist/doc/$name + echo -n "make clean in $temp_dist/doc/$name/... " + echo >> $log + echo "make clean in $temp_dist/doc/$name/" >> $log + make clean >> $log + echo "--------" >> $log + echo "done." + popd +fi + +if [ $doi18n = "yes" ]; then + test -d $temp_dist/po && rm -Rf $temp_dist/po + mkdir $temp_dist/po + pushd $temp_dir + + for pofile in $pofiles; do + echo "Getting translations for $pofile from i18n..." + + for lang in $i18nlangs; do + pofilename="l10n-kde3/$lang/messages/$i18nmodule/$pofile"; + echo "Getting $pofilename" >> $log + svn cat "$svnroot/$pofilename" >$pofile 2>&1 || rm -f $pofile + if [ ! -f "$pofile" ]; then + echo "$lang's $pofile does not exist." >> $log + continue + fi + + dest=$temp_dist/po/$lang + mkdir -p $dest + echo -n "Copying $lang's $pofile over... " + echo "$lang's $pofile file included." >> $log + mv $pofile $dest + echo "done." + + echo "KDE_LANG = $lang +SUBDIRS = \$(AUTODIRS) +POFILES = AUTO" > $dest/Makefile.am + + subdirs="non_empty" + done + done + + popd + if [ -z "$subdirs" ]; then + rm -Rf $temp_dist/po + else + echo "SUBDIRS = \$(AUTODIRS)" > $temp_dist/po/Makefile.am + fi +fi + +# copy the admin directory +if [ -z $admindir ]; then + cp -pRL $module/admin $temp_dist + echo "cp -pRL $module/admin $temp_dist" >> $log +else + cp -pRL $admindir $temp_dist + echo "cp -pRL $admindir $temp_dist" >> $log +fi + +# and all files from the base dir, except directories +echo "Copying over files from the module directory:" >> $log +find $module -maxdepth 1 ! -xtype d | xargs --verbose --replace={} cp {} $temp_dist 2>> $log +echo "--------" >> $log + +# we now enter the temp_dist and delete all unwanted files +# and add wanted files +cd $temp_dist + +# override top-level files +echo "Override files: " >> $log +for file in $override; do + test -e $temp_dist/$name/$file && mv $temp_dist/$name/$file . && echo "mv $temp_dist/$name/$file ." >> $log +done + +test ! -z "$addfiles" && echo "Addfiles: " >> $log +for file in $addfiles; do + test -e $file && cp -R $file $temp_dist && echo "cp -R $file $temp_dist" >> $log +done + +test ! -z "$appaddfiles" && echo "Application addfiles: " >> $log +for file in $appaddfiles; do + test -e $file && cp -R $file $temp_dist/$name/ && echo "cp -R $file $temp_dist/$name/" >> $log +done + +echo "--------" >> $log + +# replace all user requested files +if [ -n "$replace_files" ]; then + echo "Replace user requested files" >> $log + pair_list="`echo $replace_files | sed -e 's/,/ /g'`" + for pair in $pair_list; do + pair_tmp="`echo $pair | sed -e 's/@/ /g'`" + from="`echo $pair_tmp | awk '//{print $1}'`" + to="`echo $pair_tmp | awk '//{print $2}'`" + if [ -z "$from" ] || [ -z "$to" ]; then + echo "bogus pair \"$from@$to\"" >> $log + continue + fi + echo "Replacing \"$to\" by \"$from\"" >> $log + from_path="$temp_dist/$name/$from" + to_path="$temp_dist/$name/$to" + if [ ! -f "$from_path" ]; then + echo "$from_path does not exist!" >> $log + echo "" + echo "Warning: \"$from\" does not exist!" + echo -n "Please enter the path in --replace-files relative " + echo "to the package root of your project." + echo "Your package root is: \"$module/$directory\"" + echo "" + continue + fi + rm -f "$to_path" && \ + mv "$from_path" "$to_path" + if [ $? -ne 0 ]; then + echo -n "Moving \"$from_path\" failed! " >> $log + echo -n "This should not happen." >> $log + if [ -f "$to_path" ]; then + echo "" + else + echo " No \"$to\" will exist in the archive!" >> $log + fi + fi + done + echo "--------" >> $log +fi + +# version file, if it doesn't exist +test ! -z $version && test ! -e VERSION && echo "$name version $version" > VERSION + +cd $temp_dist/$name +echo "make clean in $temp_dist/$name/:" >> $log +echo "" >> $log +echo -n "make clean in $temp_dist/$name/... " +make clean >> $log +echo "--------" >> $log +echo "done." + +cd $temp_dist + +# remove files +echo "Remove files: " >> $log +for file in $remove; do + find . -name $file | xargs rm -Rf + echo "find . -name $file | xargs rm -Rf" >> $log +done + +# remove more files +echo "Remove toplevel files: " >> $log +for file in $toplevelremove; do + test -e $file && rm -Rf $file && echo "rm -Rf $file" >> $log +done +unset file + +# remove hidden files +test ! -z $removehidden && echo "Remove hidden files: " >> $log && find $temp_dist -name ".*" -and ! -name "." | xargs --verbose rm -Rf 2>> $log + +echo "--------" >> $log + +cd $temp_dist + +# create the configure script +# working directory is $temp_dist +export UNSERMAKE=no +echo "make -f Makefile.cvs in $temp_dist/:" >> $log +echo "" >> $log +echo -n "make -f Makefile.cvs in $temp_dist/... " +make -f Makefile.cvs >> $log 2>> $log +echo "rm Makefile.cvs" >> $log +rm -f Makefile.cvs +echo "rm autom4te.cache" >> $log +rm -Rf autom4te.cache +echo "--------" >> $log +echo "done." + +echo "Directory will be $filename." + +# play around with our tar file in temp_dir +cd $temp_dir + +if [ ! -z $leavedir ]; then + test -e $returndir/$filename && rm -Rf $returndir/$filename + cp -R $filename $returndir +fi + +# make a tar of temp_dist +if [ -z $nogzip ] || [ -z $nobzip2 ]; then + echo -n "Tarring... " + echo "tar cf $filename.tar $filename" >> $log + tar cf $filename.tar $filename >> $log + echo "done." +fi + +if [ -z $nogzip ] && [ ! -z `which gzip 2> /dev/null` ]; then + cp $filename.tar $filename.tar.tmp + echo -n "running gzip... " + echo "gzip $filename.tar" >> $log + gzip $filename.tar + echo "done." + mv $filename.tar.tmp $filename.tar + mv $filename.tar.gz $returndir + echo "mv $filename.tar.gz $returndir" >> $log +fi +if [ -z $nobzip2 ] && [ ! -z `which bzip2 2> /dev/null` ]; then + echo -n "running bzip2... " + echo "bzip2 $filename.tar" >> $log + bzip2 $filename.tar + echo "done." + mv $filename.tar.bz2 $returndir + echo "mv $filename.tar.bz2 $returndir" >> $log +fi + +test -e $filename.tar && rm -f $filename.tar + +# cleanup all tempoaries +exit_cleanup + +cd $returndir + +test -z $leavedir && test ! -z $nobzip2 && test ! -z $nogzip && echo "Finished - no created files." && exit 1 + +# cool, everything went ok! +if [ -z $leavedir ]; then + echo "Finished. Created packages:" +else + if [ -z $nogzip ] || [ -z $nobzip2 ]; then + echo "Finished. Created packages/directories:" + else + echo "Finished. Created directory:" + fi +fi + +echo "--------" >> $log +echo "Done: " >> $log +echo "Files are in `pwd`." >> $log + +if [ ! -z $leavedir ] && [ -d $filename ]; then + ls -ld $filename + ls -ld $filename >> $log +fi +if [ -z $nogzip ] && [ -e $filename.tar.gz ]; then + ls -l $filename.tar.gz + ls -l $filename.tar.gz >> $log +fi +if [ -z $nobzip2 ] && [ -e $filename.tar.bz2 ]; then + ls -l $filename.tar.bz2 + ls -l $filename.tar.bz2 >> $log +fi +if [ $log != "/dev/null" ]; then + echo "Created log:" + ls -l $origlog +fi diff --git a/scripts/svnaddcurrentdir b/scripts/svnaddcurrentdir new file mode 100755 index 00000000..2474bb01 --- /dev/null +++ b/scripts/svnaddcurrentdir @@ -0,0 +1,30 @@ +#!/bin/sh +#Alexander Neundorf <neundorf@kde.org> +#copyright 2002, GPL + +#call this script to add all files in and below the current dir to SVN +#it adds *.c, *.h, *.C, *.cpp, *.cc automatically +#*~, *.o, *.so, *.lo, *.la, .libs/, .deps/, .#* are ignored +#it asks for the remaining files + + +#ignore dirs "CVS", ".deps", ".libs" ".svn" +#ignore files *.o, *.so, *.lo, *.la, *~, .#* +FOUND=`find |grep -v "^\.$"| grep -v CVS| grep -v "\.[ls]\?o$"|grep -v "~$"|grep -v "\.libs/"|grep -v "\.deps/" |grep -v "\.svn/" |grep -v "\.depend/"| grep -v "/\.#" |grep -v "\.la$"` +#echo $FOUND + +ask_for_adding() { +echo +read -p "Add file $file to SVN ? (y/n) " answer rest +#if [ "$answer" != "y" ]; then echo $file; fi +if [ "$answer" == "y" ]; then svn add $file; fi +} + + +for file in $FOUND +do +#matches all *.h, *.c, *.cpp, *.C, *.cpp, *.cc (and some others too) + echo $file | grep "\.[cCh][cp]\?p\?$" && svn add $file + echo $file | grep -v "\.[cCh][cp]\?p\?$" && ask_for_adding +done + diff --git a/scripts/svnbackport b/scripts/svnbackport new file mode 100755 index 00000000..cdecdcb4 --- /dev/null +++ b/scripts/svnbackport @@ -0,0 +1,64 @@ +#!/bin/sh +# Backport the last change in HEAD, to a branch. +# Usage: svnbackport <files> +# WARNING: the branch tag is hardcoded into the script, make sure to check it! +# +# This is a port of the "cvsbackport" script: +# Initial author: Dirk Mueller +# Support for multiple command-line arguments: David Faure +# Ported to SVN: Till Gerken +# Help message: Thomas Zander +# +# It is a straight port and not very sophisticated. It might break. I hope +# that someone else with more knowledge about Subversion will pick it up. +# It needs to be used from within the repository so that it can guess +# the remote URL correctly. +# + +#REPOSITORY=https://svn.kde.org/home/kde + +if test -z "$1" -o "$1" = "-h" -o "$1" = "--help"; then + echo "Usage: svnbackport recentlyCommittedFile"; + exit; +fi + +BRANCH=3.5 + +SRC_REMOTE=`svn info | grep URL: | cut -c6-` +TARGET_REMOTE=`echo $SRC_REMOTE | sed "s|trunk/KDE|branches/KDE/$BRANCH|"` + + +echo "Backporting to $BRANCH" +TMPFILE=`mktemp svnbackport.XXXXXX` || exit 1 +files=$* +until test $# -eq 0; do + + echo "looking for last change to $1..." + svnlastchange $1 > $TMPFILE + echo "browsing last change to $1..." + less $TMPFILE + + FILE_PATH=$1 + FROM_URL=$SRC_REMOTE/$1 + TO_URL=$TARGET_REMOTE/$1 + + echo "switching to branch..." + svn switch $TO_URL $FILE_PATH + patch $FILE_PATH $TMPFILE + rm -f $TMPFILE + echo "showing diff for $1..." + svn diff $FILE_PATH | less + + shift +done + +kdialog --yesno "Do you want to commit all changes?" +if [ $? = 0 ]; then + svn ci $files +fi + +echo "switching back to trunk..." +for file in $files +do + svn switch $SRC_REMOTE/$file $file +done diff --git a/scripts/svnchangesince b/scripts/svnchangesince new file mode 100755 index 00000000..eec267e5 --- /dev/null +++ b/scripts/svnchangesince @@ -0,0 +1,63 @@ +#!/bin/sh +# +# Written by Thiago Macieira <thiago@kde.org> +# This file is in the public domain. +# +# Shows the changes to the subversion repository since the local copy +# was last updated. +# + +showdiff=false +showlog=true + +while test $# -ge 1; do + case "$1" in + -d) + showdiff=true + shift + ;; + + -D) + showdiff=false + shift + ;; + + -l) + showlog=true + shift + ;; + + -L) + showlog=false + shift + ;; + + -h) + cat <<EOF +svnchangesince - Shows the changes to the SVN repository since the last update +Usage: + svnchangesince [-d|-D] [-l|-L] [-h] [filenames] + +where: + -d include diffs in output + -D don't include diffs in output [default] + -l include logs in output [default] + -L don't include logs in output + -h show this help string +EOF + exit 0 + ;; + + *) + break + ;; + esac +done + +if $showlog; then + svn log -v -r HEAD:BASE "$@" +fi + +if $showdiff; then + svn diff -r BASE:HEAD "$@" +fi diff --git a/scripts/svnforwardport b/scripts/svnforwardport new file mode 100755 index 00000000..0e1ba917 --- /dev/null +++ b/scripts/svnforwardport @@ -0,0 +1,64 @@ +#!/bin/sh +# Backport the last change in HEAD, to a branch. +# Usage: svnforwardport <files> +# WARNING: the branch tag is hardcoded into the script, make sure to check it! +# +# This is a port of the "cvsbackport" script: +# Initial author: Dirk Mueller +# Support for multiple command-line arguments: David Faure +# Ported to SVN: Till Gerken +# Help message: Thomas Zander +# +# It is a straight port and not very sophisticated. It might break. I hope +# that someone else with more knowledge about Subversion will pick it up. +# It needs to be used from within the repository so that it can guess +# the remote URL correctly. +# + +#REPOSITORY=https://svn.kde.org/home/kde + +if test -z "$1" -o "$1" = "-h" -o "$1" = "--help"; then + echo "Usage: svnforwardport recentlyCommittedFile"; + exit; +fi + +BRANCH=3.5 + +SRC_REMOTE=`svn info | grep URL: | cut -c6-` +TARGET_REMOTE=`echo $SRC_REMOTE | sed "s|branches/KDE/$BRANCH|trunk/KDE|"` + + +echo "Forward porting from $BRANCH to trunk" +TMPFILE=`mktemp svnforport.XXXXXX` || exit 1 +files=$* +until test $# -eq 0; do + + echo "Looking for last change to $1..." + svnlastchange $1 > $TMPFILE + echo "Browsing last change to $1..." + less $TMPFILE + + FILE_PATH=$1 + FROM_URL=$SRC_REMOTE/$1 + TO_URL=$TARGET_REMOTE/$1 + + echo "Switching to trunk..." + svn switch $TO_URL $FILE_PATH + patch $FILE_PATH $TMPFILE + rm -f $TMPFILE + echo "Showing diff for $1..." + svn diff $FILE_PATH | less + + shift +done + +kdialog --yesno "Do you want to commit all changes?" +if [ $? = 0 ]; then + svn ci $files +fi + +echo "Switching back to branch..." +for file in $files +do + svn switch $SRC_REMOTE/$file $file +done diff --git a/scripts/svngettags b/scripts/svngettags new file mode 100755 index 00000000..cd658f7c --- /dev/null +++ b/scripts/svngettags @@ -0,0 +1,3 @@ +#!/bin/sh +echo "There is no equivalent to cvsgettags for Subversion" +exit 1 diff --git a/scripts/svnlastchange b/scripts/svnlastchange new file mode 100755 index 00000000..c9c271ea --- /dev/null +++ b/scripts/svnlastchange @@ -0,0 +1,172 @@ +#!/usr/bin/env perl +# +# This file is Copyright (C) 2005 Thiago Macieira <thiago@kde.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# ===================================================================== +# This is a replacement for the old svnlastchange script, with a bit +# more of functionality. +# +# The old one was: +# svn log -r COMMITTED "$*" +# svn diff -r PREV:COMMITTED "$*" || \ +# echo >&2 "Error retrieving diff: the file was probably added in the last revision" +# +# ===================================================================== + +# Turn on warnings the best way depending on the Perl version. +BEGIN { + if ( $] >= 5.006_000) + { require warnings; import warnings; } + else + { $^W = 1; } +} +use strict; + +# +# Read the parameters +# +my @files; +my $rev; +my $special = 0; +my $onlyrev = 0; +my $onlylog = 0; +while (@ARGV) + { + my $arg = shift @ARGV; + if ($arg eq '-h') + { + &usage; + exit 0; + } + elsif ($arg =~ /^-r(.*)$/) + { + $rev = $1; + if (length($1) == 0) + { + $rev = shift @ARGV; + } + $special = 1 if ($rev =~ /^-/); + } + elsif ($arg eq '-R') + { + $onlyrev = 1; + $special = 1; + $rev = -1 unless $rev; + } + elsif ($arg eq '-l') + { + $onlylog = 1; + } + else + { + push(@files, $arg); + } + } +@files = ('.') unless @files; + +if (!$special) + { + my $prev; + if ($rev) + { + $prev = $rev - 1; + } + else + { + $rev = 'COMMITTED'; + $prev = 'PREV'; + } + + system('svn', 'log', '-r', $rev, @files); + system('svn', 'diff', '-r', "$prev:$rev", @files) unless $onlylog; + exit $?; + } + +# +# Special operation +# Retrieve the full log in order to find the right version +# +foreach my $file (@files) + { + my $pid = open(LOG, '-|'); + die "svnlastchange: cannot fork: $!\n" unless (defined $pid); + unless ($pid) + { + open(STDERR, ">&STDOUT") + or die "svnlastchange: cannot dup STDOUT: $!\n"; + exec('svn', 'log', $file) + or die "svnlastchange: cannot exec svn: $!\n"; + } + + my $is_header = 0; + while (<LOG>) + { + s/[\r\n]+$//; + + if ($is_header && /^r(\d+) \| /) + { + $rev = $rev + 1; + if ($rev == 0) + { + if ($onlyrev) + { + print "$1\n"; + } + else + { + system('svn', 'log', '-r', $1, $file); + system('svn', 'diff', '-r', ($1 - 1) . ":$1", $file) + unless $onlylog; + } + last; + } + } + + if ($_ eq '------------------------------------------------------------------------') + { + $is_header = 1; + } + else + { + $is_header = 0; + } + } + close(LOG); + exit $? if $?; + } + +sub usage +{ + print "svnlastchange [-hlR] [-r rev] [filename...]\n"; + print "\n"; + print "Where:\n"; + print " -h shows this help screen\n"; + print " -l shows the commit log only\n"; + print " -R prints the revision number only (to be used with -r)\n"; + print " -r rev shows the commit log for revision 'rev'\n"; + print " if rev is negative, the 'rev'nth revision before the current\n"; + print " one is shown\n"; + print "\n"; + print "Examples:\n"; + print " svnlastchange . shows the last change to the current directory\n"; + print " svnlastchange -r -2 shows the change before the last\n"; + print " svnlastchange -R -r -1 shows the last change's revision\n"; + + exit 0; +} + + diff --git a/scripts/svnlastlog b/scripts/svnlastlog new file mode 100755 index 00000000..d812b13b --- /dev/null +++ b/scripts/svnlastlog @@ -0,0 +1,4 @@ +#!/bin/sh +# This is a stripped down version of svnlastchange + +svnlastchange -l "$@" diff --git a/scripts/svnrevertlast b/scripts/svnrevertlast new file mode 100755 index 00000000..e98a2e53 --- /dev/null +++ b/scripts/svnrevertlast @@ -0,0 +1,9 @@ +#!/bin/sh + +surl=$PWD +for i in $@ ; +do + cd $surl/`dirname $i` + svn merge -r BASE:PREV `basename $i` +done + diff --git a/scripts/svnversions b/scripts/svnversions new file mode 100755 index 00000000..fbdca03b --- /dev/null +++ b/scripts/svnversions @@ -0,0 +1,51 @@ +#! /usr/bin/env bash +unset LANG LC_ALL +LC_ALL=C +export LC_ALL + +if [ $# -eq 1 ]; then + svn info $1 | awk '/^Last Changed Rev/ { print $4 }' +else + for f; do + svn info $f | awk "/^Last Changed Rev/ { print \"$f\", \$4 }" + done +fi + +exit + +=head1 NAME + +svnversions -- Displays version of the files passed as argument. + +=head1 SYNOPSIS + + svnversions <file1> [<file2> [...]] + +=head1 DESCRIPTION + +svnversions displays the last revision a file in Subversion was +changed, as known by the local checked out directory. No connection is +required to the Subversion server. It is equivalent to the "COMMITTED" +revision name. + +Unlike svnversion(1), this program returns the revision a file was +modified. svnversion(1) tells the revision a working dir is at. + +It can be used in other scripts, or simply to ask for diffs using + +svn diff -r [<version>:]<version> <file(s)> + +=head1 AUTHOR + +Thiago Macieira <thiago@kde.org> + +Inspired on cvsversion, written by +David Faure <faure@kde.org> + +=head1 SEE ALSO + +This command parses the output from 'svn info'. + + svn(1), svnversion(1) + +=cut diff --git a/scripts/zonetab2pot.py b/scripts/zonetab2pot.py new file mode 100755 index 00000000..2549e8e6 --- /dev/null +++ b/scripts/zonetab2pot.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +'''This script reads timezone list as its first argument +or from /usr/share/zoneinfo/zone.tab, and converts it +to a PO file template. + +This is free software, released under GPL. +Author: Lukas Tinkl <lukas@kde.org>, 2002 +''' + +import sys +import fileinput +import string + +def makePOT(_file): + for line in fileinput.input(_file): + if (line[0]=='#'): #skip comments + continue + section=string.split(string.strip(line), '\t')[2] #third field, tab separated + newline='msgid \"' + section+ '\"\n' #msgid + newline+='msgstr \"\"\n' #msgstr + print(newline) #output to stdout + +if __name__ == '__main__': + makePOT(sys.argv[1:] or "/usr/share/zoneinfo/zone.tab") |