gifsicle-1.78/0000755000175000017500000000000012251251540010234 500000000000000gifsicle-1.78/gifview.10000644000175000017500000001360412251251477011713 00000000000000.\" -*- mode: nroff -*- .ds V 1.78 .ds E " \-\- .if t .ds E \(em .de Op .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de Oa .IR "\fB\\$1\& \|\fI\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de Qo .RB ` "\\$1" "'\\$2" .. .de Sp .if n .sp .if t .sp 0.4 .. .de Es .Sp .RS 5 .nf .. .de Ee .fi .RE .PP .. .TH GIFVIEW 1 "5 May 2012" "Version \*V" .SH NAME gifview \- displays GIF images and animations on the X window system .SH SYNOPSIS .B gifview \%[\fB--display\fP \fIdisplay\fP] \%[options] \%[filenames and frames].\|.\|. ' .SH DESCRIPTION .B gifview displays GIF image files on workstations and terminals running the X Window System. .B gifview understands multi-image GIFs, which can be displayed either as slideshows or as animations. ' .SH INTERACTION .B gifview windows recognize several keystrokes and button commands. Many of them are only useful for multi-image GIFs. .TP 12 .RB "Space or " n ' Go to the next frame. .TP .BR b " or " p Go to the previous frame. .TP .BR r " or " < Go to the first frame. .TP .BR > Go to the last frame. .TP ESC Stop the animation. .TP .BR s " or " a Toggle between animation and slideshow mode. .TP .BR u Toggle between normal and unoptimized mode. .TP Backspace ' Delete this window. .TP .B q Quit .BR gifview . ' .PP Left-clicking on a window goes to the next frame; right-clicking on a window deletes that window. ' .SH COMMAND LINE .BR gifview 's command line consists of .IR "GIF input files" and .IR options . Most options start with a dash (\-) or plus (+); frame selections, a kind of option, start with a number sign (#). Anything else is a GIF input file. .PP .B gifview displays one window for each GIF input file you specify. If no GIF input file is given, or you give the special filename `\-', it reads from the standard input. ' .SH OPTIONS .PD 0 .TP 5 .Op \-\-animate ", " \-a ' Animate multi-image GIFs by default. Normally, multi-image GIFs first appear in slideshow mode. You can always use the .RB ` a ' keystroke to toggle between modes. This option has a converse, .Qo \-\-no\-animate or .Qo +a . ' .Sp .TP 5 .Op \-\-unoptimize ", " \-U ' Display multi-image GIFs as ``unoptimized'', which shows a faithful representation of what a user will see at each frame of an animation. See .BR gifsicle (1) for a more detailed description of unoptimization. This option has a converse, .Qo \-\-no\-unoptimize or .Qo +U . GIFs are always displayed unoptimized in animation mode. ' .Sp .TP 5 .Oa \-d display .TP .Oa \-\-display display ' Sets the X display to .IR display . This option must come before any GIF files. ' .Sp .TP 5 .Oa \-\-name name ' Sets the application name under which resources are found, rather than the default of "gifview". Since .B gifview itself does not use the resource database, this is mostly useful for communication with your window manager. ' .Sp .TP 5 .Oa \-\-geometry geometry ' Set the size and position of .BR gifview 's windows. This is a standard X option. At most one .Op \-\-geometry option can be given per window (that is, per input GIF file). ' .Sp .TP 5 .Oa \-\-title title ' Sets the .B gifview window's title. The default is "gifview", followed by information about the currently displayed file and frame. ' .Sp .TP 5 .Oa \-w window .TP .Oa \-\-window window ' Display the next GIF input in an existing X window, instead of making a new top-level window. This way, you can use .B gifview to display animated GIFs in a window you created with another program. The .I window argument should be an integer .RB ( gifview will use that window ID) or `root' .RB ( gifview will use the root window). ' .Sp .TP 5 .Oa \-\-new\-window window ' Display the next GIF input in a new child of an existing X window. This child window will disappear when .B gifview exits. The .I window argument should be an integer .RB ( gifview will use that window ID) or `root' .RB ( gifview will use the root window). ' .Sp .TP 5 .Op \-\-install\-colormap ", " \-i ' Use a private colormap for each window (if you are using a PseudoColor display). This avoids polluting the existing colormap, and may produce better results if your colormap is full, but causes annoying colormap flashing. ' .Sp .TP 5 .Oa \-\-background color .TP .Oa \-\-bg color ' Set the background color, which is used for transparent pixels. ' .Sp .TP 5 .Oa \-\-min\-delay delay ' Set the minimum delay between frames to .IR delay , which is measured in hundredths of a second. Default is 0. ' .Sp .TP 5 .Oa \-\-fallback\-delay delay ' Set the frame delay of GIFs that do not specify a delay value or have a delay of 0. The final value is still subject to the value of \-\-min\-delay. Like \-\-min\-delay, .IR delay is measured in hundredths of a second. Default is 0. ' .Sp .TP 5 .Op \-\-no\-interactive ", " \+e ' Don't pay attention to mouse buttons or keystrokes. ' .Sp .TP 5 .Op \-\-memory\-limit lim ' Cache at most .I lim megabytes of images in memory when animating. Default is 40. ' .Sp .TP 5 .Op \-\-help ' Print usage information and exit. ' .Sp .TP .Op \-\-version ' Print the version number and some quickie warranty information and exit. ' .PD ' .\" ----------------------------------------------------------------- .SS Frame Selections A frame selection tells .B gifview which frame to initially display from the current input file. They are useful only for animations, as non-animated GIFs only have one frame. Frame selections can only be displayed in slideshow mode. .Sp .PD 0 .TP 13 .BI # num ' Select frame \fInum\fR. (The first frame is .Qo #0 . Negative numbers count backwards from the last frame, which is .Qo #-1 .) ' .TP 13 .BI # name ' Select the frame named \fIname\fR. .PD .PP If you give two or more frame selections, you will get one window per frame selection. ' .SH SEE ALSO .BR gifsicle (1) ' .SH BUGS Please email suggestions, additions, patches and bugs to ekohler@gmail.com. ' .SH AUTHORS .na Eddie Kohler, ekohler@gmail.com .br http://www.read.seas.harvard.edu/~kohler/ .PP http://www.lcdf.org/gifsicle/ .br The .B gifsicle home page. ' gifsicle-1.78/INSTALL0000644000175000017500000001644612237442106011224 00000000000000Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. gifsicle-1.78/install-sh0000755000175000017500000003325512237442114012173 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gifsicle-1.78/COPYING0000644000175000017500000004320612237442106011220 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. gifsicle-1.78/gifsicle.10000644000175000017500000007237712251251477012054 00000000000000.\" -*- mode: nroff -*- .ds V 1.78 .ds E " \-\- .if t .ds E \(em .de Op .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de Oa .IR "\fB\\$1\& \|\fI\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de Qo .RB \(oq "\\$1" "\(cq\\$2" .. .de Qa .BI "\fR\(oq\fB\\$1" " \\$2" " \\$3" " \\$4" "\fR\(cq\\$5" .. .de Sp .if n .sp .if t .sp 0.4 .. .de Ix .TP 25 \\$1 .nh \\$2 .hy .. .de Es .Sp .RS 5 .nf .. .de Ee .fi .RE .PP .. .de Xs .RS 5 .nf .. .de Xe .fi .RE .. .TH GIFSICLE 1 "5 May 2012" "Version \*V" .SH NAME gifsicle \- manipulates GIF images and animations .SH SYNOPSIS .B gifsicle \%[options, frames, and filenames].\|.\|. ' .SH DESCRIPTION .B gifsicle is a powerful command-line program for creating, editing, manipulating, and getting information about GIF images and animations. .PP .B Gifsicle normally processes input GIF files according to its command line options and writes the result to the standard output. The .Op \-i option, for example, tells .B gifsicle to interlace its inputs: .Es \fBgifsicle \-i < pic.gif > interlaced-pic.gif\fR .Ee .PP .B Gifsicle is good at creating and manipulating GIF animations. By default, it combines two or more input files into a \(lqflipbook\(rq animation: .Es \fBgifsicle pic1.gif pic2.gif pic3.gif > animation.gif\fR .Ee Use options like .Op \-\-delay ", " \-\-loopcount ", and " \-\-optimize to tune your animations. .PP To modify GIF files in place, use the .Op \-\-batch option. With .Op \-\-batch , .B gifsicle will modify the files you specify instead of writing a new file to the standard output. To interlace all the GIFs in the current directory, you could say: .Es \fBgifsicle \-\-batch \-i *.gif .Ee .PP New users may want to skip to the Examples section at the end. ' .SH CONCEPT INDEX ' Concepts are on the left, relevant .B gifsicle options are on the right. ' .Sp .PD 0 .Ix "Animations, changing" "frame selections, frame changes, etc." .Ix "\ \ \ disposal" "\fB\-\-disposal\fP" .Ix "\ \ \ looping" "\fB\-\-loopcount\fP" .Ix "\ \ \ portions of" "frame selections" .Ix "\ \ \ smaller" "\fB\-\-optimize\fP, \fB\-\-colors\fP" .Ix "\ \ \ speed" "\fB\-\-delay\fP" .Ix "Bad output" "\fB\-\-careful\fP" .Ix "Background color" "\fB\-\-background\fP" .Ix "Colors, changing" "\fB\-\-change\-color\fP, \fB\-\-use\-colormap\fP, \fB\-\-dither\fP, \fB\-\-transform\-colormap\fP" .Ix "\ \ \ reducing number" "\fB\-\-colors\fP, \fB\-\-dither\fP, \fB\-\-gamma\fP" .Ix "Comments" "\fB\-\-comment\fP" .Ix "Extensions" "\fB\-\-extension\fP, \fB\-\-app\-extension\fP, \fB\-\-extension\-info\fP" .Ix "File size" "\fB\-\-optimize\fP, \fB\-\-unoptimize\fP, \fB\-\-colors\fP" .TP 30 Image transformations .Ix "\ \ \ cropping" "\fB\-\-crop\fP, \fB\-\-crop\-transparency\fP" .Ix "\ \ \ flipping" "\fB\-\-flip\-*\fP" .Ix "\ \ \ resizing" "\fB\-\-resize\fP, \fB\-\-scale\fP" .Ix "\ \ \ rotating" "\fB\-\-rotate\-*\fP" .Ix "Grayscale" "\fB\-\-use\-colormap\fP" .Ix "Interlacing" "\fB\-\-interlace\fP" .Ix "Positioning frames" "\fB\-\-position\fP" .Ix "Screen, logical" "\fB\-\-logical\-screen\fP" .Ix "Selecting frames" "frame selections (like \fB'#0'\fP)" .Ix "Transparency" "\fB\-\-transparent\fP" .Ix "Warnings" "\fB\-\-no\-warnings\fP" .PD ' .SH COMMAND LINE .BR gifsicle 's command line consists of GIF input files and options. Most options start with a dash (\-) or plus (+); frame selections, a kind of option, start with a number sign (#). Anything else is a GIF input file. .PP .B gifsicle reads and processes GIF input files in order. If no GIF input file is given, or you give the special filename \(oq\-\(cq, it reads from the standard input. .PP .B gifsicle exits with status 0 if there were no errors and status 1 otherwise. ' .SH OPTIONS Every option has a long form, .Qo \-\-long\-descriptive\-name . You don't need to type the whole long descriptive name, just enough to make it unambiguous. .PP Some options also have a short form, .Qo \-X . You can combine short options if they don't take arguments: .Qo \-IIb is the same as .Qo "\-I \-I \-b" . But be careful with options that do take arguments: .Qo \-cblah means .Qo "\-c \fRblah" , not .Qo "\-c \-b \-l \-a \-h" . .PP Many options also have a converse, .Qo \-\-no\-option , which turns off the option. You can turn off a short option .Qo \-X by saying .Qo \+X instead. ' .\" ----------------------------------------------------------------- .SS Mode Options Mode options tell .B gifsicle what kind of output to generate. There can be at most one, and it must precede any GIF inputs. .TP 5 .Op "\-\-merge" ", " "\-m" ' Combine all GIF inputs into one file with multiple frames and write that file to the standard output. This is the default mode. ' .TP .Op \-\-batch ", " \-b ' Modify each GIF input in place by reading and writing to the same filename. (GIFs read from the standard input are written to the standard output.) ' .TP .Op \-\-explode ", " \-e ' Create an output GIF for each frame of each input file. The output GIFs are named \(oqxxx.000\(cq, \(oqxxx.001\(cq, and so on, where \(oqxxx\(cq is the name of the input file (or whatever you specified with .Qo \-\-output ) and the numeric extension is the frame number. ' .TP .Op \-\-explode\-by\-name ", " \-E ' Same as .Op \-\-explode "," but write any named frames to files \(oqxxx.\fIname\fR\(cq instead of \(oqxxx.\fIframe-number\fR\(cq. Frames are named using the .Qo \-\-name option. ' .\" ----------------------------------------------------------------- .SS General Options General options control the information .B gifsicle prints and where it writes its output. The info options and .Op \-\-verbose can be turned off with .Qo \-\-no\-X . ' .Sp .PD 0 .TP 5 .Op \-\-info ", " \-I ' Print a human-readable description of each input GIF to the standard output, or whatever file you specify with .Op \-o . This option suppresses normal output, and cannot be combined with mode options like .Op \-\-batch . If you give two .Op \-\-info or .Op \-I options, however, information is printed to standard error, and normal output takes place as usual. ' .Sp .TP 5 .Op \-\-color\-info ", " \-\-cinfo ' Like .Op \%\-\-info , but also print information about input files' colormaps. ' .Sp .TP 5 .Op \-\-extension\-info ", " \-\-xinfo ' Like .Op \%\-\-info , but also print any unrecognized GIF extensions in a .BR hexdump (1)-like format. ' .Sp .TP 5 .Op \-\-size\-info ", " \-\-sinfo ' Like .Op \%\-\-info , but also print information about compressed image sizes. ' .Sp .TP 5 .Op \-\-help ", " \-h ' Print usage information and exit. ' .Sp .TP .Oa \-o file .TP .Oa \-\-output file ' Send output to .IR file . The special filename \(oq-\(cq means the standard output. ' .Sp .TP .Op \-\-verbose ", " \-V ' Print progress information (files read and written) to standard error. ' .Sp .TP .Op \-\-no\-warnings ", " \-w ' Suppress all warning messages. ' .Sp .TP .Op \-\-version ' Print the version number and some short non-warranty information and exit. ' .Sp .PD 0 .TP 5 .Op \-\-careful ' Write slightly larger GIFs that avoid bugs in some other GIF implementations. Some Java and Internet Explorer versions cannot display the correct, minimal GIFs that Gifsicle produces. Use the .Op \-\-careful option if you are having problems with a particular image. ' .Sp .TP .Op \-\-conserve\-memory ' Conserve memory usage at the expense of processing time. This may be useful if you are processing large GIFs on a computer without very much memory. ' .Sp .TP .Op \-\-nextfile ' Allow input files to contain multiple concatenated GIF images. If a filename appears multiple times on the command line, \fBgifsicle\fR will read a new image from the file each time. This option can help scripts avoid the need for temporary files. For example, to create an animated GIF with three frames with different delays, you might run "\fBgifsicle \-\-nextfile \-d10 \- \-d20 \- \-d30 \- > out.gif\fR" and write the three GIF images, in sequence, to \fBgifsicle\fR's standard input. ' .Sp .TP .Op \-\-multifile ' Like .Op \-\-nextfile , but read .I as many GIF images as possible from each file. This option is intended for scripts. For example, to merge an unknown number of GIF images into a single animation, run "\fBgifsicle \-\-multifile \- > out.gif\fR" and write the GIF images, in sequence, to \fBgifsicle\fR's standard input. Any frame selections apply only to the last file in the concatenation. ' .PD ' .\" ----------------------------------------------------------------- .SS Frame Selections A frame selection tells .B gifsicle which frames to use from the current input file. They are useful only for animations, as non-animated GIFs only have one frame. Here are the acceptable forms for frame specifications. .Sp .PD 0 .TP 13 .BI # num ' Select frame \fInum\fR. (The first frame is .Qo #0 . Negative numbers count backwards from the last frame, which is .Qo #-1 .) ' .TP 13 .BI # num1 \- num2 ' Select frames \fInum1\fR through \fInum2\fR. ' .TP 13 .BI # num1 \- ' Select frames \fInum1\fR through the last frame. ' .TP 13 .BI # name ' Select the frame named \fIname\fR. .PD .PP The \(oq#\(cq character has special meaning for many shells, so you generally need to quote it. .PP For example, .Xs \fBgifsicle happy.gif "#0"\fR .Xe uses the first frame from happy.gif; .Xs \fBgifsicle happy.gif "#0-2"\fR .Xe uses its first three frames; and .Xs \fBgifsicle happy.gif "#-1-0"\fR .Xe uses \(oqhappy.gif\(cqs frames in reverse order (starting from frame #-1\*Ethe last frame\*Eand ending at frame #0\*Ethe first). .PP The action performed with the selected frames depends on the current mode. In merge mode, only the selected frames are merged into the output GIF. In batch mode, only the selected frames are modified; other frames remain unchanged. In explode mode, only the selected frames are exploded into output GIFs. ' .\" ----------------------------------------------------------------- .SS Frame Change Options Frame change options insert new frames into an animation or replace or delete frames that already exist. Some things\*Efor example, changing one frame in an animation\*Eare difficult to express with frame selections, but easy with frame changes. ' .TP 5 .Oa \-\-delete frames " [" frames ".\|.\|.]" ' Delete .I frames from the input GIF. ' .TP .Oa \-\-insert\-before "frame other-GIFs" ' Insert .I other-GIFs before .I frame in the input GIF. ' .TP .Oa \-\-append "other-GIFs" ' Append .I other-GIFs to the input GIF. ' .TP .Oa \-\-replace "frames other-GIFs" ' Replace .I frames from the input GIF with .IR other-GIFs . ' .TP \fB\-\-done\fR ' Complete the current set of frame changes. ' .PP The .I frames arguments are frame selections (see above). These arguments always refer to frames from the .I original input GIF. So, if \(oqa.gif\(cq has 3 frames and \(oqb.gif\(cq has one, this command .Xs \fBgifsicle a.gif \-\-delete "#0" \-\-replace "#2" b.gif\fR .Xe will produce an output animation with 2 frames: \(oqa.gif\(cq frame 1, then \(oqb.gif\(cq. .PP The .I other-GIFs arguments are any number of GIF input files and frame selections. These images are combined in merge mode and added to the input GIF. The .I other-GIFs last until the next frame change option, so this command replaces the first frame of \(oqin.gif\(cq with the merge of \(oqa.gif\(cq and \(oqb.gif\(cq: .Xs \fBgifsicle \-b in.gif \-\-replace "#0" a.gif b.gif\fR .Xe .PP This command, however, replaces the first frame of \(oqin.gif\(cq with \(oqa.gif\(cq and then processes \(oqb.gif\(cq separately: .Xs \fBgifsicle \-b in.gif \-\-replace "#0" a.gif \-\-done b.gif\fR .Xe .PP Warning: You shouldn't use both frame selections and frame changes on the same input GIF. ' .\" ----------------------------------------------------------------- .SS Image Options Image options modify input images\*Eby changing their interlacing, transparency, and cropping, for example. Image options have three forms: .Qo \-\-X , .Qo \-\-no\-X , and .Qo \-\-same\-X . The .Qo \-\-X form selects a value for the feature, the .Qo \-\-no\-X form turns off the feature, and the .Qo \-\-same\-X form means that the feature's value is copied from each input. The default is always .Qo \-\-same\-X . For example, .Op \-background= """#0000FF""" sets the background color to blue, .Op \-\-no\-background turns the background color off (by setting it to 0), and .Op \-\-same\-background uses input images' existing background colors. You can give each option multiple times; for example, .Xs \fBgifsicle \-b \-O2 \-i a.gif \-\-same\-interlace b.gif c.gif\fR .Xe will make \(oqa.gif\(cq interlaced, but leave \(oqb.gif\(cq and \(oqc.gif\(cq interlaced only if they were already. ' .Sp .PD 0 .TP 5 .Oa \-B color .TP .Oa \-\-background color ' Set the output GIF's background to .IR color . The argument can have the same forms as in the .Op \-\-transparent option below. ' .Sp .TP .Oa \-\-crop x1 , y1 - x2\fR,\fIy2 .TP .Oa \-\-crop x1 , y1 + width\fRx\fIheight ' Crop the following input frames to a smaller rectangular area. The top-left corner of this rectangle is .RI ( x1 , y1 ); you can give either the lower-right corner, .RI ( x2 , y2 ), or the width and height of the rectangle. In the .IR x1 , y1 + width x height form, .I width and .I height can be zero or negative. A zero dimension means the cropping area goes to the edge of the image; a negative dimension brings the cropping area that many pixels back from the image edge. For example, .Op \-\-crop " 2,2+-2x-2" will shave 2 pixels off each side of the input image. Cropping takes place before any rotation, flipping, resizing, or positioning. ' .Sp .TP .Op \-\-crop\-transparency ' Crop any transparent borders off the following input frames. This happens after any cropping due to the .Op \-\-crop option. It works on the raw input images; for example, any transparency options have not yet been applied. ' .Sp .TP .Op \-\-flip\-horizontal .TP .Op \-\-flip\-vertical ' Flip the following frames horizontally or vertically. ' .Sp .TP .Op \-i .TP .Op \-\-interlace ' Turn interlacing on. ' .Sp .TP .Oa \-S width x height .TP .Oa \-\-logical\-screen width x height ' Set the output logical screen to .IR width x height . .Op \-\-no\-logical\-screen sets the output logical screen to the size of the largest output frame, while .Op \-\-same\-logical\-screen sets the output logical screen to the largest input logical screen. .Op \-\-screen is a synonym for .Op \-\-logical\-screen . ' .Sp .TP .Oa \-p x\fR,\fIy .TP .Oa \-\-position x\fR,\fIy ' Set the following frames' positions to .RI ( x , y ). .Op \-\-no\-position means .Op \-\-position " 0,0." Normally, .Oa \-\-position x\fR,\fIy places every succeeding frame exactly at \fIx\fR,\fIy\fR. However, if an entire animation is input, \fIx\fR,\fIy\fR is treated as the position for the animation. ' .Sp .TP .Op \-\-rotate\-90 .TP .Op \-\-rotate\-180 .TP .Op \-\-rotate\-270 ' Rotate the following frames by 90, 180, or 270 degrees. .Op \-\-no\-rotate turns off any rotation. ' .Sp .TP .Oa \-t color .TP .Oa \-\-transparent color ' Make .I color transparent in the following frames. .I Color can be a colormap index (0\-255), a hexadecimal color specification (like "#FF00FF" for magenta), or slash- or comma-separated red, green and blue values (each between 0 and 255). .PD ' .\" ----------------------------------------------------------------- .SS Extension Options Extension options add non-visual information to the output GIF. This includes names, comments, and generic extensions. ' .Sp .PD 0 .TP 5 .Oa \-x app\-name " " extension .TP .Oa \-\-app\-extension app\-name " " extension ' Add an application extension named .I app\-name and with the value .I extension to the output GIF. ' .Sp .TP .Oa \-c text .TP .Oa \-\-comment text ' Add a comment, .IR text , to the output GIF. The comment will be placed before the next frame in the stream. .Sp .Op \-\-no\-comments and .Op \-\-same\-comments affect all the images following, and apply only to input GIF comments, not ones added with .Op \-\-comment . ' .Sp .TP .Oa \-\-extension number " " extension ' Add an extension numbered .I number and with the value .I extension to the output GIF. .I Number can be in decimal, octal, hex, or it can be a single character like \(oqn\(cq, whose ASCII value is used. .Sp .Op \-\-no\-extensions (or .Op +x ) and .Op \-\-same\-extensions affect all the images following, and apply only to input GIF extensions. ' .Sp .TP .Oa \-n text .TP .Oa \-\-name text ' Set the next frame's name to .IR text . This name is stored as an extension in the output GIF (extension number 0xCE, followed by the characters of the frame name). .Sp .Op \-\-no\-names and .Op \-\-same\-names affect all the images following. They apply only to input GIF names, not ones added with .Op \-\-name . ' .PD ' .\" ----------------------------------------------------------------- .SS Animation Options Animation options apply to GIF animations, or to individual frames in GIF animations. As with image options, most animation options have three forms, .Qo \-\-X , .Qo \-\-no\-X , and .Qo \-\-same\-X , and you can give animation options multiple times; for example, .Xs \fBgifsicle \-b a.gif \-d50 "#0" "#1" \-d100 "#2" "#3"\fR .Xe sets the delays of frames 0 and 1 to 50, and frames 2 and 3 to 100. ' .Sp .PD 0 .TP 5 .Oa \-d time .TP .Oa \-\-delay time ' Set the delay between frames to .IR time in hundredths of a second. ' .Sp .TP .Oa \-D method .TP .Oa \-\-disposal method ' Set the disposal method for the following frames to .IR method . A frame's disposal method determines how a viewer should remove the frame when it's time to display the next. .I Method can be a number between 0 and 7 (although only 0 through 3 are generally meaningful), or one of these names: .BR none (leave the frame visible for future frames to build upon), .BR asis (same as "none"), .BR background " (or " bg ")" (replace the frame with the background), or .BR previous (replace the frame with the area from the previous displayed frame). .Op \-\-no\-disposal means .Op \-\-disposal = none . ' .Sp .TP .Op \-l "[\fIcount\fR]" .TP .Op \-\-loopcount "[=\fIcount\fR]" ' Set the Netscape loop extension to .IR count . .I Count is an integer, or .B forever to loop endlessly. If you supply a .Op \-\-loopcount option without specifying .IR count , Gifsicle will use .BR forever . .Op \-\-no\-loopcount (the default) turns off looping. .Sp Set the loop count to one less than the number of times you want the animation to run. An animation with .Op \-\-no\-loopcount will show every frame once; .Op \-\-loopcount =1 will loop once, thus showing every frame twice; and so forth. Note that .Op \-\-loopcount =0 is equivalent to .Op \-\-loopcount =forever, not .Op \-\-no\-loopcount . ' .Sp .TP .Op \-O "[\fIlevel\fR]" .TP .Op \-\-optimize "[=\fIlevel\fR]" ' Optimize output GIF animations for space. .I Level determines how much optimization is done; higher levels take longer, but may have better results. There are currently three levels: .Sp .RS .TP 5 .Op \-O1 Stores only the changed portion of each image. This is the default. .TP 5 .Op \-O2 Also uses transparency to shrink the file further. .TP 5 .Op \-O3 Try several optimization methods (usually slower, sometimes better results). .Sp .PP Other optimization flags provide finer-grained control. .Sp .TP 5 .Op \-Okeep-empty Preserve empty transparent frames (they are dropped by default). .Sp .PP There is no .Op \-\-same\-optimize option. .RE ' .Sp .TP 5 .Oa \-U .TP .Oa \-\-unoptimize ' Unoptimize GIF animations into an easy-to-edit form. .Sp GIF animations are often optimized (see .Op \-\-optimize ) to make them smaller and faster to load, which unfortunately makes them difficult to edit. .Op \-\-unoptimize changes optimized input GIFs into unoptimized GIFs, where each frame is a faithful representation of what a user would see at that point in the animation. .Sp There is no .Op \-\-same\-unoptimize option. .RE ' .PD ' .\" ----------------------------------------------------------------- .SS Image Transformation Options ' Image transformation options apply to entire GIFs as they are read or written. They can be turned off with .Qo \-\-no\-option . ' .Sp .PD 0 .TP 5 .Oa \-\-resize width x height ' Resize the output GIF to .IR width x height . Either .I width or .I height may be an underscore \(oq_\(cq. If the argument is .IR width x_, then the output GIF is scaled to .I width pixels wide without changing its aspect ratio. An analogous operation is performed for .RI _x height . Resizing happens after all input frames have been combined and before optimization. Gifsicle's resize algorithm is designed for speed, not quality; for best-looking results you will need to use other tools. ' .Sp .TP .Oa \-\-resize\-width width .TP .Oa \-\-resize\-height height ' Like .Oa \-\-resize width x_ and .Oa \-\-resize "" _x height respectively. ' .Sp .TP .Oa \-\-resize\-fit width x height ' Like .Op \-\-resize , but resizes the output GIF to fit .I within a rectangle with dimensions .IR width x height . The GIF's aspect ratio remains unchanged. No resize is performed if the GIF already fits within the given rectangle. Either .I width or .I height may be an underscore \(oq_\(cq, which is treated as infinity. ' .Sp .TP .Oa \-\-resize\-fit\-width width .TP .Oa \-\-resize\-fit\-height height ' Like .Oa \-\-resize\-fit width x_ and .Oa \-\-resize\-fit "" _x height respectively. ' .Sp .TP .Oa \-\-scale Xfactor [x Yfactor ] ' Scale the output GIF's width and height by .IR Xfactor " and " Yfactor . If .I Yfactor is not given, it defaults to .IR Xfactor . Scaling happens after all input frames have been combined and before optimization. .PD ' .\" ----------------------------------------------------------------- .SS Color Options ' Color options apply to entire GIFs as they are read or written. They can be turned off with .Qo \-\-no\-option . .Sp .PD 0 .TP 5 .Oa \-k num .TP .Oa \-\-colors num ' Reduce the number of distinct colors in each output GIF to .I num or less. .I Num must be between 2 and 256. This can be used to shrink output GIFs or eliminate any local color tables. .Sp Normally, an adaptive group of colors is chosen from the existing color table. You can affect this process with the .Op \-\-color\-method option or by giving your own colormap with .Op \-\-use\-colormap . Gifsicle may need to add an additional color (making .IR num +1 in all) if there is transparency in the image. ' .Sp .TP .Oa \-\-color\-method method ' Determine how a smaller colormap is chosen. .RB \(oq diversity \(cq, the default, is .BR xv (1)'s diversity algorithm, which uses a strict subset of the existing colors and generally produces good results. .RB \(oq blend\-diversity \(cq is a modification of this: some color values are blended from groups of existing colors. .RB \(oq median\-cut \(cq is the median cut algorithm described by Heckbert. .Op \-\-method is a synonym for .Op \-\-color\-method . ' .Sp .TP 5 .Oa \-f .TP .Op \-\-dither "[=\fImethod\fR]" ' When .Op \-\-dither is on and the colormap is changed, combinations of colors are used to approximate missing colors. This looks better, but makes bigger files and can cause animation artifacts, so it is off by default. .Sp Specify a dithering algorithm with the optional \fImethod\fR argument. The default, .RB \(oq floyd-steinberg \(cq, uses Floyd-Steinberg error diffusion. This usually looks best, but can cause animation artifacts, because dithering choices will vary from frame to frame. Gifsicle also supports ordered dithering algorithms that avoid animation artifacts. The .RB \(oq ro64 \(cq mode uses a large, random-looking pattern and generally produces good results. The .RB \(oq o3 \(cq, .RB \(oq o4 \(cq, and .RB \(oq o8 \(cq modes use smaller, more regular patterns. The .RB \(oq ordered \(cq mode chooses a good ordered dithering algorithm. For special effects, try the halftone modes .RB \(oq halftone \(cq, .RB \(oq squarehalftone \(cq, and .RB \(oq diagonal \(cq. Some modes take optional parameters using commas. The halftone modes take a cell size and a color limit: .RB \(oq halftone,10,3 \(cq creates 10-pixel wide halftone cells where each cell uses up to 3 colors. ' .Sp .TP 5 .Oa \-\-gamma gamma ' Set the gamma correction to .IR gamma , which can be a real number or .RB \(oq srgb \(cq. Roughly speaking, higher numbers exaggerate shadows and lower numbers exaggerate highlights. The default is the function defined by the standard sRGB color space, which usually works well. (Its effects are similar to \fB\-\-gamma\fP=2.2.) Gifsicle uses gamma correction when choosing a color palette (\fB\-\-colors\fP) and when dithering (\fB\-\-dither\fP). ' .Sp .PD 0 .TP .Oa \-\-change\-color color1 " " color2 ' Change .I color1 to .I color2 in the following input GIFs. (The .I color arguments have the same forms as in the .Op \-t option.) Change multiple colors by giving the option multiple times. Color changes don't interfere with one another, so you can safely swap two colors with .Qa \-\-change\-color "color1 color2" \-\-change\-color "color2 color1" . They all take effect as an input GIF is read. .Op \-\-no\-change\-color cancels all color changes. ' .Sp .TP .Oa \-\-transform\-colormap command ' .I Command should be a shell command that reads from standard input and writes to standard output. Each colormap in the output GIF is translated into text colormap format (see .Op \-\-use\-colormap below) and piped to the command. The output that command generates (which should also be in text colormap format) will replace the input colormap. The replacement doesn't consider color matching, so pixels that used color slot .I n in the input will still use color slot .I n in the output. ' .Sp .TP .Oa \-\-use\-colormap colormap ' Change the image to use .IR colormap . Each pixel in the image is changed to the closest match in .I colormap (or, if .Op \-\-dither is on, to a dithered combination of colors in .IR colormap ")." .I Colormap can be .BR web for the 216-color \(lqWeb-safe palette\(rq; .BR gray for grayscale; .BR bw for black-and-white; or the name of a file. That file should either be a text file (the format is described below) or a GIF file, whose global colormap will be used. If .Op \-\-colors\fR=\fIN is also given, an .IR N \-sized subset of .I colormap will be used. .Sp Text colormap files use this format: .Es ; each non-comment line represents one color, "red green blue" ; each component should be between 0 and 255 0 0 0 ; like this 255 255 255 ; or use web hex notation #ffffff ; like this .Ee ' .PD .PP .br ' .SH EXAMPLES ' First, let's create an animation, \(oqanim.gif\(cq: .Es \fBgifsicle a.gif b.gif c.gif d.gif > anim.gif\fR .Ee This animation will move very quickly: since we didn't specify a delay, a browser will cycle through the frames as fast as it can. Let's slow it down and pause .5 seconds between frames, using the .Op \-\-delay option. .Es \fBgifsicle \-\-delay 50 a.gif b.gif c.gif d.gif > anim.gif\fR .Ee If we also want the GIF to loop three times, we can use .Op \-\-loopcount : .Es \fBgifsicle \-d 50 \-\-loop=3 a.gif b.gif c.gif d.gif > anim.gif\fR .Ee (Rather than type .Op \-\-delay again, we used its short form, .Op \-d . Many options have short forms; you can see them by running .RB \(oq "gifsicle \-\-help" \(cq. We also abbreviated .Op \-\-loopcount to .Op \-\-loop , which is OK since no other option starts with \(oqloop\(cq.) .PP To explode \(oqanim.gif\(cq into its component frames: .Es \fBgifsicle \-\-explode anim.gif\fR .br \fBls anim.gif*\fR .br anim.gif anim.gif.000 anim.gif.001 anim.gif.002 anim.gif.003 .Ee To optimize \(oqanim.gif\(cq: .Es \fBgifsicle \-b \-O2 anim.gif\fR .Ee To change the second frame of \(oqanim.gif\(cq to \(oqx.gif\(cq: .Es \fBgifsicle \-b \-\-unoptimize \-O2 anim.gif \-\-replace "#1" x.gif\fR .Ee .Op \-\-unoptimize is used since \(oqanim.gif\(cq was optimized in the last step. Editing individual frames in optimized GIFs is dangerous without .Op \-\-unoptimize ; frames following the changed frame could be corrupted by the change. Of course, this might be what you want. .PP Note that .Op \-\-unoptimize and .Op \-\-optimize can be on simultaneously. .Op \-\-unoptimize affects .I input GIF files, while .Op \-\-optimize affects .I output GIF files. .PP To print information about the first and fourth frames of \(oqanim.gif\(cq: .Es \fBgifsicle \-I "#0" "#3" < anim.gif\fR .Ee To make black the transparent color in all the GIFs in the current directory, and also print information about each: .Es \fBgifsicle \-bII \-\-trans "#000000" *.gif\fR .Ee Giving .Op \-I twice forces normal output to occur. With only one .Op \-I , the GIFs would not be modified. .PP To change \(oqanim.gif\(cq to use a 64-color subset of the Web-safe palette: .Es \fBgifsicle \-b \-\-colors=64 \-\-use\-col=web anim.gif\fR .Ee To make a dithered black-and-white version of \(oqanim.gif\(cq: .Es \fBgifsicle \-\-dither \-\-use\-col=bw anim.gif > anim-bw.gif\fR .Ee .PP To overlay one GIF atop another\*Eproducing a one-frame output GIF that looks like the superposition of the two inputs\*Euse .B gifsicle twice: .Es \fBgifsicle bottom.gif top.gif | gifsicle \-U "#1" > result.gif\fR .Ee ' .SH BUGS ' Some optimized output GIFs may appear incorrectly on some GIF implementations (for example, Java's); see the .Op \-\-careful option. .PP Please email suggestions, additions, patches and bugs to ekohler@gmail.com. ' .SH "SEE ALSO" ' For a tutorial on GIF images and animations, you might try some of the resources listed on-line at webreference\%.com: .br http://www.webreference.com/authoring/graphics/animation\|.html ' .SH AUTHORS .na Eddie Kohler .br http://www.read.seas.harvard.edu/~kohler/ .br He wrote it. .PP Anne Dudfield .br http://www.frii.com/~annied/ .br She named it. .PP Hans Dinsen-Hansen .br http://www.danbbs.dk/~dino/ .br Adaptive tree method for GIF writing. .PP http://www.lcdf.org/gifsicle/ .br The .B gifsicle home page. ' gifsicle-1.78/gifdiff.10000644000175000017500000000276212251251477011654 00000000000000.\" -*- mode: nroff -*- .ds V 1.78 .ds E " \-\- .if t .ds E \(em .de Op .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de Sp .if n .sp .if t .sp 0.4 .. .de Es .Sp .RS 5 .nf .. .de Ee .fi .RE .PP .. .TH GIFDIFF 1 "31 August 1998" "Version \*V" .SH NAME gifdiff \- compares GIF images .SH SYNOPSIS .B gifdiff \%[options] GIF\-file\-1 GIF\-file\-2 ' .SH DESCRIPTION .B gifdiff compares two GIF files and determines if they appear identical. Differences that don't affect appearance (like colormap ordering or how much an animation is optimized) are not reported. .PP .B gifdiff prints details of any differences it finds. If the GIFs are the same, it prints nothing. It exits with status 0 if there were no differences, 1 if there were some differences, and 2 if there was trouble. ' .SH OPTIONS .PD 0 .TP 5 .Op \-\-brief ", " \-q ' Report only whether the GIFs differ, not the details of the differences. ' .Sp .TP 5 .Op \-\-ignore\-redundancy ", " \-w ' Do not report differences in the numbers of redundant frames (frames which do not change the displayed image). ' .Sp .TP 5 .Op \-\-help ' Print usage information and exit. ' .Sp .TP .Op \-\-version ' Print the version number and some quickie warranty information and exit. ' .PD ' .SH SEE ALSO .BR gifsicle (1) ' .SH BUGS Please email suggestions, additions, patches and bugs to ekohler@gmail.com. ' .SH AUTHORS .na Eddie Kohler, ekohler@gmail.com .br http://www.read.seas.harvard.edu/~kohler/ .PP http://www.lcdf.org/gifsicle/ .br The .B gifsicle home page. ' gifsicle-1.78/depcomp0000755000175000017500000005601612237442114011544 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # 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, 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, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gifsicle-1.78/NEWS0000644000175000017500000007752612251251245010676 00000000000000Gifsicle NEWS Version 1.78 9.Dec.2013 * Correct an optimization bug introduced in 1.76. Reported by Tom Roostan. Version 1.77 26.Nov.2013 * Major improvements to color selection (important when reducing colormap size). Use gamma-corrected colors in selection and dithering; this makes image quality much better. Also, when reducing colors with dithering, prefer to select colors that dithering can't approximate. * Add ordered dithering modes, which avoid animation artifacts. The default ordered dithering mode (`--dither=ordered`) is a novel mode that combines some of the visual advantages of error diffusion with the artifact avoidance of ordered dithering. * Add halftone dithering (`--dither=halftone`). * gifview: Improved cache memory management for better animations. Collect memory for old frames based on an explicit --memory-limit (default 40MB). * gifview: Add `--fallback-delay` option, to specify a fallback delay for frames with delay 0. Thanks to Sung Pae. Version 1.76 20.Nov.2013 * Fix `-O2` crashes introduced with `--resize` improvements. Reported by Bryan Stillwell. Version 1.75 18.Nov.2013 * Improve `--careful` (fewer crashes). Reported by Bryan Stillwell. * Improve `-O2`: again, don't refuse to optimize images with local color tables. Reported by Bryan Stillwell. * Greatly improve `--dither` speed. Version 1.74 16.Nov.2013 * Improve `--resize` behavior: avoid animation artifacts due to different rounding decisions. Also speed it up. Reported by Bryan Stillwell. Version 1.73 15.Nov.2013 * Fix bug where `-O2` would refuse to optimize some images with local color tables, claiming that "more than 256 colors were required". What was really required is previous disposal. Reported by Bryan Stillwell. Version 1.72 9.Nov.2013 * Fix crash bugs on some combinations of `--crop` and `--resize` (prevalent on images whose first frame didn't cover the whole logical screen). Reported by Bryan Stillwell. Version 1.71 15.Jun.2013 * Avoid rounding errors in `--resize`. Reported by Paul Kane. * Report error when `-I` is combined with `-b`. Reported by Frank Dana. * Frame selections also apply in batch mode. Reported by LOU Yu Hong Leo. Version 1.70 31.Jan.2013 * Fix `--crop` bug introduced in version 1.68, visible in images containing local color tables. Bug reported by Alberto Nannini. Version 1.69 31.Jan.2013 * Minor bug fix release. Version 1.68 24.Nov.2012 * gifsicle: Alberto Nannini reported some images that are optimized beyond what Gifsicle can do. In fact, Gifsicle's GIF writer was limited enough that even when running without optimization, it seriously expanded the input images. Some improvements to Gifsicle's writing procedure avoid this problem; now `gifsicle IMAGE` will produce large results less often, and when it does generate larger results, they're larger by hundreds of bytes, not hundreds of thousands. However, due to restrictions in the current optimizer (and on my time), I was unable to improve `gifsicle -O3`'s handling of these images. The optimizer that produced the images must be doing something pretty clever. (Is it SuperGIF?) Version 1.67 5.May.2012 * gifsicle: Frame specifications like "#2-0" are allowed; they insert frames in reverse order. Feature request from Leon Arnott. * gifview: Add --min-delay option. Version 1.66 2.Apr.2012 * gifsicle: Add -Okeep-empty for Gerald Johanson. Version 1.65 2.Apr.2012 * gifsicle: Several users (Kornel LesiÅ„ski and others) reported "bugs" with Gifsicle-optimized images and Mac programs like Safari. The bug is in Safari, but add --careful to work around it. * Improve -O3 a bit (although for some images, the new -O3 is bigger than the old). Version 1.64 22.Nov.2011 * gifsicle: Add --resize-fit options. Tom Glenne request. Version 1.63 17.Jul.2011 * gifsicle: Avoid crash on frame selections where frames are repeated. Werner Lemberg report. Version 1.62 4.Apr.2011 * gifsicle: -O3 optimization level tries even harder, so that now gifsicle -O3 should never produce larger results than gifsicle-1.60 -O2. Jernej SimonÄiÄ report. Version 1.61 25.Feb.2011 * gifsicle: Add new -O3 optimization level, which applies several transparency heuristics and picks the one with the best result. David Jamroga pointed out a file that gifsicle made larger; -O3 shrinks it. * gifsicle: Correct some optimizer bugs introduced in 1.59 that could lead to visually different output. * gifdiff: Add -w/--ignore-redundancy option. * gifview: Correct crash bug. * gifsicle/gifdiff: Correct occasionally odd error messages. Version 1.60 12.Apr.2010 * GIF reading library: Correct error that could corrupt the reading of certain large images. Reported by Jernej SimonÄiÄ. Version 1.59 11.Mar.2010 * gifsicle -O2: Optimize away entirely-transparent frames when possible. Requested by Gerald Johanson. Version 1.58 14.Jan.2010 * gifsicle: Fix optimizer bug reported by Dion Mendel. Version 1.57 11.Nov.2009 * gifsicle: Don't throw away totally-cropped frames with 0 delay, since most browsers treat 0-delay frames as 100ms-delay frames. Reported by Calle Kabo. Version 1.56 18.Oct.2009 * gifsicle: Fix --crop-transparency for animated images; previous versions could lose frames. Problem reported by Daniel v. Dombrowski. * gifview: Make --disposal=background behavior look like Firefox. Version 1.55 3.Apr.2009 * gifsicle: Another optimize fix for --disposal previous. Reported by Gerald Johanson. Version 1.54 3.Apr.2009 * gifsicle, gifview: Fix several serious bugs with --disposal previous that could affect optimized, unoptimized, and displayed images. Reported by Gerald Johanson. Version 1.53 19.Mar.2009 * gifsicle: Frames in an unoptimized image will use disposal "none" when possible. This leads to fewer surprises later. Version 1.52 18.May.2008 * gifsicle: Fix bug introduced in 1.51: --crop-transparent works. Reported by dgdd wanadoo fr. Version 1.51 12.May.2008 * gifsicle: '--crop' preserves the logical screen when it can. Reported by Petio Tonev. Version 1.50 7.May.2008 * gifsicle, gifview: Refuse to read GIFs from the terminal. Requested by Robert Riebisch. Version 1.49 2.May.2008 * Just some Makefile updates requested by Robert Riebisch. Version 1.48 16.Mar.2007 * gifsicle: Avoid crash in '--crop-transparency' when an image's first frame is totally transparent. Reported by Gerald Johanson. Version 1.47 10.Mar.2007 * gifsicle: Improve '--nextfile' behavior. Version 1.46 9.Jan.2007 * gifsicle: Add '--nextfile' option, useful for scripts. Problem reported by Jason Young. Version 1.45 30.Dec.2006 * Do not compile gifview by default when X is not available. * gifview: Add '--title' option, based on patch supplied by Andres Tello Abrego. Version 1.44 3.Oct.2005 * gifview: Enforce a minimum delay of 0.002 sec. Requested by Dale Wiles. Version 1.43 8.Sep.2005 * '-I -b', and other similar combinations, causes a fatal error rather than putting information in an unexpected file. Reported by Michiel de Bondt. Version 1.42 8.Jan.2005 * Improve manual page. Version 1.41 19.Aug.2004 * Fix problems with 64-bit machines. Thanks to Dan Stahlke for pointing out the problem and providing a patch. Version 1.40 28.Aug.2003 * Fix longstanding bug where '--disposal=previous' was mistakenly equivalent to '--disposal=asis'. * Include Makefile.bcc, from Stephen Schnipsel. Version 1.39 11.Jul.2003 * Fix Makefile.w32 (oops). Version 1.38 26.Jun.2003 * Include Makefile.w32 (oops). Version 1.37 11.Feb.2003 * Fix bug where combining `--rotate-X' and `-O' options would cause a segmentation fault. Reported by Dan Lasley . * Rearrange source tree. Version 1.36 17.Nov.2002 * Fix subscript-out-of-range error in main.c reported by Andrea Suatoni. Version 1.35 14.Aug.2002 * Fixed bug where `--crop' could cause a segmentation fault, present since 1.32 or 1.33. Reported by Tom Schumm . Version 1.34 13.Aug.2002 * Fixed bug where combining `--crop' and `-O' options could corrupt output. Reported by Tom Schumm . Version 1.33 1.Aug.2002 * Be more careful about time while animating. In particular, prepare frames before they are needed, so that they can be displayed exactly when required. Problem reported by Walter Harms . * More warning fixes. Version 1.32 5.Jul.2002 * Add `--multifile' option handling concatenated GIF files. This is useful for scripts. For example, `gifsicle --multifile -' will merge all GIF files written to its standard input into a single animation. * More fixes for spurious background warnings. Version 1.31 17.Jun.2002 * Changed behavior of `--crop X,Y+WIDTHxHEIGHT' option when WIDTH or HEIGHT is negative. Previously, zero or negative WIDTH and HEIGHT referred to the image's entire width or height. Thus, the option `--crop 10,0+0x0' would always lead to an error, because the crop left position (10) plus the crop width (the image width) was 10 pixels beyond the image edge. The new behavior measures zero or negative WIDTH and HEIGHT relative to the image's bottom-right corner. * Changed background behavior. Hopefully the only user-visible effect will be fewer spurious warnings. * Fixed a bug that could corrupt output when optimizing images with `-O2' that had more than 256 colors. Version 1.30 27.Jul.2001 * Fixed bug in ungif code: Writing a large ungif could corrupt memory, leading eventually to bad output. This bug has been present since Gifsicle could write ungifs! Bad files and assistance provided by Jeff Brown . Version 1.29 22.May.2001 * Fixed an optimization bug that could produce bad images. Again, reported by Dale Wiles . It turns out that 1.26 was a bad release! I've reconstructed and run some regression tests; hopefully Dale and I have exhausted the bug stream. Version 1.28 13.May.2001 * `--colors' option still didn't work; it produced bad images. Again, thanks to Dale Wiles for reporting the bug. * Added explicit `--conserve-memory' option. Version 1.27 10.May.2001 * Fixed `--colors' option, which caused segmentation faults. Thanks to Dale Wiles for reporting the bug. Version 1.26 22.Apr.2001 * Added `--crop-transparency' option, which crops any transparent edges off the image. Requested by Gre7g Luterman . * Try to conserve memory in gifsicle when working with huge images (> 20 megabytes of uncompressed data). May make gifsicle slower if you actually had enough memory to deal with the uncompressed data. Version 1.25 13.Feb.2001 * Fixed gifview bug: If every frame in an animation had a small or zero delay, then gifview would previously enter a infinite loop and become noninteractive. Reported by Franc,ois Petitjean . Version 1.24 11.Feb.2001 * Delete `unoptimized_pixmaps' array when deleting a viewer in gifview. Reported by Franc,ois Petitjean . * Added `--resize-width' and `--resize-height' options. * Why is it that Frenchmen are always telling me to delete the Clp_Parser immediately before calling exit()? Don't they realize that exit() frees application memory just as well as free()? Are things different in France? More French, perhaps? Version 1.23 12.Dec.2000 * In Houston on a layover because of stupid Continental Airlines: allow GIFs without terminators. Problem reported by Matt Olech . Version 1.22 23.Nov.2000 * Handle time more carefully when displaying animations. Should result in more precise timings. Problem reported by Iris Baye . Version 1.21 9.Sep.2000 * Fixed `--careful -O2', which could create bad GIFs when there were bad interactions with transparency. Bug reported by Manfred Schwarb . Version 1.20 23.Jun.2000 * Added `--careful' option, because some bad GIF implementations (Java, Internet Explorer) don't support Gifsicle's super-optimized, but legal, GIFs. Problem reported by Andrea Beiser . * Gifdiff will work on very large images (better memory usage). Version 1.19 25.Apr.2000 * Fixed memory corruption bug: `gifsicle --use-colormap=FILE.gif' would formerly cause a segmentation fault. Bug reported by Alan Watts . Version 1.18 3.Apr.2000 * Gifview now uses X server memory more parsimoniously. This should make it more robust, and nicer to the X server, on large animations. Requested by Vladimir Eltsov . Appears to solve bug reported by Vince McIntyre . * Gifview treats frame selection more sensibly. A frame selection just tells it which frame to start on. * Added a message to the manual page warning people to quote the `#' character in frame selections. The interactive bash shell, for example, interprets it as a comment. Version 1.17 15.Mar.2000 * Added `--resize _xH' and `--resize Wx_'. Requested by Edwin Piekart . * Changed behavior of `--no-logical-screen'. Now gifsicle will include all visible GIFs when calculating the size of the logical screen. * Got rid of spurious redundant-option warnings. Version 1.16.1 10.Sep.1999 * Gifview can put a GIF (or an animated GIF) on the root window; use `gifview -w root'. Requested by Roland Blais . Version 1.16 31.Aug.1999 * Optimization improvement: More colormap manipulation. Version 1.16 produces smaller GIFs than 1.15 in the large majority of cases (but not all). * Fixed memory corruption bug in quantization. Found and fixed by Steven Marthouse . Version 1.15 20.Aug.1999 * Bug fix: no more assertion failures when combining images that require local colormaps. * Fixed serious quantization bug introduced in 1.14: when reducing the number of colors, gifsicle would ignore a random portion of the colors in the old colormap. * Optimization bug fix: two adjacent identical frames will no longer crash the optimizer. Bug introduced in 1.14. That's two for two: two "speed improvements" in 1.14, two bugs introduced! * Bug fix: Exploding the standard input results in files named `#stdin#.NNN', as the documentation claims, not `.NNN'. * Optimization improvement: the optimizer reorders colormaps in a slightly smarter way, which can result in smaller compression. * If a position option like `-p 0,5' is followed by a multi-frame GIF (without frame specifications), then the position option places the animation as a whole, not each of its individual frames. * An unrecognized nonnumeric frame specification is now treated as a file name, so you can say `gifsicle #stdin#.000', for example. * Gifview improvements: Now even images with local color tables can be "unoptimized" or animated. * `--replace' now preserves the replaced frame's disposal as well as its delay. * `gifsicle -I -' reports "" as the input file name. Version 1.14.2 16.Aug.1999 * Fixed memory bug in Gif_DeleteImage (I freed a block of memory, then accessed it). I am a moron!! This bug affected Version 1.14.1 only. Version 1.14.1 9.Aug.1999 * Fixed configuration bug: you couldn't compile gifsicle from a different directory (it told you to try --enable-ungif). * Steven Marthouse helped fix `Makefile.w32' to enable wildcards in filenames under Windows. Requested by Mark Olesen . Version 1.14 2.Aug.1999 * Switched to an adaptive tree strategy for LZW GIF compression, which is faster than the old hashing strategy. This method is the brainchild of Hans Dinsen-Hansen . * Bug fix/optimization improvement: Some images would include a transparent index that was not a valid color (it was larger than the colormap). Gifsicle formerly ignored these transparent indices. It doesn't any longer; furthermore, it will generate those kinds of transparent index, which can mean smaller colormaps and smaller GIFs. * Speed improvements in optimization and colormap quantization. * Added `--no-warnings' (`-w') option to inhibit warning messages. Suggested by Andrea Beiser . * `--info' output can now be sent to a file with `-o', just as with any other kind of output. * More specific error messages on invalid GIFs. Version 1.13 16.Jun.1999 * Added optional support for run-length-encoded GIFs to avoid patent problems. Run-length encoding idea based on code by Hutchinson Avenue Software Corporation found in Thomas Boutell's gd library . * `gifsicle --explode' now generates filenames of the form `file.000 .. file.100' rather than `file.0 .. file.100', so you can use shell globbing like `file.*' and automatically get the right order. * Added `--background' option to gifview, so you can set the color used for transparent pixels. Suggested by Art Blair . * Gifdiff is built by default on Unix. Version 1.12 25.Mar.1999 * Added `--window' option to gifview, which lets it display a GIF in an arbitrary X window. Thanks to Larry Smith for patches. * Added `--install-colormap' to gifview. Suggested by Yair Lenga . * Gifsicle now exits with status 1 if there were any errors, status 0 otherwise. Before, it exited with status 1 only if there was a fatal error, or nothing was successfully output. The new behavior seems more useful. Problem reported by David Kelly . Version 1.11.2 10.Mar.1999 * `gifsicle -U' will now unoptimize 1-image GIFs as well as animations. Version 1.11.1 24.Jan.1999 * Fixed core dump on corrupted GIF files (in particular, bad extensions). Problem reported by tenthumbs . Version 1.11 22.Jan.1999 * Added `--scale XFACTORxYFACTOR' to complement `--resize'. * Made `--resize' work better on animations (no more off-by-one errors). * Fixed bug in `--use-colormap': If transparency was added to the new colormap, the transparent color index could later be used (incorrectly) as a real image color. This was particularly common if the image was dithered. * `--dither' now tries to mitigate "jumping dither" animation artifacts (where adjacent frames in an animation have different dithering patterns, so the animation shifts). It does an OK job. * Improvements to `--color-method=blend-diversity'. Version 1.10 6.Jan.1999 * Gifview is built by default. * No other changes from 1.10b1: Emil said it worked on Windows. Version 1.10b1 31.Dec.1998 * The two malloc packages that come with Gifsicle don't #define `malloc' or `realloc'; they #define `xmalloc' and `xrealloc'. * Changes to Windows port from Emil Mikulic . Version 1.9.2 28.Dec.1998 * Gifsicle compiles out of the box on Windows! Port maintained by Emil Mikulic . * Moved to config.h-based configuration to simplify GIF library and Windows port. * Some CLP improvements. Version 1.9.1 16.Dec.1998 * If a reduced-colormap image needs a special transparent color, gifsicle will now try to keep the same transparent color value as the input GIF. * Cropping an image now automatically recalculates the output logical screen, rather than retaining the logical screen of the uncropped image. * Improvement to colormap modification behavior: If it looks like a color reserved for transparency will be necessary, gifsicle will reserve a slot for it. This will reduce the likelihood that you ask for a colormap of size 64, say, and get one of size 128 (because gifsicle added a slot for transparency). Version 1.9 14.Dec.1998 * `--no-background' is now the same as `--background=0' (set the background to pixel 0) instead of `--same-background'. Version 1.9b3 10.Dec.1998 * Fixed a serious bug in merge.c introduced in 1.8: Merging several images with global colormaps could corrupt the output colors. * Fixed a serious bug in optimize.c introduced in 1.9b1: Optimizing GIFs which required local color tables could crash the program due to a buffer overrun. (I was adding the background to the output colormap without making sure there was room for it.) * Fixed an optimizer bug which could result in incorrect animations: background disposal was not handled correctly. * The optimizer now generates `--disposal=none' instead of `--disposal=asis' in certain situations, which can result in smaller animations. Suggestion by Markus F.X.J. Oberhumer . * GIF library changes: cleaner, somewhat faster GIF reading code inspired by Patrick J. Naughton , whose code is distributed with XV. Version 1.9b2 9.Dec.1998 * Fixed `--logical-screen' and `--no-logical-screen', which had no effect in 1.9b1. In a stunning turn of events, this problem was reported by Markus F.X.J. Oberhumer . Version 1.9b1 5.Dec.1998 * Added `--resize WxH' option, prompted by code from Christian Kumpf . * Made `--change-color PIXELINDEX color' work, and `--change-color color PIXELINDEX' illegal. * Many behavior fixes relating to background and transparency. Gifsicle would tend to create GIFs which looked as expected, but lost information internally; for example, a color value which was only used for transparency would be changed to black, no matter what the input color was. In some cases, gifsicle simply reports a warning now where it ignored information before. Problems reported by Markus F.X.J. Oberhumer . * Better error messages are now given on redundant, ambiguous, or useless command-line options. * Options that affect GIFs on output (such as `--output', `--optimize') now behave more like other options: you should put them before the files they affect. (You may still put them at the end of the argument list if they should affect the last output file.) This should only affect people who used batch or explode mode in complex ways. * Gifsicle will not write a GIF to stdout if it's connected to a terminal. Version 1.8 3.Dec.1998 * Fixed strange behavior when changing transparency: a new black entry was added to the colormap in almost all situations. Problem reported by Markus F.X.J. Oberhumer . * Fixed `--transform-colormap' bug: commands like "thing 2" (ending in an integer) will work now. * Small fixes (in a gifsicle pipeline, error messages won't be interleaved). Version 1.7.1 2.Dec.1998 * Added configuration check for `strerror'. Problem reported by Mario Gallotta . * Added colormap canonicalization: If you pipe a GIF through `gifsicle -O' or `-O2', the output colormaps will be arranged in a predictable order. Feature suggested by Markus F.X.J. Oberhumer . Version 1.7 28.Nov.1998 * Added `--use-colormap=gray' and `--use-colormap=bw'. Idea and some code thanks to Christian Kumpf . * Added `--transform-colormap', which allows you to plug programs into gifsicle that arbitrarily change GIF files' colormaps. * All `--change-color' options now happen simultaneously, so you can safely swap two colors with `--change-color C1 C2 --change-color C2 C1'. * Colormap modifications are slightly more powerful (they don't reserve a color for transparency if they don't need one, and if a subset of the modified colormap is used, only that subset is output). * Fixed `--use-colormap' bug: the last color in a used colormap would be ignored (it was reserved for transparency). Symptom: if you put a partially transparent image into the Web-safe palette, the result would never contain white. * When changing to a grayscale colormap, gifsicle now uses luminance difference to find the closest color. This gives better results for `--use-colormap=gray' and the like. * Added Introduction and Concept Index sections to the gifsicle manpage. * The gifsicle package now uses automake. Version 1.6 23.Nov.1998 * A frame extracted from the middle of an animation will now have the animation's screen size rather than 640x480. Problem reported by Mr. Moose . Version 1.5 27.Sep.1998 * `--help' now prints on stdout, as according to the GNU standards. * Changes to support Win32 port thanks to Emil Mikulic . * Makefiles: Added `make uninstall' target, enabled `./configure's program name transformations, made VPATH builds possible. Version 1.4.1 16.Sep.1998 * Fixed `--unoptimize' bug: a frame's transparency could disappear under rare circumstances. Bug reported by Rodney Brown Version 1.4 12.Sep.1998 * Added `--extension' and `--app-extension'. Version 1.3.4 7.Sep.1998 * More configuration changes. * Fixed bug in gifview `--geometry' option processing: `--geometry -0-0' wasn't recognized. Version 1.3.2 5.Sep.1998 * Fixed configuration bugs reported by Alexander Mai (OS/2 build didn't work). Version 1.3.1 4.Sep.1998 * Fixed configuration bug: int32_t could be improperly redefined. Reported by Anne "Idiot" Dudfield and Dax Kelson . Version 1.3 3.Sep.1998 * Added `--flip-*' and `--rotate-*' options. * Fixed rare bug in GIF writing code: the last pixel in a frame could previously become corrupted. Version 1.3b1 2.Aug.1998 * Optimization has been completely overhauled. All optimization functions are in a separate file, optimize.c. Some bugs have been caught. Optimization is now quite powerful, and rarely expands any input file. (An expansion of 1-30 bytes usually means that the input file cheated by leaving off 'end-of-image' codes, which the standard says must be used.) People interested in making optimization even better should contact me, or just go ahead and hack the code. Thanks again to David Hedbor for providing test cases. Specific changes: - The optimizer can handle any input file, even one with local colormaps or more than 256 colors. If there are more than 256 colors, an optimal subset is placed in the global colormap. - The global colormap is reordered so that some images can use a small initial portion of it, which lets them compress smaller. - Bug fix: Images relying on background disposal are optimized correctly. - `-O2' never does worse than `-O1'. - Made the `-O2' heuristic better. Some other small changes and improvements here and there. - The optimizer has been pretty extensively tested using gifdiff. * New program: gifdiff compares two GIFs for identical appearance. It is not built unless you give the `--enable-gifdiff' option to `./configure'. It's probably not useful unless you're testing a GIF optimizer. * Robustness fixes in GIF library. Version 1.2.1 8.Jun.1998 * `--info' now sends information to standard output. `--info --info' still sends information to standard error. * `--transparent' didn't work. It does now. * Added `--background' option. Fixed background processing so that an input background is reflected in the output GIF. * Re-fixed small bug with the interaction between per-frame options and frame selections. Version 1.2 28.May.1998 * Fixed small bug with the interaction between per-frame options (`--name', `--comment') and frame selections. * Fixed bad bug in merge: If a global colormap from the source needed to be dumped into a local colormap in the destination, the pixel map was wrong, resulting in bad colors in the destination. * Fixed memory leaks. Changed memory usage pattern in gifsicle to release source image memory as soon as possible, resulting in a better memory profile. Both programs now keep images in compressed form for better performance. * Fixed bugs in gifread.c that corrupted memory when uncompressing some bad images. * Added debugging malloc library (`./configure --enable-dmalloc' to use it). * Added `--no-delay' and `--no-disposal' options, which should have been there all along. * `--crop' will not generate an image with 0 width or height, even if a frame is cropped out of existence. * Other performance improvements. Version 1.2b6 25.May.1998 * License clarification in README. * GIF comments are now printed out more carefully in `--info': binary characters appear as backslash escapes. (Literal backslashes are printed as `\\'.) * New `--extension-info/--xinfo' option. * Removed spurious warning about local colormaps when a `--colors' option is in effect. * Replacing a named frame with another image now keeps the name by default. * Many changes to gifview. Added `--animate', `--display', `--geometry', `--name', `--help' options, keystrokes, multiple GIFs on the command line, and a manual page. Version 1.2b5 12.May.1998 * Longstanding bug fix in gifunopt.c: an interlaced replacement frame caused strange behavior when later optimizing, as the underlying data wasn't deinterlaced. * Further improvements in optimizer; specifically, `-O2' works better now -- it uses actual image data to look for an unused pixel value when there's no transparency specified. Version 1.2b4 12.May.1998 * Improved `--optimize's performance on images where successive frames had different transparent color indexes. Version 1.2b3 11.May.1998 * Fixed bugs in `--unoptimize': it would try to unoptimize images with local color tables and some transparency manipulations could cause a silent failure (example: 2 colors; frame 0 = [*11], frame 1 = [*0*], where * is a transparent pixel. Unoptimized, frame 1 should contain [*01] -- but this can't be expressed with only 2 colors.) * Greatly improved `--optimize's performance on some images by changing the way frames were switched to `--disposal=background'. Problem noticed by David Hedbor * Documentation improvements. * Unrecognized extensions are now passed through without change. The `--no-extensions' option (currently undocumented) removes all unrecognized extensions. * Bug fix in gifview: frame selections now prevent display of entire GIF. Version 1.2b2 9.May.1998 * Fixed bad dumb bug in gif.h: lack of parens around macro argument * Changed heuristic for diversity algorithm: never blend if there are 3 colors or less * Some optimizations to Floyd-Steinberg code Version 1.2b1 8.May.1998 * Added colormap options: `--colors', `--color-method', `--dither', and `--use-colormap'. All this code is in quantize.c. * Renamed `--color-change' to `--change-color'. Version 1.1.2 * Added `--color-change' option. * Added negative frame numbers. `#-N' no longer means `#0-N'; it means the `N'th frame from the end (where `#-1' is the last frame). You can use negative frame numbers in ranges as well (e.g., `#-5--1'). Version 1.1.1 22.Nov.1997 * Fixed bug in CLP which segmentation-faulted on `-' arguments. Version 1.1 20.Nov.1997 * Added `--crop' option. * Changed usage behavior on bad command lines. Version 1.0 21.Jun.1997 * Added `--output/-o' option to specify output filename. * Slight behavior change: Now, if you replace a frame (say frame #2), its delay value will be preserved in the replacement frame, unless you give an explicit delay. (Before, the replacement frame's delay would be used, which was probably 0.) Version 0.91 15.Jun.1997 * Bug fix: `--optimize' didn't handle the bottom row of an image's changed area correctly. This could lead to incorrect animations. Specific change: merge.c line 744: was y < fbt, now y <= fbt. * Added `-S' as synonym for `--logical-screen'. Version 0.9 12.Jun.1997 * First public release. gifsicle-1.78/aclocal.m40000644000175000017500000011164212251251264012024 00000000000000# generated automatically by aclocal 1.13.3 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.13' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.13.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.13.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR gifsicle-1.78/Makefile.am0000644000175000017500000000465012237442106012221 00000000000000## Process this file with automake to produce Makefile.in AUTOMAKE_OPTIONS = foreign check-news SUBDIRS = src man_MANS = gifsicle.1 @OTHERMANS@ EXTRA_DIST = COPYING README.md gifsicle.spec \ include/lcdf/clp.h include/lcdf/inttypes.h \ include/lcdfgif/gif.h include/lcdfgif/gifx.h \ gifsicle.1 gifview.1 gifdiff.1 logo.gif logo1.gif gifsicle: @cd src && $(MAKE) gifsicle gifdiff: @cd src && $(MAKE) gifdiff gifview: @cd src && $(MAKE) gifview srclinks: cd $(top_srcdir); sh ./sourcecheckout.sh versionize: perl -pi -e "s/^\\.ds V.*/.ds V $(VERSION)/;" $(top_srcdir)/gifsicle.1 $(top_srcdir)/gifview.1 $(top_srcdir)/gifdiff.1 perl -pi -e "s/^Version:(\s+).*/Version:"'$$'"{1}$(VERSION)/; s/$(PACKAGE)-[\w.]+\.tar\.gz/$(PACKAGE)-$(VERSION).tar.gz/;" $(top_srcdir)/gifsicle.spec perl -pi -e "s/gifsicle [\d.]+/gifsicle $(VERSION)/; s/VERSION \"[\w.]+/VERSION \"$(VERSION)/;" $(top_srcdir)/src/win32cfg.h rpm: dist buildarch=`rpm --showrc | awk '/^build arch/ { print $$4; }'` ; \ mkdir -p /tmp/rpm-gfs/SOURCES /tmp/rpm-gfs/RPMS/$$buildarch \ /tmp/rpm-gfs/BUILD ; \ echo 'include: /usr/lib/rpm/rpmrc' > /tmp/rpm-gfs/rc ; \ echo 'macrofiles: /usr/lib/rpm/macros:/tmp/rpm-gfs/macros' >> /tmp/rpm-gfs/rc ; \ echo '%_topdir /tmp/rpm-gfs' > /tmp/rpm-gfs/macros ; \ cp logo1.gif $(PACKAGE)-$(VERSION).tar.gz /tmp/rpm-gfs/SOURCES ; \ rpmbuild --rcfile /tmp/rpm-gfs/rc -bb gifsicle.spec ; \ cp /tmp/rpm-gfs/RPMS/$$buildarch/*.rpm . rm -rf /tmp/rpm-gfs rpm-ungif: dist buildarch=`rpm --showrc | awk '/^build arch/ { print $$4; }'` ; \ mkdir -p /tmp/rpm-ugfs/SOURCES /tmp/rpm-ugfs/RPMS/$$buildarch \ /tmp/rpm-ugfs/BUILD ; \ echo 'include: /usr/lib/rpm/rpmrc' > /tmp/rpm-ugfs/rc ; \ echo 'macrofiles: /usr/lib/rpm/macros:/tmp/rpm-ugfs/macros' >> /tmp/rpm-ugfs/rc ; \ echo '%_topdir /tmp/rpm-ugfs' > /tmp/rpm-ugfs/macros ; \ cp logo1.gif $(PACKAGE)-$(VERSION).tar.gz /tmp/rpm-ugfs/SOURCES ; \ GIFSICLE_UNGIF=yes rpmbuild --rcfile /tmp/rpm-ugfs/rc -bb gifsicle.spec ; \ cp /tmp/rpm-ugfs/RPMS/$$buildarch/*.rpm `echo /tmp/rpm-ugfs/RPMS/$$buildarch/*.rpm | sed 's/.*gifsicle/ungifsicle/'` rm -rf /tmp/rpm-ugfs dist-ungif: dist $(AMTAR) xzf gifsicle-$(VERSION).tar.gz @rm gifsicle-$(VERSION)/src/gifwrite.c rm -rf ungifsicle-$(VERSION) mv gifsicle-$(VERSION) ungifsicle-$(VERSION) GZIP=$(GZIP_ENV) $(AMTAR) chozf ungifsicle-$(VERSION).tar.gz ungifsicle-$(VERSION) rm -rf ungifsicle-$(VERSION) .PHONY: srclinks versionize rpm dist-ungif rpm-ungif gifsicle-1.78/gifsicle.spec0000644000175000017500000000311612251251477012627 00000000000000Summary: GIF image and animation manipulator Name: gifsicle Version: 1.78 Release: 1 Source: http://www.lcdf.org/gifsicle/gifsicle-1.78.tar.gz Icon: logo1.gif URL: http://www.lcdf.org/gifsicle/ Group: Applications/Graphics Vendor: Little Cambridgeport Design Factory Packager: Eddie Kohler License: GPL BuildRoot: /tmp/gifsicle-build %description Gifsicle manipulates GIF image files on the command line. It supports merging several GIFs into a GIF animation; exploding an animation into its component frames; changing individual frames in an animation; turning interlacing on and off; adding transparency; adding delays, disposals, and looping to animations; adding or removing comments; optimizing animations for space; and changing images' colormaps, among other things. The gifsicle package contains two other programs: gifview, a lightweight GIF viewer for X, can show animations as slideshows or in real time, and gifdiff compares two GIFs for identical visual appearance. %prep %setup %build %configure make %install [ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install %clean [ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT %post %files %attr(-,root,root) %doc NEWS README %attr(0755,root,root) %{_bindir}/gifsicle %attr(0755,root,root) %{_bindir}/gifdiff %attr(0755,root,root) %{_bindir}/gifview %attr(0644,root,root) %{_mandir}/man1/gifsicle.1* %attr(0644,root,root) %{_mandir}/man1/gifdiff.1* %attr(0644,root,root) %{_mandir}/man1/gifview.1* gifsicle-1.78/logo1.gif0000644000175000017500000000146512237442106011676 00000000000000GIF89a0Dõk1!s91s99{9BR{9R{Bc)k„B{„B„1”ŒJ­Bµ”JÆJçRçBJçZRçœZïŒÆïµÖ÷Z÷c÷k÷!k÷9s÷B„÷R”÷{”÷œR÷¥R÷¥c÷­„ÿ„­ÿµ„ÿÆ”ÿÎŒÿÎ¥ÿÖµÿÞÎÿÿÿ!ù),0DÿÀ”p˜±ȤrÉ<^8CbsJm>£)Mu˵\DXLwÜÄ`S²ynÒëõ[Œ¯ÍX¸œÁ¾÷dt€y…cxCz‰U‹Bb\ƒQ“ ›› ”sCiŸ¡G  €‘)u²T®Ÿ·j}—j­ †av™ ¼UXZ{­Äg€ ±S–Q"“[uL¹Â¨I£~ŽKìíâKÚæF´QÜìã!ñuFÈ=&ùô)ä÷NI®i6ŒÂƒº# 3ê{Öd‘ &:³˜$¡F…áɪ'2EÅ pNjlÈ„`K,8ø“™qK›ÿ›CðÔ'a †@'Žꦒ ‡’NÁÔi›R£œ :ÔêÇ H³b!ñéÁ§Š"”i 0`ˆ+7˜µgPpåùïÚe‡öõ›µS gÝËs„â¤(ó}œ”,ÓÄ”o‚|ò‰Ì7=Ñ„hÒ"ÛuŒº ¾ x¶.xB°cgœ}f©‡H3ï!e'8@ƒŒŸ A¡ÏØèö }ˆiÛ \Çía´t¡Ć@¾Ý…”u€]€vôÅOQ[_‚Ø@wñù–~ `€>æ—Üp  À²Ö]Y͵‡Ý‚úí‡RL@À Ð~†y ¨—Àú'o @€8§OtÝ‘ðÚõÁØá~’µøƒû ¡šFœ¤Œ1èä“JöSR©å–\vùX;gifsicle-1.78/include/0000755000175000017500000000000012251251540011657 500000000000000gifsicle-1.78/include/lcdfgif/0000755000175000017500000000000012251251540013255 500000000000000gifsicle-1.78/include/lcdfgif/gifx.h0000644000175000017500000000476012243663074014324 00000000000000#ifndef LCDF_GIFX_H #define LCDF_GIFX_H #include #ifdef __cplusplus extern "C" { #endif /* gifx.h - Functions to turn GIFs in memory into X Pixmaps. Copyright (C) 1997-2013 Eddie Kohler, ekohler@gmail.com This file is part of the LCDF GIF library. The LCDF GIF library is free software*. It is distributed under the GNU General Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #include #define GIFX_COLORMAP_EXTENSION -107 typedef struct Gif_XContext Gif_XContext; typedef struct Gif_XColormap Gif_XColormap; typedef struct Gif_XFrame Gif_XFrame; struct Gif_XContext { Display *display; int screen_number; Drawable drawable; Visual *visual; uint16_t depth; uint16_t ncolormap; Colormap colormap; uint16_t nclosest; Gif_Color *closest; int free_deleted_colormap_pixels; Gif_XColormap *xcolormap; GC image_gc; GC mask_gc; unsigned long transparent_pixel; unsigned long foreground_pixel; int refcount; }; struct Gif_XFrame { Pixmap pixmap; int postdisposal; int user_data; }; Gif_XContext * Gif_NewXContext(Display *display, Window window); Gif_XContext * Gif_NewXContextFromVisual(Display *display, int screen_number, Visual *visual, int depth, Colormap cmap); void Gif_DeleteXContext(Gif_XContext *gfx); Pixmap Gif_XImage(Gif_XContext *gfx, Gif_Stream *gfs, Gif_Image *gfi); Pixmap Gif_XImageColormap(Gif_XContext *gfx, Gif_Stream *gfs, Gif_Colormap *gfcm, Gif_Image *gfi); Pixmap Gif_XSubImage(Gif_XContext *gfx, Gif_Stream *gfs, Gif_Image *gfi, int l, int t, int w, int h); Pixmap Gif_XSubImageColormap(Gif_XContext *gfx, Gif_Image *gfi, Gif_Colormap *gfcm, int l, int t, int w, int h); Pixmap Gif_XMask(Gif_XContext *gfx, Gif_Stream *gfs, Gif_Image *gfi); Pixmap Gif_XSubMask(Gif_XContext *gfx, Gif_Image *gfi, int l, int t, int w, int h); Gif_XFrame * Gif_NewXFrames(Gif_Stream *gfs); void Gif_DeleteXFrames(Gif_XContext *gfx, Gif_Stream *gfs, Gif_XFrame *frames); Pixmap Gif_XNextImage(Gif_XContext *gfx, Gif_Stream *gfs, int i, Gif_XFrame *frames); int Gif_XAllocateColors(Gif_XContext *gfx, Gif_Colormap *gfcm); void Gif_XDeallocateColors(Gif_XContext *gfx, Gif_Colormap *gfcm); unsigned long * Gif_XClaimStreamColors(Gif_XContext *gfx, Gif_Stream *gfs, int *np_store); #ifdef __cplusplus } #endif #endif gifsicle-1.78/include/lcdfgif/gif.h0000644000175000017500000002031612242717703014125 00000000000000/* gif.h - Interface to the LCDF GIF library. Copyright (C) 1997-2011 Eddie Kohler, kohler@cs.ucla.edu This file is part of the LCDF GIF library. The GIF library is free software. It is distributed under the GNU General Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #ifndef LCDF_GIF_H /* -*- mode: c -*- */ #define LCDF_GIF_H #include #include #include #ifdef __cplusplus extern "C" { #endif /* NOTE: You should define the types uint8_t, uint16_t and uint32_t before including this file, probably by #including . */ #define GIF_MAJOR_VERSION 1 #define GIF_MINOR_VERSION 5 #define GIF_VERSION "1.5" typedef struct Gif_Stream Gif_Stream; typedef struct Gif_Image Gif_Image; typedef struct Gif_Colormap Gif_Colormap; typedef struct Gif_Comment Gif_Comment; typedef struct Gif_Extension Gif_Extension; typedef struct Gif_Record Gif_Record; typedef uint16_t Gif_Code; #define GIF_MAX_CODE_BITS 12 #define GIF_MAX_CODE 0x1000 #define GIF_MAX_BLOCK 255 /** GIF_STREAM **/ struct Gif_Stream { Gif_Colormap *global; uint8_t background; uint16_t screen_width; uint16_t screen_height; long loopcount; /* -1 means no loop count */ Gif_Comment *comment; Gif_Image **images; int nimages; int imagescap; Gif_Extension *extensions; unsigned errors; int userflags; int refcount; }; Gif_Stream * Gif_NewStream(void); void Gif_DeleteStream(Gif_Stream *); Gif_Stream * Gif_CopyStreamSkeleton(Gif_Stream *); Gif_Stream * Gif_CopyStreamImages(Gif_Stream *); #define Gif_ScreenWidth(gfs) ((gfs)->screen_width) #define Gif_ScreenHeight(gfs) ((gfs)->screen_height) #define Gif_ImageCount(gfs) ((gfs)->nimages) #define GIF_UNOPTIMIZE_SIMPLEST_DISPOSAL 1 #define GIF_MAX_SCREEN_WIDTH 65535 #define GIF_MAX_SCREEN_HEIGHT 65535 void Gif_CalculateScreenSize(Gif_Stream *, int force); int Gif_Unoptimize(Gif_Stream *); int Gif_FullUnoptimize(Gif_Stream *, int flags); /** GIF_IMAGE **/ struct Gif_Image { char *identifier; Gif_Comment *comment; Gif_Colormap *local; short transparent; /* -1 means no transparent index */ uint16_t delay; uint8_t disposal; uint16_t left; uint16_t top; uint16_t width; uint16_t height; uint8_t interlace; uint8_t **img; /* img[y][x] == image byte (x,y) */ uint8_t *image_data; void (*free_image_data)(void *); uint32_t compressed_len; uint8_t *compressed; void (*free_compressed)(void *); void *user_data; void (*free_user_data)(void *); int refcount; }; #define GIF_DISPOSAL_NONE 0 #define GIF_DISPOSAL_ASIS 1 #define GIF_DISPOSAL_BACKGROUND 2 #define GIF_DISPOSAL_PREVIOUS 3 Gif_Image * Gif_NewImage(void); void Gif_DeleteImage(Gif_Image *gfi); int Gif_AddImage(Gif_Stream *gfs, Gif_Image *gfi); void Gif_RemoveImage(Gif_Stream *gfs, int i); Gif_Image * Gif_CopyImage(Gif_Image *gfi); Gif_Image * Gif_GetImage(Gif_Stream *gfs, int i); Gif_Image * Gif_GetNamedImage(Gif_Stream *gfs, const char *name); int Gif_ImageNumber(Gif_Stream *gfs, Gif_Image *gfi); #define Gif_ImageWidth(gfi) ((gfi)->width) #define Gif_ImageHeight(gfi) ((gfi)->height) #define Gif_ImageDelay(gfi) ((gfi)->delay) #define Gif_ImageUserData(gfi) ((gfi)->userdata) #define Gif_SetImageUserData(gfi, v) ((gfi)->userdata = v) typedef void (*Gif_ReadErrorHandler)(int is_error, const char *error_text, int frame_number, void *user_data); typedef struct { int flags; void *padding[7]; } Gif_CompressInfo; #define Gif_UncompressImage(gfi) Gif_FullUncompressImage((gfi),0,0) int Gif_FullUncompressImage(Gif_Image *gfs,Gif_ReadErrorHandler,void*); int Gif_CompressImage(Gif_Stream *gfs, Gif_Image *gfi); int Gif_FullCompressImage(Gif_Stream *gfs, Gif_Image *gfi, const Gif_CompressInfo *gcinfo); void Gif_ReleaseUncompressedImage(Gif_Image *gfi); void Gif_ReleaseCompressedImage(Gif_Image *gfi); int Gif_SetUncompressedImage(Gif_Image *gfi, uint8_t *data, void (*free_data)(void *), int data_interlaced); int Gif_CreateUncompressedImage(Gif_Image *gfi); int Gif_ClipImage(Gif_Image *gfi, int l, int t, int w, int h); void Gif_InitCompressInfo(Gif_CompressInfo *gcinfo); /** GIF_COLORMAP **/ typedef struct { uint8_t haspixel; union { struct { uint8_t red; uint8_t green; uint8_t blue; } comp; uint8_t a[3]; } c; #define gfc_red c.comp.red #define gfc_green c.comp.green #define gfc_blue c.comp.blue #define gfc_array c.a uint32_t pixel; } Gif_Color; struct Gif_Colormap { int ncol; int capacity; uint32_t userflags; int refcount; Gif_Color *col; }; Gif_Colormap * Gif_NewColormap(void); Gif_Colormap * Gif_NewFullColormap(int count, int capacity); void Gif_DeleteColormap(Gif_Colormap *); Gif_Colormap * Gif_CopyColormap(Gif_Colormap *); int Gif_ColorEq(Gif_Color *, Gif_Color *); #define GIF_COLOREQ(c1, c2) \ ((c1)->gfc_red==(c2)->gfc_red && (c1)->gfc_green==(c2)->gfc_green && \ (c1)->gfc_blue==(c2)->gfc_blue) int Gif_FindColor(Gif_Colormap *, Gif_Color *); int Gif_AddColor(Gif_Colormap *, Gif_Color *, int look_from); /** GIF_COMMENT **/ struct Gif_Comment { char **str; int *len; int count; int cap; }; Gif_Comment * Gif_NewComment(void); void Gif_DeleteComment(Gif_Comment *); int Gif_AddCommentTake(Gif_Comment *, char *, int); int Gif_AddComment(Gif_Comment *, const char *, int); /** GIF_EXTENSION **/ struct Gif_Extension { int kind; /* negative kinds are reserved */ char *application; uint8_t *data; uint32_t length; int position; Gif_Stream *stream; Gif_Extension *next; void (*free_data)(void *); }; Gif_Extension * Gif_NewExtension(int, const char *); void Gif_DeleteExtension(Gif_Extension *); int Gif_AddExtension(Gif_Stream *, Gif_Extension *, int); Gif_Extension * Gif_GetExtension(Gif_Stream *, int, Gif_Extension *); /** READING AND WRITING **/ struct Gif_Record { const unsigned char *data; uint32_t length; }; #define GIF_READ_COMPRESSED 1 #define GIF_READ_UNCOMPRESSED 2 #define GIF_READ_CONST_RECORD 4 #define GIF_READ_TRAILING_GARBAGE_OK 8 #define GIF_WRITE_CAREFUL_MIN_CODE_SIZE 1 #define GIF_WRITE_EAGER_CLEAR 2 #define GIF_WRITE_OPTIMIZE 4 #define GIF_WRITE_SHRINK 8 Gif_Stream * Gif_ReadFile(FILE *); Gif_Stream * Gif_FullReadFile(FILE *, int flags, Gif_ReadErrorHandler, void *); Gif_Stream * Gif_ReadRecord(const Gif_Record *); Gif_Stream * Gif_FullReadRecord(const Gif_Record *, int flags, Gif_ReadErrorHandler, void *); int Gif_WriteFile(Gif_Stream *gfs, FILE *f); int Gif_FullWriteFile(Gif_Stream *gfs, const Gif_CompressInfo *gcinfo, FILE *f); #define Gif_ReadFile(f) Gif_FullReadFile((f),GIF_READ_UNCOMPRESSED,0,0) #define Gif_ReadRecord(r) Gif_FullReadRecord((r),GIF_READ_UNCOMPRESSED,0,0) #define Gif_CompressImage(s, i) Gif_FullCompressImage((s),(i),0) #define Gif_WriteFile(s, f) Gif_FullWriteFile((s),0,(f)) /** HOOKS AND MISCELLANEOUS **/ int Gif_InterlaceLine(int y, int height); char * Gif_CopyString(const char *); #define GIF_T_STREAM (0) #define GIF_T_IMAGE (1) #define GIF_T_COLORMAP (2) typedef void (*Gif_DeletionHookFunc)(int, void *, void *); int Gif_AddDeletionHook(int, Gif_DeletionHookFunc, void *); void Gif_RemoveDeletionHook(int, Gif_DeletionHookFunc, void *); #ifdef GIF_DEBUGGING #define GIF_DEBUG(x) Gif_Debug x void Gif_Debug(char *x, ...); #else #define GIF_DEBUG(x) #endif #ifndef Gif_New # ifndef xmalloc # define xmalloc malloc # define xrealloc realloc # define xfree free # endif # define Gif_New(t) ((t *)xmalloc(sizeof(t))) # define Gif_NewArray(t, n) ((t *)xmalloc(sizeof(t) * (n))) # define Gif_ReArray(p, t, n) ((p)=((t*)xrealloc((void*)(p),sizeof(t)*(n)))) #endif #ifndef Gif_DeleteFunc # define Gif_DeleteFunc (&xfree) # define Gif_DeleteArrayFunc (&xfree) #endif #ifndef Gif_Delete # define Gif_Delete(p) (*Gif_DeleteFunc)((void *)(p)) # define Gif_DeleteArray(p) (*Gif_DeleteArrayFunc)((void *)(p)) #endif #ifdef __cplusplus } #endif #endif gifsicle-1.78/include/lcdf/0000755000175000017500000000000012251251540012567 500000000000000gifsicle-1.78/include/lcdf/inttypes.h0000644000175000017500000000130612237442106014543 00000000000000#ifndef LCDF_INTTYPES_H #define LCDF_INTTYPES_H /* Define known-width integer types. */ #ifdef HAVE_INTTYPES_H # include #elif defined(HAVE_SYS_TYPES_H) # include # ifdef HAVE_U_INT_TYPES typedef u_int8_t uint8_t; typedef u_int16_t uint16_t; typedef u_int32_t uint32_t; # endif #elif defined(_WIN32) typedef __int8 int8_t; typedef unsigned __int8 uint8_t; typedef __int16 int16_t; typedef unsigned __int16 uint16_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; #endif #ifndef HAVE_UINTPTR_T # if SIZEOF_VOID_P == SIZEOF_UNSIGNED_LONG typedef unsigned long uintptr_t; # elif SIZEOF_VOID_P == SIZEOF_UNSIGNED_INT typedef unsigned int uintptr_t; # endif #endif #endif gifsicle-1.78/include/lcdf/clp.h0000644000175000017500000002541612241770404013452 00000000000000/* -*- related-file-name: "../../liblcdf/clp.c" -*- */ #ifndef LCDF_CLP_H #define LCDF_CLP_H #ifdef __cplusplus extern "C" { #endif /* clp.h - Public interface to CLP. * This file is part of CLP, the command line parser package. * * Copyright (c) 1997-2013 Eddie Kohler, ekohler@gmail.com * * CLP is free software. It is distributed under the GNU General Public * License, Version 2, or, alternatively and at your discretion, under the * more permissive (BSD-like) Click LICENSE file as described below. * * 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, subject to the * conditions listed in the Click LICENSE file, which is available in full at * http://github.com/kohler/click/blob/master/LICENSE. The conditions * include: you must preserve this copyright notice, and you cannot mention * the copyright holders in advertising related to the Software without * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS * OR IMPLIED. This notice is a summary of the Click LICENSE file; the * license in that file is binding. */ typedef struct Clp_Option Clp_Option; typedef struct Clp_Parser Clp_Parser; typedef struct Clp_ParserState Clp_ParserState; /** @brief Option description. * * CLP users declare arrays of Clp_Option structures to specify what options * should be parsed. * @sa Clp_NewParser, Clp_SetOptions */ struct Clp_Option { const char *long_name; /**< Name of long option, or NULL if the option has no long name. */ int short_name; /**< Character defining short option, or 0 if the option has no short name. */ int option_id; /**< User-specified ID defining option, returned by Clp_Next. */ int val_type; /**< ID of option's value type, or 0 if option takes no value. */ int flags; /**< Option parsing flags. */ }; /** @name Value types * These values describe the type of an option's argument and are used in * the Clp_Option val_type field. For example, if an option took integers, its * Clp_Option structure would have val_type set to Clp_ValInt. */ /**@{*/ #define Clp_NoVal 0 /**< @brief Option takes no value. */ #define Clp_ValString 1 /**< @brief Option value is an arbitrary string. */ #define Clp_ValStringNotOption 2 /**< @brief Option value is a non-option string. See Clp_DisallowOptions. */ #define Clp_ValBool 3 /**< @brief Option value is a boolean. Accepts "true", "false", "yes", "no", "1", and "0", or any prefixes thereof. The match is case-insensitive. */ #define Clp_ValInt 4 /**< @brief Option value is a signed int. Accepts an optional "+" or "-" sign, followed by one or more digits. The digits may be include a "0x" or "0X" prefix, for a hexadecimal number, or a "0" prefix, for an octal number; otherwise it is decimal. */ #define Clp_ValUnsigned 5 /**< @brief Option value is an unsigned int. Accepts an optional "+" sign, followed by one or more digits. The digits may be include a "0x" or "0X" prefix, for a hexadecimal number, or a "0" prefix, for an octal number; otherwise it is decimal. */ #define Clp_ValLong 6 /**< @brief Option value is a signed long. */ #define Clp_ValUnsignedLong 7 /**< @brief Option value is an unsigned long. */ #define Clp_ValDouble 8 /**< @brief Option value is a double. Accepts a real number as defined by strtod(). */ #define Clp_ValFirstUser 10 /**< @brief Value types >= Clp_ValFirstUser are available for user types. */ /**@}*/ /** @name Option flags * These flags are used in the Clp_Option flags field. */ /**@{*/ #define Clp_Mandatory (1<<0) /**< @brief Option flag: value is mandatory. It is an error if the option has no value. This is the default if an option has arg_type != 0 and the Clp_Optional flag is not provided. */ #define Clp_Optional (1<<1) /**< @brief Option flag: value is optional. */ #define Clp_Negate (1<<2) /**< @brief Option flag: option may be negated. --no-[long_name] will be accepted in argument lists. */ #define Clp_OnlyNegated (1<<3) /**< @brief Option flag: option must be negated. --no-[long_name] will be accepted in argument lists, but --[long_name] will not. This is the default if long_name begins with "no-". */ #define Clp_PreferredMatch (1<<4) /**< @brief Option flag: prefer this option when matching. Prefixes of --[long_name] should map to this option, even if other options begin with --[long_name]. */ /**@}*/ /** @name Option character types * These flags are used in to define character types in Clp_SetOptionChar(). */ /**@{*/ /* Clp_NotOption 0 */ #define Clp_Short (1<<0) /**< @brief Option character begins a set of short options. */ #define Clp_Long (1<<1) /**< @brief Option character begins a long option. */ #define Clp_ShortNegated (1<<2) /**< @brief Option character begins a set of negated short options. */ #define Clp_LongNegated (1<<3) /**< @brief Option character begins a negated long option. */ #define Clp_LongImplicit (1<<4) /**< @brief Option character can begin a long option, and is part of that long option. */ /**@}*/ #define Clp_NotOption 0 /**< @brief Clp_Next value: argument was not an option. */ #define Clp_Done -1 /**< @brief Clp_Next value: there are no more arguments. */ #define Clp_BadOption -2 /**< @brief Clp_Next value: argument was an erroneous option. */ #define Clp_Error -3 /**< @brief Clp_Next value: internal CLP error. */ #define Clp_ValSize 40 /**< @brief Minimum size of the Clp_Parser val.cs field. */ #define Clp_ValIntSize 10 /**< @brief Minimum size of the Clp_Parser val.is field. */ /** @brief A value parsing function. * @param clp the parser * @param vstr the value to be parsed * @param complain if nonzero, report error messages via Clp_OptionError * @param user_data user data passed to Clp_AddType() * @return 1 if parsing succeeded, 0 otherwise */ typedef int (*Clp_ValParseFunc)(Clp_Parser *clp, const char *vstr, int complain, void *user_data); /** @brief A function for reporting option errors. * @param clp the parser * @param message error message */ typedef void (*Clp_ErrorHandler)(Clp_Parser *clp, const char *message); /** @brief Command line parser. * * A Clp_Parser object defines an instance of CLP, including allowed options, * value types, and current arguments. * @sa Clp_NewParser, Clp_SetOptions, Clp_SetArguments */ struct Clp_Parser { const Clp_Option *option; /**< The last option. */ int negated; /**< Whether the last option was negated. */ int have_val; /**< Whether the last option had a value. */ const char *vstr; /**< The string value provided with the last option. */ union { int i; unsigned u; long l; unsigned long ul; double d; const char *s; void *pv; #ifdef HAVE_INT64_TYPES int64_t i64; uint64_t u64; #endif char cs[Clp_ValSize]; unsigned char ucs[Clp_ValSize]; int is[Clp_ValIntSize]; unsigned us[Clp_ValIntSize]; } val; /**< The parsed value provided with the last option. */ void *user_data; /**< Uninterpreted by CLP; users can set arbitrarily. */ struct Clp_Internal *internal; }; /** @cond never */ #if __GNUC__ >= 4 # define CLP_SENTINEL __attribute__((sentinel)) #else # define CLP_SENTINEL /* nothing */ #endif /** @endcond never */ /** @brief Create a new Clp_Parser. */ Clp_Parser *Clp_NewParser(int argc, const char * const *argv, int nopt, const Clp_Option *opt); /** @brief Destroy a Clp_Parser object. */ void Clp_DeleteParser(Clp_Parser *clp); /** @brief Return @a clp's program name. */ const char *Clp_ProgramName(Clp_Parser *clp); /** @brief Set @a clp's program name. */ const char *Clp_SetProgramName(Clp_Parser *clp, const char *name); /** @brief Set @a clp's error handler function. */ Clp_ErrorHandler Clp_SetErrorHandler(Clp_Parser *clp, Clp_ErrorHandler errh); /** @brief Set @a clp's UTF-8 mode. */ int Clp_SetUTF8(Clp_Parser *clp, int utf8); /** @brief Return @a clp's treatment of character @a c. */ int Clp_OptionChar(Clp_Parser *clp, int c); /** @brief Set @a clp's treatment of character @a c. */ int Clp_SetOptionChar(Clp_Parser *clp, int c, int type); /** @brief Set @a clp's option definitions. */ int Clp_SetOptions(Clp_Parser *clp, int nopt, const Clp_Option *opt); /** @brief Set @a clp's arguments. */ void Clp_SetArguments(Clp_Parser *clp, int argc, const char * const *argv); /** @brief Set whether @a clp is searching for options. */ int Clp_SetOptionProcessing(Clp_Parser *clp, int on); #define Clp_DisallowOptions (1<<0) /**< @brief Value type flag: value can't be an option string. See Clp_AddType(). */ /** @brief Define a new value type for @a clp. */ int Clp_AddType(Clp_Parser *clp, int val_type, int flags, Clp_ValParseFunc parser, void *user_data); #define Clp_AllowNumbers (1<<0) /**< @brief String list flag: allow explicit numbers. See Clp_AddStringListType() and Clp_AddStringListTypeVec(). */ #define Clp_StringListLong (1<<1) /**< @brief String list flag: values have long type. */ /** @brief Define a new string list value type for @a clp. */ int Clp_AddStringListTypeVec(Clp_Parser *clp, int val_type, int flags, int nstrs, const char * const *strs, const int *vals); /** @brief Define a new string list value type for @a clp. */ int Clp_AddStringListType(Clp_Parser *clp, int val_type, int flags, ...) CLP_SENTINEL; /** @brief Parse and return the next argument from @a clp. */ int Clp_Next(Clp_Parser *clp); /** @brief Return the next argument from @a clp without option parsing. */ const char *Clp_Shift(Clp_Parser *clp, int allow_options); /** @brief Create a new Clp_ParserState. */ Clp_ParserState *Clp_NewParserState(void); /** @brief Destroy a Clp_ParserState object. */ void Clp_DeleteParserState(Clp_ParserState *state); /** @brief Save @a clp's current state in @a state. */ void Clp_SaveParser(const Clp_Parser *clp, Clp_ParserState *state); /** @brief Restore parser state from @a state into @a clp. */ void Clp_RestoreParser(Clp_Parser *clp, const Clp_ParserState *state); /** @brief Report a parser error. */ int Clp_OptionError(Clp_Parser *clp, const char *format, ...); /** @brief Extract the current option as a string. */ int Clp_CurOptionNameBuf(Clp_Parser *clp, char *buf, int len); /** @brief Extract the current option as a string. */ const char *Clp_CurOptionName(Clp_Parser *clp); #undef CLP_SENTINEL #ifdef __cplusplus } #endif #endif gifsicle-1.78/logo.gif0000644000175000017500000002077712237442106011624 00000000000000GIF89a<„õÿœŒ{R{9ïµÖ­Z­Î­”ÿÎŒ¥{B÷{”÷B„J­BÆÎŒç¥µÖ÷œRk1cBÎBRJ)kœJÆs„”cR{µ9µÆBÿÖB÷ïÞçBJÆ„”­Þ­!­ZÖÎÖc΄{ÿRRÆŒ{”)Zkcµcsµcç½÷Z­Bç„RBÿÖZÿ)÷µÿÆÿŒ9ÿ9JÆB„”JµcÿÿRç)Zï1¥÷”­÷ÖÿJ!ÿ NETSCAPE2.0!ù2,<„ÿ@€pH,ȤrÉlˆD"E•"άVˆ z¿ßvK6 ¦àtx\&wÕð/¢½}Çï©9½iÇßõ{I}~wlO„‰)‡fЉ€ŒŽŠ‘\“‰ •—”Œ›ŒŸ˜‡ž¢„‡ƒ¦p‡ª§{¥­wh±p™{µw·m©¹^»e´¾`dÃpÅZ°Ç_†[ÂÌ)ÀÆÑat½ÇÓZÕÄtÜ_×ß^ÞâTäâÚNËÜÎYÐÕçâmëÕéMïÑÉNåæeôðÁø-*#ÐÞ’ÑÚÝØFàÀ-™T‚/A : È¿‰H°EyÄáÃmë˜$SÑâ“­|6eA•õQ¬™ÅäIÿ>&Iñ©3 Q--ö ªEdµ¢G’ºÜçS™O¡C¤2ƒjÄçOUÝ]µ™3KDvbÃReªÎ‹ pãÂU¡bW"o ÐC÷mÜZ1»:Š[×YEo èÝt—ˆ)¿…6¢ÕäD4kùŃuˆÓMGî–Ù×e08ÆI Á ¤X^ ®MÒÖ®sÃ&D[Úž¤¹ƒ»Ž‚—ÉLΨÁ-?Õ\v÷l~ãͺüënÞ¡y}W+VtUTzƒt‡ˆDUŽs‹NC’‚d›…{]˜•¡¢VŸ¥„§”h𫬠tˆ²¢•¯¶r†~w§¦³±w{¥œ¼vi·Æmz¹lȱŒÎ¾»À”—pØ“ºwÑÁº½j_Ç–²p¬çèäâ¶ÛîïjÓñ{éõ|líøÒÀ®aüÑÓ¦,`7ObŽ©¶ÚÀ<áFlõ°Ÿ*‰bˆ5['A€æ*ÂÒ7QZD|i4v<¯äJŽ ÿÅiU¯QÀÁdNÁ¹qÜLÿYØøTÓ£Ð:.—U ™L‹­h" %TT,((Ÿ;™QIr‹ª¨V»dá•©<¯FۈÒ'¬aQ‚LËsj?œ0íò4JԭDZNÝvDõóZÑ+}¡ù;ùQÊ/_­vüòR•r¥ŠqJEztO¡ÝxÙÝä(–ÛE»ÙbM3¬7‹-{Öi(0+WÕ™¤µbÕ ëº8;³¸²m„sþí;p­›c[ÜÆÔaM›»3 &‹Á0«8â ‘ÓøÑ+ãåRf\ÂòÞÜç“_áÛïøô§Ýò#Þ€ØÐ} ¥œ ¬l(HR^1ᆃÔ'BÄ"÷q…ÚÕÁÞt[ ЕÕ­€_SÂÈ"#à%˜D2q&z±qxˆdb"ù bFêç]’¨Édë !ù ,:dÿ` Ždižè0p,» *ÏôÉ´xÎ-uï‹7ÕÙÄ~ÈÒj(ì8;Ç$rÉÔ=;œ¨´¬Z¯ÙmméôâÀ,­¸D[¿ØÖÚÖrç®øÜ`^:Ûýxq8|$€‚LOCjbpff„eŽ^‹I’‡”w"„Øsö-S:)µ œvKÈ?±&\—˜1zã’Dœ'IÁÕ&ÿzóôc_t;H1¹*ÑLš}!qi &É8MU<–hJ¡%sb¹È©¦t`‚NK¦Q"‹‚CSnÛI±QŸBXö (L©*¦…T~ÙÚÒ+N…GÕÒ4:¶ë[Ž>ºTUUÉÝ—ýþµ›C, ž÷þ á-&¼£TnÁ –æ×(r÷¤Š;±ÊQ=SŠí̇ñ²D[Ý›² —ž U¿Z—áqá9¤‚^-TòNHX_3ÔìKØ_Ù°>½‚pŠ7O{uûöMzø·Í{'LW…ù‰’Ãb41Xžu2Œd’÷ñG! ʱe`?‹‰`¡ ”˜€Š ‹RáE‚e¡À°,ôX ¨àLŒm8F(ÁÚ9Ñ`¿ À ÉÉk0P•¥FÈNtçp| @C”„If 8&@ŽœÙ¢‹jªS›Ì#¦ !!ù ,:dÿÀ€pH,GÆbj:ȨtŠ8¯ØÐ„Aíz…ØOèC.79 Ðw}\8Åå¸9°ïî±|OÑAvw^VM|‡ !‚ƒRL~Š|oeNSM’Šzšb!—HN•|‰‰pZ¢E†t›§ qM«C…d¥‡™ifµCŸ‡³’¡« ±iÃr“³¿ÉË{†}tÇWt½Ñ{§¢³ÙÚs‰¢Ófåᔯ´ ç}®î³šëƒÞñòž•õwúâ§tñ3vç¾WÔÀáÂÖo …Ô¾È)”A M ÓÖŠ Fe°x¡3ÇÅß?sløeÚ?H‡Y“YM™¿pÉÓ #ÿ‡7ý̹¦',…D½ü[¹qM8FFú¦Æd±‘¨¾ÑD*RÚ9•¾¬2kš0˜DswÚ…œ*'H­lþeKÒO¥'¿bù×ëV1;¾†”%•Ine u7sM9Ws|j³oÔqqk.%üç/Πy%ÅtóqFŠ¢3ó̧0‘EÕè “˜f+è}oQ"–9^LÈß(–"[tèÁ„w€¦îÚÛ}&8¦û8t1w6¾ìºxt”ÈÉy*?Üœ{ÔeM¤·„|]Ò’ËI±=x>(Çz6Çn:|”~ñ*'…AèAÙ"ëqdž9½ä" q¥Í†’Yƒõg ZGbpuñÿnÈÑž*JÓ †•-ØÄ]RØX9³Ib“wF,(˜sc!È„X_@+ÁÃA^ H•X¥ßgxž+:ùhâeµE)<§…´d‹ímxŠ>áõ$4!áõá6U‡fU‡5ã›LÚAäÇ–QèåZk1zEç:’) X8‰™Nn.ÞÔƒ|Šá Á¨lW¨WêMñˆþÁ˜2ª€…ÅžF8ሽ„ài¤OÒH„;€’!A£œž•b’ÊI6º´è§rrçê«à|ØÄ¬ Ø*Õ; vWŒ äWÊŽDøÙ^Ñz**®w( ,Ñ (cüZÞIl´³p™ ´;Àä–…]ÍÝg’>,0¼ÓœÂh JÅ#:&€òã RKZT@Šh‘:Ü& +11äþ€ €@$i& ìñüfòÉ.•ËÞ ³™&’:såç„Í7ÑcÆW°¸F!ù2,:dÿÀ€pH,H‘ˆåjºX"¤tJM:¯XW´Êí ³àfìõòš¢p˜ü‚mÏæ´:;†ÙcoxU>϶í/Zz{.ca11WvwM ƒRrl‡XcŠN10dWHb0—X“uš¢‚DW ”W†Œš­M©C|.°§tlLY,´§™›}Ä¿l¥/¹Ä`yz¯ŒÃË`†1©˜dÊÒŸ°¶ÚjÈcßËd¡NãËÔs™Œèƒ¼ì ¦kÐïzÄám²˜Ðоz¼1w*Ù6MÂ9–«9Øš4ó(› VäœLìbŽŸ]Àsbp ƒª‰ˆN‹šaSÚÆ*kªdñ›!ÿpøt’PpÖ¾¨ŒáÉ&žir]Cw…½Hî“”Þ@{7¥Ó§ ‘¿G^8#¸Ê⤴U®¥ãDƒ†Kï&Ù–\Ö9Û™Ö–úÈÅ6mo•vF9 •cõ"â)æíj•ÿÞÜH“IßÁsáÃRçOõUF;þ·Kú»u±àŽtÿbq‰^(×\‹ä–}åз—+}aÁ:c™„Y¹ìç‰4Þq…Xå!ÿ_"6^vÑ‚G–08à7)5Ô„ƒÕd¡29Ð$¦S\(ÖxÚÔ!@ öG™QDù9I9îËgåGÉÓÓ»Õﺋ„H|ìí_‰•OšM©Ô¶Ððú^}v"ÞojëÓåû!ß)E·µ{ó.øD%_[ìýW…-Þ #W˜Q¡Y òQW÷ üXÆWq‡xRÿá/Ѳš$²”DšR“—*Ö˜¦–!ÎèW|›ÈƒF!ŠÍ‘B R#Ç€$ÊæR_¬ÈZ‹½ ©¢ YœŽµTsEN^öÓFEˆ=­ÉÕ–ÖZ¾TåŽSV‘!F¼ “4]4ðÍÙXg œUœÃUÜ$fžmfYS™ç #ÚärõüòáQЗƒÙc§^LÀÕäØ «ŽP§H8dP'ÏÂ{n71 $ä~…JO„ä .¹èrÎB'FSÆ7Vʱ§Â~œåHPˆ“LÞ!ù ,:dÿÀpH,Èmɤ%ŸÐ¨±I¥J¯Øªviêb¿Èí¶{2ÏB±–|*£¿êq»ì|C¹]qž9§×ía4lk{\m&M€GxsˆU&‡l…ŠiL‡„}eމ•–K}š£V•£˜¥q[Ÿ]©ª«U§˜±M·†'Š—¯«±lnv²ZÁÊŒœfÆÇ‚&ËÉÖŽ©L€Ç]ÌÖɵ'Ûo²Äßá¸åh«’]àÍ—¶KÑjÚ‚òT‘í`r ê³$˜}©ü¢&ß#v&„áŠó¦™[µ^ ÔbÎ×Ò<™¨gRÈŽ!SþÃbR¥¬7ˆZº“F°™ÓrAÃ$ÎÿAv~9QMØÂn9¢Iw-eÒY##ÊÓX²‰(¥<õ%KTá$‡¦²~;HlX$X¬¢Jœ÷Ô+µ ¡fu5-;1eÚ‰U&5éhf¥÷,î#y ±fÁ5ŽSœ±O¸#¤÷°O_‡øâÄÕtZ$Í›¹(Û“´4°ÅdE%±¿‚Öe2ýÝ5¶hÇA}Ëß`°‘Û“‡çk?Á7¦ei¹Âz)áÜÅóÑqô/ã†SVÙpzh5p2Þº:«aΣƒ)W,ÅW)oû°¿çñ>‰%…ËmLÞî¶{-¶ÊT»yÇÚÇœ€˜WVݵÌI“ 'óô%['ÍÔgß3±](ÿ 6o$ànØÀÆØ&ðCÀˆ òa WÈ¥#À”_ÎIó K9êòÊyÇ0³¢õè™(ëfÁ \œ[Ij±ŒNùŒBAqÔ•rHv…@vcbd&4pÖD‰ÙU¸•af¤éZse&:e¢^Â]¡Î…ø¬Æ>CFQbÇ©â‹àñGU¨‡Ö1WÉS©Yé<àé§ž*ˆU¶ß4<À@‡ˆÚé§\@v]kÏ÷ÀªÚ´wüõc]`ÀRºéq0€¨™Ä¢Sü¼º*Œ6.ñ&­H)ÔD<°&rÖ¶ÑÝ®úÔ`jÒcÆ’Ã òê¹èn±$ÞÕiàêfÕÓÙf³+=‹KDeÓØ¿Ç[‰õUÊ'† âÀÄW/̨™‚¸ lÜ€mé8QåÀzÞÂŒùræ‰6oÖÌ™e'Oÿ™<#j ª“ K/)McÉœ¡¥]:Á#)PÊQ+ëªf•1‹bÜØ¢ZµÀ±Â2á$ Y/¦Ö"ÕÚ5Ó%°Uä¼³J.LR+‰úúäsæ' …ë¹½Xq¬Æ6!ÃÄKƒ`+[ ÎÌ.¨ tgRÒÙ³ºÐH÷n¼HPØ-A\k•V4ÅI€"èî‚ö×Ý5ñ¤º¨Ù­~‚GÐm>n­Í(@… Š7‘L†›nÉió3vN¸Kêò¬6Z—`¹7á7ï>ä@¹··ƒ^/Ä~@2ÀõdÆUÛ!a_ñ9¢ßÅÒÑ "Œ±„P„áªmèM¢w^ˆÇUDb†%Á!ù ,:dÿ  Ždiž(AG{**Ï4êÞøKÔ|/¹ nç+–€Âd‹h,"•ʦJ=0¥²gUyÅ– Û­÷¤ sÇ%s=*«“¶à½F»éB6~ïÅ^wU€XxˆˆP~j‰ŠT^,oŽU^‡‰T}Rt„PšF’f–…M¦§E¢©Q›­M‚°. >´P]=¸®F³¼¯¼y¨-žÂ-¶<@”Ƹº5’”ÇÁ˜ÇÔ͸ÉÐÖ9Á¦ÚA²°âß¡­ÒÃE´BÜ3¿æ.Ï3¬á‹F¸ô.ÄÞ8мaOÆÀ€Súc§pá­†-6,xbD†÷Y\e‘¢ 3ýê<¤î G*ŽBÕV‰Òxd”4ÉŠ"—4wmQ)²†<~/j$„qh"øÕÙp)‹Å˜n”š‘ªB˜%x ó8B+°8‚õJ +‰°¹þ€ºä)ÛkníQæ"@îæ­PAÈÌ*j‘ð ·p_ÕÔX…r·B€bdo,¦bo:jçü¡&s«ÂWòHº§q¬É¥ó†Î‘YéTyÇi<†ïê‹“T¬â¸–_3¨¶hAURV Ž<¤|äüÓ']¨ÖÕ5ŸÎ·÷îAÌ~ß}ÎK!ù ,:dÿà ŽdižèD,›¾p|¶tÉx>Ø|­ÿ¦ž°,·b‰TÆV̦3NgU&àJÊV¹#ï—+_ËÖsYÃ$‹5ì¶ê…ÛáÂiöÎ÷ôU}vG€}RFo|ˆ?Š‹CNkx”yJYJk^˜hž‰ f?£š@¦¤:-~©<Ÿ–®6¢±²4E‚µ©J¹­®‰‚¶D¨•w·ÄÇI¥ÅÎ{¾<É~ÑGƒ‘Ħʳڠ‡ÍÛÆ—«®ä¯â©ÜÈæçè>êã„î²ÖÃõËÝùúí8ýåþL·d`- ú“¡0G ñ1Œ¢KŒ<…E ðÑ¢prp4h”¥BJGF˜#ŽÏeUáQÅ¡u«ŒŠ^aä”úlGPÍöPK/Æ·®Œ^Ѐ@·nÝž*ÛºBºè²0©ŠJ–»ÅØ„BàÄYî%8ÔD4”*Ëqúf®æ€“e9Þ.è`6pk|–ÈY¦yUï3ýºDê~æ ³ØöÕ¹mŠr˜â7kIºMw&Lm¹››sM#½uÉÕCgË~y;wí½¿ƒgî$;gifsicle-1.78/src/0000755000175000017500000000000012251251541011024 500000000000000gifsicle-1.78/src/gifdiff.c0000644000175000017500000004046712244134664012531 00000000000000/* gifdiff.c - Gifdiff compares GIF images for identical appearance. Copyright (C) 1998-2013 Eddie Kohler, ekohler@gmail.com This file is part of gifdiff, in the gifsicle package. Gifdiff is free software. It is distributed under the GNU Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #include #include #include #include #include #include #include /* Need _setmode under MS-DOS, to set stdin/stdout to binary mode */ /* Need _fsetmode under OS/2 for the same reason */ #if defined(_MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(__DJGPP__) # include # include #endif #define QUIET_OPT 300 #define HELP_OPT 301 #define VERSION_OPT 302 #define IGNORE_REDUNDANCY_OPT 303 const Clp_Option options[] = { { "help", 'h', HELP_OPT, 0, 0 }, { "brief", 'q', QUIET_OPT, 0, Clp_Negate }, { "ignore-redundancy", 'w', IGNORE_REDUNDANCY_OPT, 0, Clp_Negate }, { "version", 'v', VERSION_OPT, 0, 0 } }; static const char *program_name; static const char *filename1; static const char *filename2; static int screen_width, screen_height; #define TRANSP (0) static uint16_t *gdata[2]; static uint16_t *glast[2]; static uint16_t *scratch; static uint16_t *line; static int brief; static int ignore_redundancy; static void combine_colormaps(Gif_Colormap *gfcm, Gif_Colormap *newcm) { int i; if (!gfcm) return; for (i = 0; i < gfcm->ncol; i++) { Gif_Color *c = &gfcm->col[i]; c->pixel = Gif_AddColor(newcm, c, 1); } } static void fill_area(uint16_t *data, int l, int t, int w, int h, uint16_t val) { int x; data += screen_width * t + l; for (; h > 0; --h) { for (x = w; x > 0; --x) *data++ = val; data += screen_width - w; } } static void copy_area(uint16_t *dst, const uint16_t *src, int l, int t, int w, int h) { dst += screen_width * t + l; src += screen_width * t + l; for (; h > 0; --h, dst += screen_width, src += screen_width) memcpy(dst, src, sizeof(uint16_t) * w); } static void expand_bounds(int *lf, int *tp, int *rt, int *bt, const Gif_Image *gfi) { int empty = (*lf >= *rt || *tp >= *bt); if (empty || gfi->left < *lf) *lf = gfi->left; if (empty || gfi->top < *tp) *tp = gfi->top; if (empty || gfi->left + gfi->width > *rt) *rt = gfi->left + gfi->width; if (empty || gfi->top + gfi->height > *bt) *bt = gfi->top + gfi->height; } static int apply_image(int is_second, Gif_Stream *gfs, int imageno, uint16_t background) { int i, x, y, any_change; Gif_Image *gfi = gfs->images[imageno]; Gif_Image *pgfi = imageno ? gfs->images[imageno - 1] : 0; int width = gfi->width; uint16_t map[256]; uint16_t *data = gdata[is_second]; uint16_t *last = glast[is_second]; Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global; /* set up colormap */ for (i = 0; i < 256; i++) map[i] = 1; if (gfs) for (i = 0; i < gfcm->ncol; i++) map[i] = gfcm->col[i].pixel; if (gfi->transparent >= 0 && gfi->transparent < 256) map[gfi->transparent] = TRANSP; /* if this image's disposal is 'previous', save the post-disposal version in 'scratch' */ if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) { copy_area(scratch, data, gfi->left, gfi->top, gfi->width, gfi->height); if (pgfi && pgfi->disposal == GIF_DISPOSAL_PREVIOUS) copy_area(scratch, last, pgfi->left, pgfi->top, pgfi->width, pgfi->height); else if (pgfi && pgfi->disposal == GIF_DISPOSAL_BACKGROUND) fill_area(scratch, pgfi->left, pgfi->top, pgfi->width, pgfi->height, background); } /* uncompress and clip */ Gif_UncompressImage(gfi); Gif_ClipImage(gfi, 0, 0, screen_width, screen_height); any_change = imageno == 0; { int lf = 0, tp = 0, rt = 0, bt = 0; expand_bounds(&lf, &tp, &rt, &bt, gfi); if (pgfi && pgfi->disposal == GIF_DISPOSAL_PREVIOUS) expand_bounds(&lf, &tp, &rt, &bt, pgfi); else if (pgfi && pgfi->disposal == GIF_DISPOSAL_BACKGROUND) { expand_bounds(&lf, &tp, &rt, &bt, pgfi); fill_area(last, pgfi->left, pgfi->top, pgfi->width, pgfi->height, background); } else pgfi = 0; for (y = tp; y < bt; ++y) { uint16_t *outd = data + screen_width * y + lf; if (!any_change) memcpy(line, outd, (rt - lf) * sizeof(uint16_t)); if (pgfi && y >= pgfi->top && y < pgfi->top + pgfi->height) memcpy(outd + pgfi->left - lf, last + screen_width * y + pgfi->left, pgfi->width * sizeof(uint16_t)); if (y >= gfi->top && y < gfi->top + gfi->height) { uint16_t *xoutd = outd + gfi->left - lf; const uint8_t *ind = gfi->img[y - gfi->top]; for (x = 0; x < width; ++x, ++ind, ++xoutd) if (map[*ind] != TRANSP) *xoutd = map[*ind]; } if (!any_change && memcmp(line, outd, (rt - lf) * sizeof(uint16_t)) != 0) any_change = 1; } } Gif_ReleaseUncompressedImage(gfi); Gif_ReleaseCompressedImage(gfi); /* switch 'glast' with 'scratch' if necessary */ if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) { uint16_t *x = scratch; scratch = glast[is_second]; glast[is_second] = x; } return any_change; } #define SAME 0 #define DIFFERENT 1 static int was_different; static void different(const char *format, ...) { va_list val; va_start(val, format); if (!brief) { vfprintf(stderr, format, val); fputc('\n', stderr); } va_end(val); was_different = 1; } static void name_loopcount(int loopcount, char *buf) { if (loopcount < 0) strcpy(buf, "none"); else if (loopcount == 0) strcpy(buf, "forever"); else sprintf(buf, "%d", loopcount); } static void name_delay(int delay, char *buf) { if (delay == 0) strcpy(buf, "none"); else sprintf(buf, "%d.%02ds", delay / 100, delay % 100); } static void name_color(int color, Gif_Colormap *gfcm, char *buf) { if (color == TRANSP) strcpy(buf, "transparent"); else { Gif_Color *c = &gfcm->col[color]; sprintf(buf, "#%02X%02X%02X", c->gfc_red, c->gfc_green, c->gfc_blue); } } int compare(Gif_Stream *s1, Gif_Stream *s2) { Gif_Colormap *newcm; int imageno1, imageno2, background1, background2; char buf1[256], buf2[256], fbuf[256]; was_different = 0; /* Compare image counts and screen sizes. If either of these differs, quit early. */ Gif_CalculateScreenSize(s1, 0); Gif_CalculateScreenSize(s2, 0); if (s1->nimages != s2->nimages && (s1->nimages == 0 || s2->nimages == 0)) { different("frame counts differ: <#%d >#%d", s1->nimages, s2->nimages); return DIFFERENT; } if (s1->screen_width != s2->screen_width || s1->screen_height != s2->screen_height) { different("screen sizes differ: <%dx%d >%dx%d", s1->screen_width, s1->screen_height, s2->screen_width, s2->screen_height); return DIFFERENT; } /* Create arrays for the image data */ screen_width = s1->screen_width; screen_height = s1->screen_height; gdata[0] = Gif_NewArray(uint16_t, screen_width * screen_height); gdata[1] = Gif_NewArray(uint16_t, screen_width * screen_height); glast[0] = Gif_NewArray(uint16_t, screen_width * screen_height); glast[1] = Gif_NewArray(uint16_t, screen_width * screen_height); scratch = Gif_NewArray(uint16_t, screen_width * screen_height); line = Gif_NewArray(uint16_t, screen_width); /* Merge all distinct colors from the two images into one colormap, setting the 'pixel' slots in the images' colormaps to the corresponding values in the merged colormap. Don't forget transparency */ newcm = Gif_NewFullColormap(1, 256); combine_colormaps(s1->global, newcm); combine_colormaps(s2->global, newcm); for (imageno1 = 0; imageno1 < s1->nimages; ++imageno1) combine_colormaps(s1->images[imageno1]->local, newcm); for (imageno2 = 0; imageno2 < s2->nimages; ++imageno2) combine_colormaps(s2->images[imageno2]->local, newcm); /* Choose the background values and clear the image data arrays */ if (s1->images[0]->transparent >= 0 || !s1->global) background1 = TRANSP; else background1 = s1->global->col[ s1->background ].pixel; if (s2->images[0]->transparent >= 0 || !s2->global) background2 = TRANSP; else background2 = s2->global->col[ s2->background ].pixel; fill_area(gdata[0], 0, 0, screen_width, screen_height, background1); fill_area(gdata[1], 0, 0, screen_width, screen_height, background2); /* Loopcounts differ? */ if (s1->loopcount != s2->loopcount) { name_loopcount(s1->loopcount, buf1); name_loopcount(s2->loopcount, buf2); different("loop counts differ: <%s >%s", buf1, buf2); } /* Loop over frames, comparing image data and delays */ apply_image(0, s1, 0, background1); apply_image(1, s2, 0, background2); imageno1 = imageno2 = 0; while (imageno1 != s1->nimages && imageno2 != s2->nimages) { int fi1 = imageno1, fi2 = imageno2, delay1 = s1->images[fi1]->delay, delay2 = s2->images[fi2]->delay; /* get message right */ if (imageno1 == imageno2) sprintf(fbuf, "#%d", imageno1); else sprintf(fbuf, "<#%d >#%d", imageno1, imageno2); /* compare pixels */ if (memcmp(gdata[0], gdata[1], screen_width * screen_height * sizeof(uint16_t)) != 0) { int d, c = screen_width * screen_height; uint16_t *d1 = gdata[0], *d2 = gdata[1]; for (d = 0; d < c; d++, d1++, d2++) if (*d1 != *d2) { name_color(*d1, newcm, buf1); name_color(*d2, newcm, buf2); different("frame %s pixels differ: %d,%d <%s >%s", fbuf, d % screen_width, d / screen_width, buf1, buf2); break; } } /* move to next images, skipping redundancy */ for (++imageno1; imageno1 < s1->nimages && !apply_image(0, s1, imageno1, background1); ++imageno1) delay1 += s1->images[imageno1]->delay; for (++imageno2; imageno2 < s2->nimages && !apply_image(1, s2, imageno2, background2); ++imageno2) delay2 += s2->images[imageno2]->delay; if (!ignore_redundancy) { fi1 = (imageno1 - fi1) - (imageno2 - fi2); for (; fi1 > 0; --fi1) different("extra redundant frame: <#%d", imageno1 - fi1); for (; fi1 < 0; ++fi1) different("extra redundant frame: >#%d", imageno2 + fi1); } if (delay1 != delay2) { name_delay(delay1, buf1); name_delay(delay2, buf2); different("frame %s delays differ: <%s >%s", fbuf, buf1, buf2); } } if (imageno1 != s1->nimages || imageno2 != s2->nimages) different("frame counts differ: <#%d >#%d", s1->nimages, s2->nimages); /* That's it! */ Gif_DeleteColormap(newcm); Gif_DeleteArray(gdata[0]); Gif_DeleteArray(gdata[1]); Gif_DeleteArray(glast[0]); Gif_DeleteArray(glast[1]); Gif_DeleteArray(scratch); Gif_DeleteArray(line); return was_different ? DIFFERENT : SAME; } void short_usage(void) { fprintf(stderr, "Usage: %s [OPTION]... FILE1 FILE2\n\ Try '%s --help' for more information.\n", program_name, program_name); } void usage(void) { printf("\ 'Gifdiff' compares two GIF files (either images or animations) for identical\n\ visual appearance. An animation and an optimized version of the same animation\n\ should compare as the same. Gifdiff exits with status 0 if the images are\n\ the same, 1 if they're different, and 2 if there was some error.\n\ \n\ Usage: %s [OPTION]... FILE1 FILE2\n\n", program_name); printf("\ Options:\n\ -q, --brief Don't report detailed differences.\n\ -w, --ignore-redundancy Ignore differences in redundant frames.\n\ -h, --help Print this message and exit.\n\ -v, --version Print version number and exit.\n\ \n\ Report bugs to .\n"); } void fatal_error(char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); fputc('\n', stderr); exit(2); /* exit(2) for trouble */ } void error(char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); fputc('\n', stderr); } void warning(char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: warning: ", program_name); vfprintf(stderr, message, val); fputc('\n', stderr); } static int gifread_error_count; static void gifread_error(int is_error, const char *message, int which_image, void *thunk) { static int last_is_error = 0; static int last_which_image = 0; static char last_message[256]; static int different_error_count = 0; static int same_error_count = 0; const char *filename = (const char *)thunk; if (gifread_error_count == 0) { last_which_image = -1; last_message[0] = 0; different_error_count = 0; } gifread_error_count++; if (last_message[0] && different_error_count <= 10 && (last_which_image != which_image || message == 0 || strcmp(message, last_message) != 0)) { const char *etype = last_is_error ? "error" : "warning"; error("While reading '%s' frame #%d:", filename, last_which_image); if (same_error_count == 1) error(" %s: %s", etype, last_message); else if (same_error_count > 0) error(" %s: %s (%d times)", etype, last_message, same_error_count); same_error_count = 0; last_message[0] = 0; } if (message) { if (last_message[0] == 0) different_error_count++; same_error_count++; strcpy(last_message, message); last_which_image = which_image; last_is_error = is_error; } else last_message[0] = 0; if (different_error_count == 11 && message) { error("(more errors while reading '%s')", filename); different_error_count++; } } static Gif_Stream * read_stream(const char **filename) { FILE *f; Gif_Stream *gfs; if (*filename == 0) { #if 0 /* Since gifdiff always takes explicit filename arguments, allow explicit reads from terminal. */ #ifndef OUTPUT_GIF_TO_TERMINAL extern int isatty(int); if (isatty(fileno(stdin))) { fatal_error(": is a terminal"); return NULL; } #endif #endif f = stdin; #if defined(_MSDOS) || defined(_WIN32) _setmode(_fileno(stdin), _O_BINARY); #elif defined(__DJGPP__) setmode(fileno(stdin), O_BINARY); #elif defined(__EMX__) _fsetmode(stdin, "b"); #endif *filename = ""; } else { f = fopen(*filename, "rb"); if (!f) fatal_error("%s: %s", *filename, strerror(errno)); } gifread_error_count = 0; gfs = Gif_FullReadFile(f, GIF_READ_COMPRESSED, gifread_error, (void *) *filename); gifread_error(-1, 0, -1, (void *) *filename); /* print out last error message */ if (!gfs) fatal_error("'%s' doesn't seem to contain a GIF", *filename); return gfs; } int main(int argc, char *argv[]) { int how_many_inputs = 0; int status; const char **inputp; Gif_Stream *gfs1, *gfs2; Clp_Parser *clp = Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); program_name = Clp_ProgramName(clp); brief = 0; while (1) { int opt = Clp_Next(clp); switch (opt) { case HELP_OPT: usage(); exit(0); break; case VERSION_OPT: printf("gifdiff (LCDF Gifsicle) %s\n", VERSION); printf("Copyright (C) 1998-2013 Eddie Kohler\n\ This is free software; see the source for copying conditions.\n\ There is NO warranty, not even for merchantability or fitness for a\n\ particular purpose.\n"); exit(0); break; case QUIET_OPT: brief = !clp->negated; break; case IGNORE_REDUNDANCY_OPT: ignore_redundancy = !clp->negated; break; case Clp_NotOption: if (how_many_inputs == 2) { error("too many file arguments"); goto bad_option; } inputp = (how_many_inputs == 0 ? &filename1 : &filename2); how_many_inputs++; if (strcmp(clp->vstr, "-") == 0) *inputp = 0; else *inputp = clp->vstr; break; bad_option: case Clp_BadOption: short_usage(); exit(1); break; case Clp_Done: goto done; } } done: if (how_many_inputs < 2) fatal_error("need exactly 2 file arguments"); if (filename1 == 0 && filename2 == 0) fatal_error("can't read both files from stdin"); gfs1 = read_stream(&filename1); gfs2 = read_stream(&filename2); status = (compare(gfs1, gfs2) == DIFFERENT); if (status == 1 && brief) printf("GIF files %s and %s differ\n", filename1, filename2); Gif_DeleteStream(gfs1); Gif_DeleteStream(gfs2); #ifdef DMALLOC dmalloc_report(); #endif return status; } gifsicle-1.78/src/gifsicle.h0000644000175000017500000001722512251246352012715 00000000000000/* gifsicle.h - Function declarations for gifsicle. Copyright (C) 1997-2011 Eddie Kohler, ekohler@gmail.com This file is part of gifsicle. Gifsicle is free software. It is distributed under the GNU Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #include #include #ifdef __GNUC__ #define NORETURN __attribute__ ((noreturn)) #define USED_ATTR __attribute__ ((used)) #else #define NORETURN #define USED_ATTR #endif typedef struct Gt_Frameset Gt_Frameset; typedef struct Gt_Crop Gt_Crop; typedef struct Gt_ColorTransform Gt_ColorTransform; typedef struct Gt_Frame { Gif_Stream *stream; Gif_Image *image; int use; const char *name; int no_name; Gif_Comment *comment; int no_comments; Gif_Color transparent; /* also background */ int interlacing; int left; int top; Gt_Crop *crop; int delay; int disposal; Gt_Frameset *nest; int explode_by_name; int no_extensions; Gif_Extension *extensions; unsigned flip_horizontal: 1; unsigned flip_vertical: 1; unsigned info_flags: 3; unsigned position_is_offset: 1; unsigned total_crop: 1; unsigned rotation; const char *input_filename; } Gt_Frame; struct Gt_Frameset { int count; int cap; Gt_Frame *f; }; struct Gt_Crop { int ready; int transparent_edges; int spec_x; int spec_y; int spec_w; int spec_h; int x; int y; int w; int h; int left_offset; int top_offset; }; typedef void (*colormap_transform_func)(Gif_Colormap *, void *); struct Gt_ColorTransform { Gt_ColorTransform *prev; Gt_ColorTransform *next; colormap_transform_func func; void *data; }; typedef struct { const char *output_name; const char *active_output_name; int screen_width; int screen_height; Gif_Color background; int loopcount; int colormap_size; Gif_Colormap *colormap_fixed; int colormap_algorithm; int dither_type; const uint8_t* dither_data; const char* dither_name; int colormap_gamma_type; double colormap_gamma; int optimizing; int scaling; int resize_width; int resize_height; double scale_x; double scale_y; int conserve_memory; } Gt_OutputData; extern Gt_OutputData active_output_data; #define GT_SCALING_NONE 0 #define GT_SCALING_RESIZE 1 #define GT_SCALING_SCALE 2 #define GT_SCALING_RESIZE_FIT 3 #define GT_OPT_MASK 0xFFFF #define GT_OPT_KEEPEMPTY 0x10000 /***** * helper **/ static inline int constrain(int low, int x, int high) { return x < low ? low : (x < high ? x : high); } /***** * error & verbose **/ extern const char *program_name; extern int verbosing; extern int error_count; extern int no_warnings; extern Gif_CompressInfo gif_write_info; void fatal_error(const char *message, ...) NORETURN; void warning(int need_file, const char *message, ...); void warncontext(int need_file, const char *message, ...); void error(int need_file, const char *message, ...); void clp_error_handler(Clp_Parser *clp, const char *clp_message); void usage(void); void short_usage(void); void verbose_open(char, const char *); void verbose_close(char); void verbose_endline(void); const char* debug_color_str(const Gif_Color* gfc); #define EXIT_OK 0 #define EXIT_ERR 1 #define EXIT_USER_ERR 1 /***** * info &c **/ #define INFO_COLORMAPS 1 #define INFO_EXTENSIONS 2 #define INFO_SIZES 4 void stream_info(FILE *f, Gif_Stream *gfs, const char *filename, int flags); void image_info(FILE *f, Gif_Stream *gfs, Gif_Image *gfi, int flags); char *explode_filename(const char *filename, int number, const char *name, int max_nimg); /***** * merging images **/ void unmark_colors(Gif_Colormap *); void unmark_colors_2(Gif_Colormap *); void mark_used_colors(Gif_Stream *gfs, Gif_Image *gfi, Gt_Crop *crop, int compress_immediately); int find_color_index(Gif_Color *c, int nc, Gif_Color *); int merge_colormap_if_possible(Gif_Colormap *, Gif_Colormap *); extern int warn_local_colormaps; void merge_stream(Gif_Stream *dest, Gif_Stream *src, int no_comments); void merge_comments(Gif_Comment *destc, Gif_Comment *srcc); Gif_Image *merge_image(Gif_Stream *dest, Gif_Stream *src, Gif_Image *srci, int same_compressed_ok); void optimize_fragments(Gif_Stream *, int optimizeness, int huge_stream); /***** * image/colormap transformations **/ Gif_Colormap *read_colormap_file(const char *, FILE *); void apply_color_transforms(Gt_ColorTransform *, Gif_Stream *); typedef void (*color_transform_func)(Gif_Colormap *, void *); Gt_ColorTransform *append_color_transform (Gt_ColorTransform *list, color_transform_func, void *); Gt_ColorTransform *delete_color_transforms (Gt_ColorTransform *list, color_transform_func); void color_change_transformer(Gif_Colormap *, void *); Gt_ColorTransform *append_color_change (Gt_ColorTransform *list, Gif_Color, Gif_Color); void pipe_color_transformer(Gif_Colormap *, void *); void combine_crop(Gt_Crop *dstcrop, const Gt_Crop *srccrop, const Gif_Image *gfi); int crop_image(Gif_Image *, Gt_Crop *, int preserve_total_crop); void flip_image(Gif_Image *, int scr_width, int scr_height, int is_vert); void rotate_image(Gif_Image *, int scr_width, int scr_height, int rotation); void resize_stream(Gif_Stream *, double new_width, double new_height, int fit); /***** * quantization **/ Gif_Color *histogram(Gif_Stream *, int *); #define KC_GAMMA_SRGB 0 #define KC_GAMMA_NUMERIC 1 void kc_set_gamma(int type, double gamma); #define COLORMAP_DIVERSITY 0 #define COLORMAP_BLEND_DIVERSITY 1 #define COLORMAP_MEDIAN_CUT 2 Gif_Colormap* colormap_blend_diversity(Gif_Color*, int, Gt_OutputData*); Gif_Colormap* colormap_flat_diversity(Gif_Color*, int, Gt_OutputData*); Gif_Colormap* colormap_median_cut(Gif_Color*, int, Gt_OutputData*); typedef struct kd3_tree kd3_tree; enum { dither_none = 0, dither_default, dither_floyd_steinberg, dither_ordered, dither_ordered_new }; int set_dither_type(Gt_OutputData* od, const char* name); void colormap_stream(Gif_Stream*, Gif_Colormap*, Gt_OutputData*); /***** * parsing stuff **/ extern int frame_spec_1; extern int frame_spec_2; extern char * frame_spec_name; extern int dimensions_x; extern int dimensions_y; extern int position_x; extern int position_y; extern Gif_Color parsed_color; extern Gif_Color parsed_color2; extern double parsed_scale_factor_x; extern double parsed_scale_factor_y; int parse_frame_spec(Clp_Parser *, const char *, int, void *); int parse_dimensions(Clp_Parser *, const char *, int, void *); int parse_position(Clp_Parser *, const char *, int, void *); int parse_scale_factor(Clp_Parser *, const char *, int, void *); int parse_color(Clp_Parser *, const char *, int, void *); int parse_rectangle(Clp_Parser *, const char *, int, void *); int parse_two_colors(Clp_Parser *, const char *, int, void *); extern Gif_Stream *input; extern const char *input_name; void input_stream(const char *); void input_done(void); void output_frames(void); /***** * stuff with frames **/ extern Gt_Frame def_frame; #define FRAME(fs, i) ((fs)->f[i]) Gt_Frameset * new_frameset(int initial_cap); Gt_Frame * add_frame(Gt_Frameset *, int num, Gif_Stream *, Gif_Image *); void clear_def_frame_once_options(void); Gif_Stream * merge_frame_interval(Gt_Frameset *, int f1, int f2, Gt_OutputData *, int compress, int *huge); void clear_frameset(Gt_Frameset *, int from); void blank_frameset(Gt_Frameset *, int from, int to, int delete_ob); /***** * mode **/ #define BLANK_MODE 0 #define MERGING 1 #define BATCHING 2 #define EXPLODING 3 #define INFOING 4 #define DELETING 5 #define INSERTING 6 extern int mode; extern int nested_mode; gifsicle-1.78/src/gifunopt.c0000644000175000017500000001362412237507603012760 00000000000000/* gifunopt.c - Unoptimization function for the GIF library. Copyright (C) 1997-2013 Eddie Kohler, kohler@cs.ucla.edu This file is part of the LCDF GIF library. The LCDF GIF library is free software. It is distributed under the GNU General Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #ifdef __cplusplus extern "C" { #endif #define TRANSPARENT 256 static void put_image_in_screen(Gif_Stream *gfs, Gif_Image *gfi, uint16_t *screen) { int transparent = gfi->transparent; int x, y; int w = gfi->width; int h = gfi->height; if (gfi->left + w > gfs->screen_width) w = gfs->screen_width - gfi->left; if (gfi->top + h > gfs->screen_height) h = gfs->screen_height - gfi->top; for (y = 0; y < h; y++) { uint16_t *move = screen + gfs->screen_width * (y + gfi->top) + gfi->left; uint8_t *line = gfi->img[y]; for (x = 0; x < w; x++, move++, line++) if (*line != transparent) *move = *line; } } static void put_background_in_screen(Gif_Stream *gfs, Gif_Image *gfi, uint16_t *screen) { uint16_t solid; int x, y; int w = gfi->width; int h = gfi->height; if (gfi->left + w > gfs->screen_width) w = gfs->screen_width - gfi->left; if (gfi->top + h > gfs->screen_height) h = gfs->screen_height - gfi->top; if (gfi->transparent >= 0) solid = TRANSPARENT; else if (gfs->images[0]->transparent >= 0) solid = TRANSPARENT; else solid = gfs->background; for (y = 0; y < h; y++) { uint16_t *move = screen + gfs->screen_width * (y + gfi->top) + gfi->left; for (x = 0; x < w; x++, move++) *move = solid; } } static int create_image_data(Gif_Stream *gfs, Gif_Image *gfi, uint16_t *screen, uint8_t *new_data, int *used_transparent) { int have[257]; int transparent = -1; int size = gfs->screen_width * gfs->screen_height; uint16_t *move; int i; /* mark colors used opaquely in the image */ assert(TRANSPARENT == 256); for (i = 0; i < 257; i++) have[i] = 0; for (i = 0, move = screen; i < size; i++, move++) have[*move] = 1; /* the new transparent color is a color unused in either */ if (have[TRANSPARENT]) { for (i = 0; i < 256 && transparent < 0; i++) if (!have[i]) transparent = i; if (transparent < 0) goto error; if (transparent >= gfs->global->ncol) { Gif_ReArray(gfs->global->col, Gif_Color, 256); if (!gfs->global->col) goto error; gfs->global->ncol = transparent + 1; } } /* map the wide image onto the new data */ *used_transparent = 0; for (i = 0, move = screen; i < size; i++, move++, new_data++) if (*move == TRANSPARENT) { *new_data = transparent; *used_transparent = 1; } else *new_data = *move; gfi->transparent = transparent; return 1; error: return 0; } static int unoptimize_image(Gif_Stream *gfs, Gif_Image *gfi, uint16_t *screen) { int size = gfs->screen_width * gfs->screen_height; int used_transparent; uint8_t *new_data = Gif_NewArray(uint8_t, size); uint16_t *new_screen = screen; if (!new_data) return 0; /* Oops! May need to uncompress it */ Gif_UncompressImage(gfi); Gif_ReleaseCompressedImage(gfi); if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) { new_screen = Gif_NewArray(uint16_t, size); if (!new_screen) return 0; memcpy(new_screen, screen, size * sizeof(uint16_t)); } put_image_in_screen(gfs, gfi, new_screen); if (!create_image_data(gfs, gfi, new_screen, new_data, &used_transparent)) { Gif_DeleteArray(new_data); return 0; } if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) Gif_DeleteArray(new_screen); else if (gfi->disposal == GIF_DISPOSAL_BACKGROUND) put_background_in_screen(gfs, gfi, screen); gfi->left = 0; gfi->top = 0; gfi->width = gfs->screen_width; gfi->height = gfs->screen_height; gfi->disposal = used_transparent; Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0); return 1; } static int no_more_transparency(Gif_Image *gfi1, Gif_Image *gfi2) { int t1 = gfi1->transparent, t2 = gfi2->transparent, y; if (t1 < 0) return 1; for (y = 0; y < gfi1->height; ++y) { uint8_t *d1 = gfi1->img[y], *d2 = gfi2->img[y], *ed1 = d1 + gfi1->width; while (d1 < ed1) { if (*d1 == t1 && *d2 != t2) return 0; ++d1, ++d2; } } return 1; } int Gif_FullUnoptimize(Gif_Stream *gfs, int flags) { int ok = 1; int i, size; uint16_t *screen; uint16_t background; Gif_Image *gfi; if (gfs->nimages < 1) return 1; for (i = 0; i < gfs->nimages; i++) if (gfs->images[i]->local) return 0; if (!gfs->global) return 0; Gif_CalculateScreenSize(gfs, 0); size = gfs->screen_width * gfs->screen_height; screen = Gif_NewArray(uint16_t, size); gfi = gfs->images[0]; background = gfi->transparent >= 0 ? TRANSPARENT : gfs->background; for (i = 0; i < size; i++) screen[i] = background; for (i = 0; i < gfs->nimages; i++) if (!unoptimize_image(gfs, gfs->images[i], screen)) ok = 0; if (ok) { if (flags & GIF_UNOPTIMIZE_SIMPLEST_DISPOSAL) { /* set disposal based on use of transparency. If (every transparent pixel in frame i is also transparent in frame i - 1), then frame i - 1 gets disposal ASIS; otherwise, disposal BACKGROUND. */ for (i = 0; i < gfs->nimages; ++i) if (i == gfs->nimages - 1 || no_more_transparency(gfs->images[i+1], gfs->images[i])) gfs->images[i]->disposal = GIF_DISPOSAL_NONE; else gfs->images[i]->disposal = GIF_DISPOSAL_BACKGROUND; } else for (i = 0; i < gfs->nimages; ++i) gfs->images[i]->disposal = GIF_DISPOSAL_BACKGROUND; } Gif_DeleteArray(screen); return ok; } int Gif_Unoptimize(Gif_Stream *gfs) { return Gif_FullUnoptimize(gfs, 0); } #ifdef __cplusplus } #endif gifsicle-1.78/src/strerror.c0000644000175000017500000000071612237442106013001 00000000000000/* Some operating systems don't have strerror. This file provides a definition which David Mazieres assures me works. */ #ifdef HAVE_CONFIG_H # include #endif #ifdef __cplusplus extern "C" { #endif char * strerror(int errno) { extern int sys_nerr; extern char *sys_errlist[]; if (errno < 0 || errno >= sys_nerr) return (char *)"bad error number"; else return sys_errlist[errno]; } #ifdef __cplusplus } #endif gifsicle-1.78/src/ungifwrt.c0000644000175000017500000004533512242717703012776 00000000000000/* -*- mode: c; c-basic-offset: 2 -*- */ /* ungifwrt.c - Functions to write unGIFs -- GIFs with run-length compression, not LZW compression. Idea due to Hutchinson Avenue Software Corporation . Copyright (C) 1997-2013 Eddie Kohler, kohler@cs.ucla.edu This file is part of the LCDF GIF library. The LCDF GIF library is free software. It is distributed under the GNU Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #ifdef HAVE_CONFIG_H # include #elif !defined(__cplusplus) && !defined(inline) /* Assume we don't have inline by default */ # define inline #endif #include #include #include #ifdef __cplusplus extern "C" { #endif #define WRITE_BUFFER_SIZE 255 typedef struct Gif_Context { Gif_Code *rle_next; } Gif_Context; typedef struct Gif_Writer { FILE *f; uint8_t *v; uint32_t pos; uint32_t cap; Gif_CompressInfo gcinfo; int global_size; int local_size; void (*byte_putter)(uint8_t, struct Gif_Writer *); void (*block_putter)(uint8_t *, uint16_t, struct Gif_Writer *); } Gif_Writer; #define gifputbyte(b, grr) ((*grr->byte_putter)(b, grr)) #define gifputblock(b, l, grr) ((*grr->block_putter)(b, l, grr)) static inline void gifputunsigned(uint16_t uns, Gif_Writer *grr) { gifputbyte(uns & 0xFF, grr); gifputbyte(uns >> 8, grr); } static void file_byte_putter(uint8_t b, Gif_Writer *grr) { fputc(b, grr->f); } static void file_block_putter(uint8_t *block, uint16_t size, Gif_Writer *grr) { fwrite(block, size, 1, grr->f); } static void memory_byte_putter(uint8_t b, Gif_Writer *grr) { if (grr->pos >= grr->cap) { grr->cap *= 2; Gif_ReArray(grr->v, uint8_t, grr->cap); } if (grr->v) { grr->v[grr->pos] = b; grr->pos++; } } static void memory_block_putter(uint8_t *data, uint16_t len, Gif_Writer *grr) { if (grr->pos + len >= grr->cap) { grr->cap *= 2; Gif_ReArray(grr->v, uint8_t, grr->cap); } if (grr->v) { memcpy(grr->v + grr->pos, data, len); grr->pos += len; } } #ifndef GIF_NO_COMPRESSION /* Write GIFs compressed with run-length encoding, an idea from code by Hutchinson Avenue Software Corporation found in Thomas Boutell's gd library . */ static void write_compressed_data(uint8_t **img, uint16_t width, uint16_t height, uint8_t min_code_bits, Gif_Context *gfc, Gif_Writer *grr) { uint8_t buffer[WRITE_BUFFER_SIZE]; uint8_t *buf; uint16_t xleft; uint8_t *imageline; uint32_t leftover; uint8_t bits_left_over; Gif_Code next_code; Gif_Code output_code; Gif_Code clear_code; Gif_Code eoi_code; #define CUR_BUMP_CODE (1 << cur_code_bits) uint8_t suffix; Gif_Code *rle_next = gfc->rle_next; uint8_t cur_code_bits; /* Here we go! */ gifputbyte(min_code_bits, grr); clear_code = 1 << min_code_bits; eoi_code = clear_code + 1; cur_code_bits = min_code_bits + 1; /* next_code set by first runthrough of output clear_code */ GIF_DEBUG(("clear(%d) eoi(%d) bits(%d)",clear_code,eoi_code,cur_code_bits)); output_code = clear_code; /* Because output_code is clear_code, we'll initialize next_code, et al. below. */ bits_left_over = 0; leftover = 0; buf = buffer; xleft = width; imageline = img[0]; while (1) { /***** * Output 'output_code' to the data stream. */ leftover |= output_code << bits_left_over; bits_left_over += cur_code_bits; while (bits_left_over >= 8) { *buf++ = leftover & 0xFF; leftover = (leftover >> 8) & 0x00FFFFFF; bits_left_over -= 8; if (buf == buffer + WRITE_BUFFER_SIZE) { gifputbyte(WRITE_BUFFER_SIZE, grr); gifputblock(buffer, WRITE_BUFFER_SIZE, grr); buf = buffer; } } if (output_code == clear_code) { /* Clear data and prepare gfc */ Gif_Code c; cur_code_bits = min_code_bits + 1; next_code = eoi_code + 1; for (c = 0; c < clear_code; c++) rle_next[c] = clear_code; } else if (next_code > CUR_BUMP_CODE) { /* bump up compression size */ if (cur_code_bits == GIF_MAX_CODE_BITS) { output_code = clear_code; continue; } else cur_code_bits++; } else if (output_code == eoi_code) break; /***** * Find the next code to output. */ /* If height is 0 -- no more pixels to write -- output eoi_code. */ if (height == 0) output_code = eoi_code; else { output_code = suffix = *imageline; if (output_code >= clear_code) /* should not happen unless GIF_WRITE_CAREFUL_MIN_CODE_SIZE */ output_code = suffix = 0; goto next_pixel; while (height != 0 && *imageline == suffix && rle_next[output_code] != clear_code) { output_code = rle_next[output_code]; next_pixel: imageline++; xleft--; if (xleft == 0) { xleft = width; height--; img++; imageline = img[0]; } } if (height != 0 && *imageline == suffix) { rle_next[output_code] = next_code; rle_next[next_code] = clear_code; } next_code++; } } if (bits_left_over > 0) *buf++ = leftover; if (buf != buffer) { GIF_DEBUG(("imageblock(%d)", buf - buffer)); gifputbyte(buf - buffer, grr); gifputblock(buffer, buf - buffer, grr); } gifputbyte(0, grr); } #else /* GIF_NO_COMPRESSION */ static void write_compressed_data(uint8_t **img, uint16_t width, uint16_t height, uint8_t min_code_bits, Gif_Context *gfc, Gif_Writer *grr) { uint8_t buffer[WRITE_BUFFER_SIZE]; uint8_t *buf; uint16_t xleft; uint8_t *imageline; uint32_t leftover; uint8_t bits_left_over; Gif_Code next_code; Gif_Code output_code; Gif_Code clear_code; Gif_Code eoi_code; Gif_Code bump_code; uint8_t cur_code_bits; /* Here we go! */ gifputbyte(min_code_bits, grr); clear_code = 1 << min_code_bits; eoi_code = clear_code + 1; cur_code_bits = min_code_bits + 1; /* bump_code, next_code set by first runthrough of output clear_code */ GIF_DEBUG(("clear(%d) eoi(%d)", clear_code, eoi_code)); output_code = clear_code; /* Because output_code is clear_code, we'll initialize next_code, bump_code, et al. below. */ bits_left_over = 0; leftover = 0; buf = buffer; xleft = width; imageline = img[0]; while (1) { /***** * Output 'output_code' to the data stream. */ leftover |= output_code << bits_left_over; bits_left_over += cur_code_bits; while (bits_left_over >= 8) { *buf++ = leftover & 0xFF; leftover = (leftover >> 8) & 0x00FFFFFF; bits_left_over -= 8; if (buf == buffer + WRITE_BUFFER_SIZE) { GIF_DEBUG(("chunk")); gifputbyte(WRITE_BUFFER_SIZE, grr); gifputblock(buffer, WRITE_BUFFER_SIZE, grr); buf = buffer; } } if (output_code == clear_code) { cur_code_bits = min_code_bits + 1; next_code = eoi_code + 1; bump_code = clear_code << 1; } else if (next_code == bump_code) { /* never bump up compression size -- keep cur_code_bits small by generating clear_codes */ output_code = clear_code; continue; } else if (output_code == eoi_code) break; /***** * Find the next code to output. */ /* If height is 0 -- no more pixels to write -- output eoi_code. */ if (height == 0) output_code = eoi_code; else { output_code = *imageline; if (output_code >= clear_code) output_code = 0; imageline++; xleft--; if (xleft == 0) { xleft = width; height--; img++; imageline = img[0]; } next_code++; } } if (bits_left_over > 0) *buf++ = leftover; if (buf != buffer) { GIF_DEBUG(("imageblock(%d)", buf - buffer)); gifputbyte(buf - buffer, grr); gifputblock(buffer, buf - buffer, grr); } gifputbyte(0, grr); } #endif /* GIF_NO_COMPRESSION */ static int calculate_min_code_bits(Gif_Stream *gfs, Gif_Image *gfi, Gif_Writer *grr) { int colors_used = -1, min_code_bits, i; if (grr->gcinfo.flags & GIF_WRITE_CAREFUL_MIN_CODE_SIZE) { /* calculate m_c_b based on colormap */ if (grr->local_size > 0) colors_used = grr->local_size; else if (grr->global_size > 0) colors_used = grr->global_size; } else if (gfi->compressed) { /* take m_c_b from compressed image */ colors_used = 1 << gfi->compressed[0]; } else if (gfi->img) { /* calculate m_c_b from uncompressed data */ int x, y, width = gfi->width, height = gfi->height; colors_used = 0; for (y = 0; y < height && colors_used < 128; y++) { uint8_t *data = gfi->img[y]; for (x = width; x > 0; x--, data++) if (*data > colors_used) colors_used = *data; } colors_used++; } else { /* should never happen */ colors_used = 256; } min_code_bits = 2; /* min_code_bits of 1 isn't allowed */ i = 4; while (i < colors_used) { min_code_bits++; i *= 2; } if ((grr->gcinfo.flags & GIF_WRITE_CAREFUL_MIN_CODE_SIZE) && gfi->compressed && gfi->compressed[0] != min_code_bits) { /* if compressed image disagrees with careful min_code_bits, recompress */ if (Gif_UncompressImage(gfi)) Gif_FullCompressImage(gfs, gfi, &grr->gcinfo); } return min_code_bits; } static int write_image_data(Gif_Image *gfi, uint8_t min_code_bits, Gif_Context *gfc, Gif_Writer *grr) { uint8_t **img = gfi->img; uint16_t width = gfi->width, height = gfi->height; if (gfi->interlace) { uint16_t y; uint8_t **nimg = Gif_NewArray(uint8_t *, height + 1); if (!nimg) return 0; for (y = 0; y < height; y++) nimg[y] = img[Gif_InterlaceLine(y, height)]; nimg[height] = 0; write_compressed_data(nimg, width, height, min_code_bits, gfc, grr); Gif_DeleteArray(nimg); } else write_compressed_data(img, width, height, min_code_bits, gfc, grr); return 1; } static int get_color_table_size(Gif_Stream *, Gif_Image *, Gif_Writer *); int Gif_FullCompressImage(Gif_Stream *gfs, Gif_Image *gfi, const Gif_CompressInfo *gcinfo) { int ok = 0; uint8_t min_code_bits; Gif_Writer grr; Gif_Context gfc; if (gfi->compressed && gfi->free_compressed) { (*gfi->free_compressed)((void *)gfi->compressed); gfi->compressed = 0; } /* 27.Jul.2001: Must allocate GIF_MAX_CODE + 1 because we assign to rle_next[GIF_MAX_CODE]! Thanks, Jeff Brown , for supplying the buggy files. */ gfc.rle_next = Gif_NewArray(Gif_Code, GIF_MAX_CODE + 1); grr.v = Gif_NewArray(uint8_t, 1024); grr.pos = 0; grr.cap = 1024; grr.byte_putter = memory_byte_putter; grr.block_putter = memory_block_putter; if (gcinfo) grr.gcinfo = *gcinfo; else Gif_InitCompressInfo(&grr.gcinfo); grr.global_size = get_color_table_size(gfs, 0, &grr); grr.local_size = get_color_table_size(gfs, gfi, &grr); if (!grr.v || !gfc.rle_next) goto done; min_code_bits = calculate_min_code_bits(gfs, gfi, &grr); ok = write_image_data(gfi, min_code_bits, &gfc, &grr); done: if (!ok) { Gif_DeleteArray(grr.v); grr.v = 0; } gfi->compressed = grr.v; gfi->compressed_len = grr.pos; gfi->free_compressed = Gif_DeleteArrayFunc; Gif_DeleteArray(gfc.rle_next); return grr.v != 0; } static int get_color_table_size(Gif_Stream *gfs, Gif_Image *gfi, Gif_Writer *grr) { Gif_Colormap *gfcm = (gfi ? gfi->local : gfs->global); int ncol, totalcol, i; if (!gfcm || gfcm->ncol <= 0) return 0; /* Make sure ncol is reasonable */ ncol = gfcm->ncol; /* Possibly bump up 'ncol' based on 'transparent' values, if careful_min_code_bits */ if (grr->gcinfo.flags & GIF_WRITE_CAREFUL_MIN_CODE_SIZE) { if (gfi && gfi->transparent >= ncol) ncol = gfi->transparent + 1; else if (!gfi) for (i = 0; i < gfs->nimages; i++) if (gfs->images[i]->transparent >= ncol) ncol = gfs->images[i]->transparent + 1; } /* Make sure the colormap is a power of two entries! */ /* GIF format doesn't allow a colormap with only 1 entry. */ if (ncol > 256) ncol = 256; for (totalcol = 2; totalcol < ncol; totalcol *= 2) /* nada */; return totalcol; } static void write_color_table(Gif_Colormap *gfcm, int totalcol, Gif_Writer *grr) { Gif_Color *c = gfcm->col; int i, ncol = gfcm->ncol; for (i = 0; i < ncol && i < totalcol; i++, c++) { gifputbyte(c->gfc_red, grr); gifputbyte(c->gfc_green, grr); gifputbyte(c->gfc_blue, grr); } /* Pad out colormap with black. */ for (; i < totalcol; i++) { gifputbyte(0, grr); gifputbyte(0, grr); gifputbyte(0, grr); } } static int write_image(Gif_Stream *gfs, Gif_Image *gfi, Gif_Context *gfc, Gif_Writer *grr) { uint8_t min_code_bits, packed = 0; grr->local_size = get_color_table_size(gfs, gfi, grr); gifputbyte(',', grr); gifputunsigned(gfi->left, grr); gifputunsigned(gfi->top, grr); gifputunsigned(gfi->width, grr); gifputunsigned(gfi->height, grr); if (grr->local_size > 0) { int size = 2; packed |= 0x80; while (size < grr->local_size) size *= 2, packed++; } if (gfi->interlace) packed |= 0x40; gifputbyte(packed, grr); if (grr->local_size > 0) write_color_table(gfi->local, grr->local_size, grr); /* calculate min_code_bits here (because calculation may involve recompression, if GIF_WRITE_CAREFUL_MIN_CODE_SIZE is true) */ min_code_bits = calculate_min_code_bits(gfs, gfi, grr); /* use existing compressed data if it exists. This will tend to whip people's asses who uncompress an image, keep the compressed data around, but modify the uncompressed data anyway. That sucks. */ if (gfi->compressed) { uint8_t *compressed = gfi->compressed; uint32_t compressed_len = gfi->compressed_len; while (compressed_len > 0) { uint16_t amt = (compressed_len > 0x7000 ? 0x7000 : compressed_len); gifputblock(compressed, amt, grr); compressed += amt; compressed_len -= amt; } } else write_image_data(gfi, min_code_bits, gfc, grr); return 1; } static void write_logical_screen_descriptor(Gif_Stream *gfs, Gif_Writer *grr) { uint8_t packed = 0x70; /* high resolution colors */ grr->global_size = get_color_table_size(gfs, 0, grr); Gif_CalculateScreenSize(gfs, 0); gifputunsigned(gfs->screen_width, grr); gifputunsigned(gfs->screen_height, grr); if (grr->global_size > 0) { uint16_t size = 2; packed |= 0x80; while (size < grr->global_size) size *= 2, packed++; } gifputbyte(packed, grr); gifputbyte(gfs->background, grr); gifputbyte(0, grr); /* no aspect ratio information */ if (grr->global_size > 0) write_color_table(gfs->global, grr->global_size, grr); } /* extension byte table: 0x01 plain text extension 0xCE name* 0xF9 graphic control extension 0xFE comment extension 0xFF application extension */ static void write_graphic_control_extension(Gif_Image *gfi, Gif_Writer *grr) { uint8_t packed = 0; gifputbyte('!', grr); gifputbyte(0xF9, grr); gifputbyte(4, grr); if (gfi->transparent >= 0) packed |= 0x01; packed |= (gfi->disposal & 0x07) << 2; gifputbyte(packed, grr); gifputunsigned(gfi->delay, grr); gifputbyte((uint8_t)gfi->transparent, grr); gifputbyte(0, grr); } static void blast_data(uint8_t *data, int len, Gif_Writer *grr) { while (len > 0) { int s = len > 255 ? 255 : len; gifputbyte(s, grr); gifputblock(data, s, grr); data += s; len -= s; } gifputbyte(0, grr); } static void write_name_extension(char *id, Gif_Writer *grr) { gifputbyte('!', grr); gifputbyte(0xCE, grr); blast_data((uint8_t *)id, strlen(id), grr); } static void write_comment_extensions(Gif_Comment *gfcom, Gif_Writer *grr) { int i; for (i = 0; i < gfcom->count; i++) { gifputbyte('!', grr); gifputbyte(0xFE, grr); blast_data((uint8_t *)gfcom->str[i], gfcom->len[i], grr); } } static void write_netscape_loop_extension(uint16_t value, Gif_Writer *grr) { gifputblock((uint8_t *)"!\xFF\x0BNETSCAPE2.0\x03\x01", 16, grr); gifputunsigned(value, grr); gifputbyte(0, grr); } static void write_generic_extension(Gif_Extension *gfex, Gif_Writer *grr) { uint32_t pos = 0; if (gfex->kind < 0) return; /* ignore our private extensions */ gifputbyte('!', grr); gifputbyte(gfex->kind, grr); if (gfex->kind == 255) { /* an application extension */ int len = gfex->application ? strlen(gfex->application) : 0; if (len) { gifputbyte(len, grr); gifputblock((uint8_t *)gfex->application, len, grr); } } while (pos + 255 < gfex->length) { gifputbyte(255, grr); gifputblock(gfex->data + pos, 255, grr); pos += 255; } if (pos < gfex->length) { uint32_t len = gfex->length - pos; gifputbyte(len, grr); gifputblock(gfex->data + pos, len, grr); } gifputbyte(0, grr); } static int write_gif(Gif_Stream *gfs, Gif_Writer *grr) { int ok = 0; int i; Gif_Image *gfi; Gif_Extension *gfex = gfs->extensions; Gif_Context gfc; gfc.rle_next = Gif_NewArray(Gif_Code, GIF_MAX_CODE + 1); if (!gfc.rle_next) goto done; { uint8_t isgif89a = 0; if (gfs->comment || gfs->loopcount > -1) isgif89a = 1; for (i = 0; i < gfs->nimages && !isgif89a; i++) { gfi = gfs->images[i]; if (gfi->identifier || gfi->transparent != -1 || gfi->disposal || gfi->delay || gfi->comment) isgif89a = 1; } if (isgif89a) gifputblock((uint8_t *)"GIF89a", 6, grr); else gifputblock((uint8_t *)"GIF87a", 6, grr); } write_logical_screen_descriptor(gfs, grr); if (gfs->loopcount > -1) write_netscape_loop_extension(gfs->loopcount, grr); for (i = 0; i < gfs->nimages; i++) { Gif_Image *gfi = gfs->images[i]; while (gfex && gfex->position == i) { write_generic_extension(gfex, grr); gfex = gfex->next; } if (gfi->comment) write_comment_extensions(gfi->comment, grr); if (gfi->identifier) write_name_extension(gfi->identifier, grr); if (gfi->transparent != -1 || gfi->disposal || gfi->delay) write_graphic_control_extension(gfi, grr); if (!write_image(gfs, gfi, &gfc, grr)) goto done; } while (gfex) { write_generic_extension(gfex, grr); gfex = gfex->next; } if (gfs->comment) write_comment_extensions(gfs->comment, grr); gifputbyte(';', grr); ok = 1; done: Gif_DeleteArray(gfc.rle_next); return ok; } int Gif_FullWriteFile(Gif_Stream *gfs, const Gif_CompressInfo *gcinfo, FILE *f) { Gif_Writer grr; grr.f = f; grr.byte_putter = file_byte_putter; grr.block_putter = file_block_putter; if (gcinfo) grr.gcinfo = *gcinfo; else Gif_InitCompressInfo(&grr.gcinfo); return write_gif(gfs, &grr); } #undef Gif_CompressImage #undef Gif_WriteFile int Gif_CompressImage(Gif_Stream *gfs, Gif_Image *gfi) { return Gif_FullCompressImage(gfs, gfi, 0); } int Gif_WriteFile(Gif_Stream *gfs, FILE *f) { return Gif_FullWriteFile(gfs, 0, f); } #ifdef __cplusplus } #endif gifsicle-1.78/src/gifwrite.c0000644000175000017500000005603412242717703012747 00000000000000/* -*- mode: c; c-basic-offset: 2 -*- */ /* gifwrite.c - Functions to write GIFs. Copyright (C) 1997-2013 Eddie Kohler, kohler@cs.ucla.edu This file is part of the LCDF GIF library. The LCDF GIF library is free software. It is distributed under the GNU General Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #ifdef HAVE_CONFIG_H # include #elif !defined(__cplusplus) && !defined(inline) /* Assume we don't have inline by default */ # define inline #endif #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define WRITE_BUFFER_SIZE 255 #define NODES_SIZE GIF_MAX_CODE #define LINKS_SIZE GIF_MAX_CODE /* 1.Aug.1999 - Removed code hashing in favor of an adaptive tree strategy based on Whirlgif-3.04, written by Hans Dinsen-Hansen . Mr. Dinsen-Hansen brought the adaptive tree strategy to my attention and argued at length that it was better than hashing. In fact, he was right: it runs a lot faster. However, it does NOT create "better" results in any way. Each code is represented by a Node. The Nodes form a tree with variable fan-out -- up to 'clear_code' children per Node. There are two kinds of Node, TABLE and LINKS. In a TABLE node, the children are stored in a table indexed by suffix -- thus, it's very efficient to determine a given child. In a LINKS node, the existent children are stored in a linked list. This is slightly slower to access. When a LINKS node gets more than 'MAX_LINKS_TYPE-1' children, it is converted to a TABLE node. (This is why it's an adaptive tree.) Problems with this implementation: MAX_LINKS_TYPE is fixed, so GIFs with very small numbers of colors (2, 4, 8) won't get the speed benefits of TABLE nodes. */ #define TABLE_TYPE 0 #define LINKS_TYPE 1 #define MAX_LINKS_TYPE 5 typedef struct Gif_Node { Gif_Code code; uint8_t type; uint8_t suffix; struct Gif_Node *sibling; union { struct Gif_Node *s; struct Gif_Node **m; } child; } Gif_Node; typedef struct Gif_CodeTable { Gif_Node *nodes; int nodes_pos; Gif_Node **links; int links_pos; int clear_code; } Gif_CodeTable; typedef struct Gif_Writer { FILE *f; uint8_t *v; uint32_t pos; uint32_t cap; Gif_CompressInfo gcinfo; int global_size; int local_size; int errors; int cleared; void (*byte_putter)(uint8_t, struct Gif_Writer *); void (*block_putter)(const uint8_t *, uint16_t, struct Gif_Writer *); } Gif_Writer; #define gifputbyte(b, grr) ((*grr->byte_putter)(b, grr)) #define gifputblock(b, l, grr) ((*grr->block_putter)(b, l, grr)) static inline void gifputunsigned(uint16_t uns, Gif_Writer *grr) { gifputbyte(uns & 0xFF, grr); gifputbyte(uns >> 8, grr); } static void file_byte_putter(uint8_t b, Gif_Writer *grr) { fputc(b, grr->f); } static void file_block_putter(const uint8_t *block, uint16_t size, Gif_Writer *grr) { if (fwrite(block, 1, size, grr->f) != (size_t) size) grr->errors = 1; } static void memory_byte_putter(uint8_t b, Gif_Writer *grr) { if (grr->pos >= grr->cap) { grr->cap = (grr->cap ? grr->cap * 2 : 1024); Gif_ReArray(grr->v, uint8_t, grr->cap); } if (grr->v) { grr->v[grr->pos] = b; grr->pos++; } } static void memory_block_putter(const uint8_t *data, uint16_t len, Gif_Writer *grr) { while (grr->pos + len >= grr->cap) { grr->cap = (grr->cap ? grr->cap * 2 : 1024); Gif_ReArray(grr->v, uint8_t, grr->cap); } if (grr->v) { memcpy(grr->v + grr->pos, data, len); grr->pos += len; } } static int gfc_init(Gif_CodeTable *gfc) { gfc->nodes = Gif_NewArray(Gif_Node, NODES_SIZE); gfc->links = Gif_NewArray(Gif_Node *, LINKS_SIZE); return gfc->nodes && gfc->links; } static inline void gfc_clear(Gif_CodeTable *gfc, Gif_Code clear_code) { int c; /* The first clear_code nodes are reserved for single-pixel codes */ gfc->nodes_pos = clear_code; gfc->links_pos = 0; for (c = 0; c < clear_code; c++) { gfc->nodes[c].code = c; gfc->nodes[c].type = LINKS_TYPE; gfc->nodes[c].suffix = c; gfc->nodes[c].child.s = 0; } gfc->clear_code = clear_code; } static inline Gif_Node * gfc_lookup(Gif_CodeTable *gfc, Gif_Node *node, uint8_t suffix) { assert(!node || (node >= gfc->nodes && node < gfc->nodes + NODES_SIZE)); assert(suffix < gfc->clear_code); if (!node) return &gfc->nodes[suffix]; else if (node->type == TABLE_TYPE) return node->child.m[suffix]; else { for (node = node->child.s; node; node = node->sibling) if (node->suffix == suffix) return node; return NULL; } } static void gfc_change_node_to_table(Gif_CodeTable *gfc, Gif_Node *work_node, Gif_Node *next_node) { /* change links node to table node */ Gif_Code c; Gif_Node **table = &gfc->links[gfc->links_pos]; Gif_Node *n; gfc->links_pos += gfc->clear_code; for (c = 0; c < gfc->clear_code; c++) table[c] = 0; table[next_node->suffix] = next_node; for (n = work_node->child.s; n; n = n->sibling) table[n->suffix] = n; work_node->type = TABLE_TYPE; work_node->child.m = table; } static inline void gfc_define(Gif_CodeTable *gfc, Gif_Node *work_node, uint8_t suffix, Gif_Code next_code) { /* Add a new code to our dictionary. First reserve a node for the added code. It's LINKS_TYPE at first. */ Gif_Node *next_node = &gfc->nodes[gfc->nodes_pos]; gfc->nodes_pos++; next_node->code = next_code; next_node->type = LINKS_TYPE; next_node->suffix = suffix; next_node->child.s = 0; /* link next_node into work_node's set of children */ if (work_node->type == TABLE_TYPE) work_node->child.m[suffix] = next_node; else if (work_node->type < MAX_LINKS_TYPE || gfc->links_pos + gfc->clear_code > LINKS_SIZE) { next_node->sibling = work_node->child.s; work_node->child.s = next_node; if (work_node->type < MAX_LINKS_TYPE) work_node->type++; } else gfc_change_node_to_table(gfc, work_node, next_node); } static inline const uint8_t * gif_imageline(Gif_Image *gfi, unsigned pos) { unsigned y = pos / gfi->width, x = pos - y * gfi->width; if (y == (unsigned) gfi->height) return NULL; else if (!gfi->interlace) return gfi->img[y] + x; else return gfi->img[Gif_InterlaceLine(y, gfi->height)] + x; } static inline unsigned gif_line_endpos(Gif_Image *gfi, unsigned pos) { unsigned y = pos / gfi->width; return (y + 1) * gfi->width; } static int write_compressed_data(Gif_Image *gfi, int min_code_bits, Gif_CodeTable *gfc, Gif_Writer *grr) { uint8_t stack_buffer[232]; uint8_t *buf = stack_buffer; unsigned bufpos = 0; unsigned bufcap = sizeof(stack_buffer) * 8; unsigned pos; unsigned clear_bufpos, clear_pos; unsigned line_endpos; const uint8_t *imageline; Gif_Node *work_node; unsigned run; #define RUN_EWMA_SHIFT 4 #define RUN_EWMA_SCALE 19 #define RUN_INV_THRESH ((unsigned) (1 << RUN_EWMA_SCALE) / 3000) unsigned run_ewma; Gif_Node *next_node; Gif_Code next_code = 0; Gif_Code output_code; #define CUR_BUMP_CODE (1 << cur_code_bits) uint8_t suffix; int cur_code_bits; /* Here we go! */ gifputbyte(min_code_bits, grr); #define CLEAR_CODE ((Gif_Code) (1 << min_code_bits)) #define EOI_CODE ((Gif_Code) (CLEAR_CODE + 1)) grr->cleared = 0; cur_code_bits = min_code_bits + 1; /* next_code set by first runthrough of output clear_code */ GIF_DEBUG(("clear(%d) eoi(%d) bits(%d)", CLEAR_CODE, EOI_CODE, cur_code_bits)); work_node = 0; run = 0; run_ewma = 1 << RUN_EWMA_SCALE; output_code = CLEAR_CODE; /* Because output_code is clear_code, we'll initialize next_code, et al. below. */ pos = clear_pos = clear_bufpos = 0; line_endpos = gfi->width; imageline = gif_imageline(gfi, pos); while (1) { /***** * Output 'output_code' to the memory buffer. */ if (bufpos + cur_code_bits >= bufcap) { unsigned ncap = bufcap * 2 + (24 << 3); uint8_t *nbuf = Gif_NewArray(uint8_t, ncap >> 3); if (!nbuf) return 0; memcpy(nbuf, buf, bufcap >> 3); if (buf != stack_buffer) Gif_DeleteArray(buf); buf = nbuf; bufcap = ncap; } { unsigned startpos = bufpos; do { if (bufpos & 7) buf[bufpos >> 3] |= output_code << (bufpos & 7); else buf[bufpos >> 3] = output_code >> (bufpos - startpos); bufpos += 8 - (bufpos & 7); } while (bufpos < startpos + cur_code_bits); bufpos = startpos + cur_code_bits; } /***** * Handle special codes. */ if (output_code == CLEAR_CODE) { /* Clear data and prepare gfc */ cur_code_bits = min_code_bits + 1; next_code = EOI_CODE + 1; run_ewma = 1 << RUN_EWMA_SCALE; gfc_clear(gfc, CLEAR_CODE); clear_pos = clear_bufpos = 0; GIF_DEBUG(("clear")); } else if (output_code == EOI_CODE) break; else if (next_code > CUR_BUMP_CODE && cur_code_bits < GIF_MAX_CODE_BITS) /* bump up compression size */ ++cur_code_bits; /***** * Find the next code to output. */ /* If height is 0 -- no more pixels to write -- we output work_node next time around. */ while (imageline) { suffix = *imageline; next_node = gfc_lookup(gfc, work_node, suffix); imageline++; pos++; if (pos == line_endpos) { imageline = gif_imageline(gfi, pos); line_endpos += gfi->width; } if (!next_node) { /* Output the current code. */ if (next_code < GIF_MAX_CODE) { gfc_define(gfc, work_node, suffix, next_code); next_code++; } else next_code = GIF_MAX_CODE + 1; /* to match "> CUR_BUMP_CODE" above */ /* Check whether to clear table. */ if (next_code > 4094) { int do_clear = grr->gcinfo.flags & GIF_WRITE_EAGER_CLEAR; if (!do_clear) { unsigned pixels_left = gfi->width * gfi->height - pos; if (pixels_left) { /* Always clear if run_ewma gets small relative to min_code_bits. Otherwise, clear if #images/run is smaller than an empirical threshold, meaning it will take more than 3000 or so average runs to complete the image. */ if (run_ewma < ((36U << RUN_EWMA_SCALE) / min_code_bits) || pixels_left > UINT_MAX / RUN_INV_THRESH || run_ewma < pixels_left * RUN_INV_THRESH) do_clear = 1; } } if ((do_clear || run < 7) && !clear_pos) { clear_pos = pos - (run + 1); clear_bufpos = bufpos; } else if (!do_clear && run > 50) clear_pos = clear_bufpos = 0; if (do_clear) { GIF_DEBUG(("rewind %u pixels/%d bits", pos - clear_pos, bufpos + cur_code_bits - clear_bufpos)); output_code = CLEAR_CODE; pos = clear_pos; imageline = gif_imageline(gfi, pos); line_endpos = gif_line_endpos(gfi, pos); bufpos = clear_bufpos; buf[bufpos >> 3] &= (1 << (bufpos & 7)) - 1; work_node = 0; run = 0; grr->cleared = 1; goto found_output_code; } } /* Adjust current run length average. */ run = (run << RUN_EWMA_SCALE) + (1 << (RUN_EWMA_SHIFT - 1)); if (run < run_ewma) run_ewma -= (run_ewma - run) >> RUN_EWMA_SHIFT; else run_ewma += (run - run_ewma) >> RUN_EWMA_SHIFT; /* Output the current code. */ output_code = work_node->code; work_node = &gfc->nodes[suffix]; run = 1; goto found_output_code; } work_node = next_node; ++run; } /* Ran out of data if we get here. */ output_code = (work_node ? work_node->code : EOI_CODE); work_node = 0; run = 0; found_output_code: ; } /* Output memory buffer to stream. */ { unsigned outpos = 0; bufpos = (bufpos + 7) >> 3; while (outpos < bufpos) { unsigned w = (bufpos - outpos > 255 ? 255 : bufpos - outpos); gifputbyte(w, grr); gifputblock(buf + outpos, w, grr); outpos += w; } gifputbyte(0, grr); } if (buf != stack_buffer) Gif_DeleteArray(buf); return 1; } static int calculate_min_code_bits(Gif_Image *gfi, const Gif_Writer *grr) { int colors_used = -1, min_code_bits, i; if (grr->gcinfo.flags & GIF_WRITE_CAREFUL_MIN_CODE_SIZE) { /* calculate m_c_b based on colormap */ if (grr->local_size > 0) colors_used = grr->local_size; else if (grr->global_size > 0) colors_used = grr->global_size; } else if (gfi->img) { /* calculate m_c_b from uncompressed data */ int x, y, width = gfi->width, height = gfi->height; colors_used = 0; for (y = 0; y < height && colors_used < 128; y++) { uint8_t *data = gfi->img[y]; for (x = width; x > 0; x--, data++) if (*data > colors_used) colors_used = *data; } colors_used++; } else if (gfi->compressed) { /* take m_c_b from compressed image */ colors_used = 1 << gfi->compressed[0]; } else { /* should never happen */ colors_used = 256; } min_code_bits = 2; /* min_code_bits of 1 isn't allowed */ i = 4; while (i < colors_used) { min_code_bits++; i *= 2; } return min_code_bits; } static int get_color_table_size(const Gif_Stream *gfs, Gif_Image *gfi, Gif_Writer *grr); static void save_compression_result(Gif_Image *gfi, Gif_Writer *grr, int ok) { if (!(grr->gcinfo.flags & GIF_WRITE_SHRINK) || (ok && (!gfi->compressed || gfi->compressed_len > grr->pos))) { if (gfi->compressed) (*gfi->free_compressed)((void *) gfi->compressed); if (ok) { gfi->compressed = grr->v; gfi->compressed_len = grr->pos; gfi->free_compressed = Gif_DeleteArrayFunc; grr->v = 0; grr->cap = 0; } else gfi->compressed = 0; } grr->pos = 0; } int Gif_FullCompressImage(Gif_Stream *gfs, Gif_Image *gfi, const Gif_CompressInfo *gcinfo) { int ok = 0; uint8_t min_code_bits; Gif_Writer grr; Gif_CodeTable gfc; gfc_init(&gfc); grr.v = NULL; grr.pos = grr.cap = 0; grr.byte_putter = memory_byte_putter; grr.block_putter = memory_block_putter; if (gcinfo) grr.gcinfo = *gcinfo; else Gif_InitCompressInfo(&grr.gcinfo); grr.global_size = get_color_table_size(gfs, 0, &grr); grr.local_size = get_color_table_size(gfs, gfi, &grr); grr.errors = 0; if (!gfc.nodes || !gfc.links) { if (!(grr.gcinfo.flags & GIF_WRITE_SHRINK)) Gif_ReleaseCompressedImage(gfi); goto done; } min_code_bits = calculate_min_code_bits(gfi, &grr); ok = write_compressed_data(gfi, min_code_bits, &gfc, &grr); save_compression_result(gfi, &grr, ok); if ((grr.gcinfo.flags & (GIF_WRITE_OPTIMIZE | GIF_WRITE_EAGER_CLEAR)) == GIF_WRITE_OPTIMIZE && grr.cleared && ok) { grr.gcinfo.flags |= GIF_WRITE_EAGER_CLEAR | GIF_WRITE_SHRINK; if (write_compressed_data(gfi, min_code_bits, &gfc, &grr)) save_compression_result(gfi, &grr, 1); } done: Gif_DeleteArray(grr.v); Gif_DeleteArray(gfc.nodes); Gif_DeleteArray(gfc.links); return grr.v != 0; } static int get_color_table_size(const Gif_Stream *gfs, Gif_Image *gfi, Gif_Writer *grr) { Gif_Colormap *gfcm = (gfi ? gfi->local : gfs->global); int ncol, totalcol, i; if (!gfcm || gfcm->ncol <= 0) return 0; /* Make sure ncol is reasonable */ ncol = gfcm->ncol; /* Possibly bump up 'ncol' based on 'transparent' values, if careful_min_code_bits */ if (grr->gcinfo.flags & GIF_WRITE_CAREFUL_MIN_CODE_SIZE) { if (gfi && gfi->transparent >= ncol) ncol = gfi->transparent + 1; else if (!gfi) for (i = 0; i < gfs->nimages; i++) if (gfs->images[i]->transparent >= ncol) ncol = gfs->images[i]->transparent + 1; } /* Make sure the colormap is a power of two entries! */ /* GIF format doesn't allow a colormap with only 1 entry. */ if (ncol > 256) ncol = 256; for (totalcol = 2; totalcol < ncol; totalcol *= 2) /* nada */; return totalcol; } static void write_color_table(Gif_Colormap *gfcm, int totalcol, Gif_Writer *grr) { Gif_Color *c = gfcm->col; int i, ncol = gfcm->ncol; for (i = 0; i < ncol && i < totalcol; i++, c++) { gifputbyte(c->gfc_red, grr); gifputbyte(c->gfc_green, grr); gifputbyte(c->gfc_blue, grr); } /* Pad out colormap with black. */ for (; i < totalcol; i++) { gifputbyte(0, grr); gifputbyte(0, grr); gifputbyte(0, grr); } } static int write_image(Gif_Stream *gfs, Gif_Image *gfi, Gif_CodeTable *gfc, Gif_Writer *grr) { uint8_t min_code_bits, packed = 0; grr->local_size = get_color_table_size(gfs, gfi, grr); gifputbyte(',', grr); gifputunsigned(gfi->left, grr); gifputunsigned(gfi->top, grr); gifputunsigned(gfi->width, grr); gifputunsigned(gfi->height, grr); if (grr->local_size > 0) { int size = 2; packed |= 0x80; while (size < grr->local_size) size *= 2, packed++; } if (gfi->interlace) packed |= 0x40; gifputbyte(packed, grr); if (grr->local_size > 0) write_color_table(gfi->local, grr->local_size, grr); /* calculate min_code_bits here (because calculation may involve recompression, if GIF_WRITE_CAREFUL_MIN_CODE_SIZE is true) */ min_code_bits = calculate_min_code_bits(gfi, grr); /* use existing compressed data if it exists. This will tend to whip people's asses who uncompress an image, keep the compressed data around, but modify the uncompressed data anyway. That sucks. */ if (gfi->compressed && (!(grr->gcinfo.flags & GIF_WRITE_CAREFUL_MIN_CODE_SIZE) || gfi->compressed[0] == min_code_bits)) { uint8_t *compressed = gfi->compressed; uint32_t compressed_len = gfi->compressed_len; while (compressed_len > 0) { uint16_t amt = (compressed_len > 0x7000 ? 0x7000 : compressed_len); gifputblock(compressed, amt, grr); compressed += amt; compressed_len -= amt; } } else if (!gfi->img) { Gif_UncompressImage(gfi); write_compressed_data(gfi, min_code_bits, gfc, grr); Gif_ReleaseUncompressedImage(gfi); } else write_compressed_data(gfi, min_code_bits, gfc, grr); return 1; } static void write_logical_screen_descriptor(Gif_Stream *gfs, Gif_Writer *grr) { uint8_t packed = 0x70; /* high resolution colors */ grr->global_size = get_color_table_size(gfs, 0, grr); Gif_CalculateScreenSize(gfs, 0); gifputunsigned(gfs->screen_width, grr); gifputunsigned(gfs->screen_height, grr); if (grr->global_size > 0) { uint16_t size = 2; packed |= 0x80; while (size < grr->global_size) size *= 2, packed++; } gifputbyte(packed, grr); gifputbyte(gfs->background, grr); gifputbyte(0, grr); /* no aspect ratio information */ if (grr->global_size > 0) write_color_table(gfs->global, grr->global_size, grr); } /* extension byte table: 0x01 plain text extension 0xCE name* 0xF9 graphic control extension 0xFE comment extension 0xFF application extension */ static void write_graphic_control_extension(Gif_Image *gfi, Gif_Writer *grr) { uint8_t packed = 0; gifputbyte('!', grr); gifputbyte(0xF9, grr); gifputbyte(4, grr); if (gfi->transparent >= 0) packed |= 0x01; packed |= (gfi->disposal & 0x07) << 2; gifputbyte(packed, grr); gifputunsigned(gfi->delay, grr); gifputbyte((uint8_t)gfi->transparent, grr); gifputbyte(0, grr); } static void blast_data(const uint8_t *data, int len, Gif_Writer *grr) { while (len > 0) { int s = len > 255 ? 255 : len; gifputbyte(s, grr); gifputblock(data, s, grr); data += s; len -= s; } gifputbyte(0, grr); } static void write_name_extension(char *id, Gif_Writer *grr) { gifputbyte('!', grr); gifputbyte(0xCE, grr); blast_data((uint8_t *)id, strlen(id), grr); } static void write_comment_extensions(Gif_Comment *gfcom, Gif_Writer *grr) { int i; for (i = 0; i < gfcom->count; i++) { gifputbyte('!', grr); gifputbyte(0xFE, grr); blast_data((const uint8_t *)gfcom->str[i], gfcom->len[i], grr); } } static void write_netscape_loop_extension(uint16_t value, Gif_Writer *grr) { gifputblock((const uint8_t *)"!\xFF\x0BNETSCAPE2.0\x03\x01", 16, grr); gifputunsigned(value, grr); gifputbyte(0, grr); } static void write_generic_extension(Gif_Extension *gfex, Gif_Writer *grr) { uint32_t pos = 0; if (gfex->kind < 0) return; /* ignore our private extensions */ gifputbyte('!', grr); gifputbyte(gfex->kind, grr); if (gfex->kind == 255) { /* an application extension */ int len = gfex->application ? strlen(gfex->application) : 0; if (len) { gifputbyte(len, grr); gifputblock((const uint8_t *)gfex->application, len, grr); } } while (pos + 255 < gfex->length) { gifputbyte(255, grr); gifputblock(gfex->data + pos, 255, grr); pos += 255; } if (pos < gfex->length) { uint32_t len = gfex->length - pos; gifputbyte(len, grr); gifputblock(gfex->data + pos, len, grr); } gifputbyte(0, grr); } static int write_gif(Gif_Stream *gfs, Gif_Writer *grr) { int ok = 0; int i; Gif_Image *gfi; Gif_Extension *gfex = gfs->extensions; Gif_CodeTable gfc; gfc_init(&gfc); if (!gfc.nodes || !gfc.links) goto done; { uint8_t isgif89a = 0; if (gfs->comment || gfs->loopcount > -1) isgif89a = 1; for (i = 0; i < gfs->nimages && !isgif89a; i++) { gfi = gfs->images[i]; if (gfi->identifier || gfi->transparent != -1 || gfi->disposal || gfi->delay || gfi->comment) isgif89a = 1; } if (isgif89a) gifputblock((const uint8_t *)"GIF89a", 6, grr); else gifputblock((const uint8_t *)"GIF87a", 6, grr); } write_logical_screen_descriptor(gfs, grr); if (gfs->loopcount > -1) write_netscape_loop_extension(gfs->loopcount, grr); for (i = 0; i < gfs->nimages; i++) { Gif_Image *gfi = gfs->images[i]; while (gfex && gfex->position == i) { write_generic_extension(gfex, grr); gfex = gfex->next; } if (gfi->comment) write_comment_extensions(gfi->comment, grr); if (gfi->identifier) write_name_extension(gfi->identifier, grr); if (gfi->transparent != -1 || gfi->disposal || gfi->delay) write_graphic_control_extension(gfi, grr); if (!write_image(gfs, gfi, &gfc, grr)) goto done; } while (gfex) { write_generic_extension(gfex, grr); gfex = gfex->next; } if (gfs->comment) write_comment_extensions(gfs->comment, grr); gifputbyte(';', grr); ok = 1; done: Gif_DeleteArray(gfc.nodes); Gif_DeleteArray(gfc.links); return ok; } int Gif_FullWriteFile(Gif_Stream *gfs, const Gif_CompressInfo *gcinfo, FILE *f) { Gif_Writer grr; grr.f = f; grr.byte_putter = file_byte_putter; grr.block_putter = file_block_putter; if (gcinfo) grr.gcinfo = *gcinfo; else Gif_InitCompressInfo(&grr.gcinfo); grr.errors = 0; return write_gif(gfs, &grr); } #undef Gif_CompressImage #undef Gif_WriteFile int Gif_CompressImage(Gif_Stream *gfs, Gif_Image *gfi) { return Gif_FullCompressImage(gfs, gfi, 0); } int Gif_WriteFile(Gif_Stream *gfs, FILE *f) { return Gif_FullWriteFile(gfs, 0, f); } #ifdef __cplusplus } #endif gifsicle-1.78/src/fmalloc.c0000644000175000017500000000134712237442106012535 00000000000000#ifdef HAVE_CONFIG_H # include #endif #include #include #ifdef __cplusplus extern "C" { #endif static void fail_die_malloc_die(size_t size, const char *file, int line) { fprintf(stderr, "Out of memory! (wanted %lu at %s:%d)\n", (unsigned long)size, file, line); exit(1); } void * fail_die_malloc(size_t size, const char *file, int line) { void *p = malloc(size); if (!p && size) fail_die_malloc_die(size, file, line); return p; } void * fail_die_realloc(void *p, size_t size, const char *file, int line) { if (!p) return fail_die_malloc(size, file, line); p = realloc(p, size); if (!p && size) fail_die_malloc_die(size, file, line); return p; } #ifdef __cplusplus } #endif gifsicle-1.78/src/win32cfg.h0000644000175000017500000001037212251251477012552 00000000000000/* Hand-edited file based on config.h.in */ /* config.h.in. Generated from configure.ac by autoheader. */ #ifndef GIFSICLE_CONFIG_H #define GIFSICLE_CONFIG_H /* Define when using the debugging malloc library. */ /* #undef DMALLOC */ /* Define to the number of arguments to gettimeofday (gifview only). */ /* #undef GETTIMEOFDAY_PROTO */ /* Define if GIF LZW compression is off. */ /* #undef GIF_UNGIF */ /* Define to 1 if you have the header file. */ /* #undef HAVE_INTTYPES_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_MEMORY_H */ /* Define to 1 if you have the `mkstemp' function. */ /* #undef HAVE_MKSTEMP */ /* Define to 1 if you have the header file. */ /* #undef HAVE_STDINT_H */ /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_STRINGS_H */ /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strtoul' function. */ #define HAVE_STRTOUL 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SELECT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_STAT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TYPES_H */ /* Define to 1 if the system has the type `uintptr_t'. */ /* #undef HAVE_UINTPTR_T */ /* Define to 1 if you have the header file. */ /* #undef HAVE_UNISTD_H */ /* Define if you have u_intXX_t types but not uintXX_t types. */ /* #undef HAVE_U_INT_TYPES */ /* Define to write GIFs to stdout even when stdout is a terminal. */ /* #undef OUTPUT_GIF_TO_TERMINAL */ /* Name of package */ #define PACKAGE "gifsicle" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "" /* Define to the full name of this package. */ #define PACKAGE_NAME "gifsicle" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "gifsicle 1.78" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "gifsicle" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "1.78" /* Pathname separator character ('/' on Unix). */ #define PATHNAME_SEPARATOR '\\' /* Define to a function that returns a random number. */ #define RANDOM rand /* The size of `unsigned int', as computed by sizeof. */ #define SIZEOF_UNSIGNED_INT 4 /* The size of `unsigned long', as computed by sizeof. */ #ifdef _WIN64 #define SIZEOF_UNSIGNED_LONG 8 #else #define SIZEOF_UNSIGNED_LONG 4 #endif /* The size of `void *', as computed by sizeof. */ #ifdef _WIN64 #define SIZEOF_VOID_P 8 #else #define SIZEOF_VOID_P 4 #endif /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "1.78 (Windows)" /* Define if X is not available. */ #define X_DISPLAY_MISSING 1 /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus # ifndef inline # define inline __inline # endif #endif /* Windows doesn't have popen, but it does have _popen. */ #define popen _popen #define pclose _pclose #ifdef __cplusplus extern "C" { #endif /* Use either the clean-failing malloc library in fmalloc.c, or the debugging malloc library in dmalloc.c. */ #ifdef DMALLOC # include "dmalloc.h" # define Gif_DeleteFunc (&debug_free) # define Gif_DeleteArrayFunc (&debug_free) #else # include # define xmalloc(s) fail_die_malloc((s),__FILE__,__LINE__) # define xrealloc(p,s) fail_die_realloc((p),(s),__FILE__,__LINE__) # define xfree free void *fail_die_malloc(size_t, const char *, int); void *fail_die_realloc(void *, size_t, const char *, int); #endif /* Prototype strerror if we don't have it. */ #ifndef HAVE_STRERROR char *strerror(int errno); #endif #ifdef __cplusplus } /* Get rid of a possible inline macro under C++. */ # define inline inline #endif #endif /* GIFSICLE_CONFIG_H */ gifsicle-1.78/src/giffunc.c0000644000175000017500000004024212237442106012536 00000000000000/* giffunc.c - General functions for the GIF library. Copyright (C) 1997-2013 Eddie Kohler, kohler@cs.ucla.edu This file is part of the LCDF GIF library. The LCDF GIF library is free software. It is distributed under the GNU General Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #ifdef __cplusplus extern "C" { #endif Gif_Stream * Gif_NewStream(void) { Gif_Stream *gfs = Gif_New(Gif_Stream); if (!gfs) return 0; gfs->global = 0; gfs->background = 0; gfs->screen_width = gfs->screen_height = 0; gfs->loopcount = -1; gfs->comment = 0; gfs->images = 0; gfs->nimages = gfs->imagescap = 0; gfs->extensions = 0; gfs->errors = 0; gfs->userflags = 0; gfs->refcount = 0; return gfs; } Gif_Image * Gif_NewImage(void) { Gif_Image *gfi = Gif_New(Gif_Image); if (!gfi) return 0; gfi->identifier = 0; gfi->comment = 0; gfi->local = 0; gfi->transparent = -1; gfi->disposal = GIF_DISPOSAL_NONE; gfi->delay = 0; gfi->left = gfi->top = gfi->width = gfi->height = 0; gfi->interlace = 0; gfi->img = 0; gfi->image_data = 0; gfi->free_image_data = Gif_DeleteArrayFunc; gfi->compressed_len = 0; gfi->compressed = 0; gfi->free_compressed = 0; gfi->user_data = 0; gfi->free_user_data = 0; gfi->refcount = 0; return gfi; } Gif_Colormap * Gif_NewColormap(void) { Gif_Colormap *gfcm = Gif_New(Gif_Colormap); if (!gfcm) return 0; gfcm->ncol = 0; gfcm->capacity = 0; gfcm->col = 0; gfcm->refcount = 0; gfcm->userflags = 0; return gfcm; } Gif_Colormap * Gif_NewFullColormap(int count, int capacity) { Gif_Colormap *gfcm = Gif_New(Gif_Colormap); if (!gfcm || capacity <= 0 || count < 0) return 0; if (count > capacity) capacity = count; gfcm->ncol = count; gfcm->capacity = capacity; gfcm->col = Gif_NewArray(Gif_Color, capacity); gfcm->refcount = 0; gfcm->userflags = 0; if (!gfcm->col) { Gif_Delete(gfcm); return 0; } else return gfcm; } Gif_Comment * Gif_NewComment(void) { Gif_Comment *gfcom = Gif_New(Gif_Comment); if (!gfcom) return 0; gfcom->str = 0; gfcom->len = 0; gfcom->count = gfcom->cap = 0; return gfcom; } Gif_Extension * Gif_NewExtension(int kind, const char *app_name) { Gif_Extension *gfex = Gif_New(Gif_Extension); if (!gfex) return 0; gfex->kind = app_name ? 255 : kind; gfex->application = Gif_CopyString(app_name); gfex->data = 0; gfex->position = 0; gfex->stream = 0; gfex->next = 0; gfex->free_data = 0; if (!gfex->application && app_name) { Gif_DeleteExtension(gfex); return 0; } return gfex; } char * Gif_CopyString(const char *s) { int l; char *copy; if (!s) return 0; l = strlen(s); copy = Gif_NewArray(char, l + 1); if (!copy) return 0; memcpy(copy, s, l + 1); return copy; } int Gif_AddImage(Gif_Stream *gfs, Gif_Image *gfi) { if (gfs->nimages >= gfs->imagescap) { if (gfs->imagescap) gfs->imagescap *= 2; else gfs->imagescap = 2; Gif_ReArray(gfs->images, Gif_Image *, gfs->imagescap); if (!gfs->images) return 0; } gfs->images[gfs->nimages] = gfi; gfs->nimages++; gfi->refcount++; return 1; } void Gif_RemoveImage(Gif_Stream *gfs, int inum) { int j; if (inum < 0 || inum >= gfs->nimages) return; Gif_DeleteImage(gfs->images[inum]); for (j = inum; j < gfs->nimages - 1; j++) gfs->images[j] = gfs->images[j+1]; gfs->nimages--; } int Gif_AddCommentTake(Gif_Comment *gfcom, char *x, int xlen) { if (gfcom->count >= gfcom->cap) { if (gfcom->cap) gfcom->cap *= 2; else gfcom->cap = 2; Gif_ReArray(gfcom->str, char *, gfcom->cap); Gif_ReArray(gfcom->len, int, gfcom->cap); if (!gfcom->str || !gfcom->len) return 0; } if (xlen < 0) xlen = strlen(x); gfcom->str[ gfcom->count ] = x; gfcom->len[ gfcom->count ] = xlen; gfcom->count++; return 1; } int Gif_AddComment(Gif_Comment *gfcom, const char *x, int xlen) { char *new_x; if (xlen < 0) xlen = strlen(x); new_x = Gif_NewArray(char, xlen); if (!new_x) return 0; memcpy(new_x, x, xlen); if (Gif_AddCommentTake(gfcom, new_x, xlen) == 0) { Gif_DeleteArray(new_x); return 0; } else return 1; } int Gif_AddExtension(Gif_Stream *gfs, Gif_Extension *gfex, int pos) { Gif_Extension *prev, *trav; if (gfex->stream) return 0; for (prev = 0, trav = gfs->extensions; trav && trav->position <= pos; prev = trav, trav = trav->next) ; if (prev) prev->next = gfex; else gfs->extensions = gfex; gfex->next = trav; return 1; } int Gif_ImageNumber(Gif_Stream *gfs, Gif_Image *gfi) { int i; for (i = 0; i < gfs->nimages; i++) if (gfs->images[i] == gfi) return i; return -1; } void Gif_CalculateScreenSize(Gif_Stream *gfs, int force) { int i; int screen_width = 0; int screen_height = 0; for (i = 0; i < gfs->nimages; i++) { Gif_Image *gfi = gfs->images[i]; /* 17.Dec.1999 - I find this old behavior annoying. */ /* if (gfi->left != 0 || gfi->top != 0) continue; */ if (screen_width < gfi->left + gfi->width) screen_width = gfi->left + gfi->width; if (screen_height < gfi->top + gfi->height) screen_height = gfi->top + gfi->height; } /* Only use the default 640x480 screen size if we are being forced to create a new screen size or there's no screen size currently. */ if (screen_width == 0 && (gfs->screen_width == 0 || force)) screen_width = 640; if (screen_height == 0 && (gfs->screen_height == 0 || force)) screen_height = 480; if (gfs->screen_width < screen_width || force) gfs->screen_width = screen_width; if (gfs->screen_height < screen_height || force) gfs->screen_height = screen_height; } Gif_Stream * Gif_CopyStreamSkeleton(Gif_Stream *gfs) { Gif_Stream *ngfs = Gif_NewStream(); if (!ngfs) return 0; ngfs->global = Gif_CopyColormap(gfs->global); ngfs->background = gfs->background; ngfs->screen_width = gfs->screen_width; ngfs->screen_height = gfs->screen_height; ngfs->loopcount = gfs->loopcount; if (gfs->global && !ngfs->global) { Gif_DeleteStream(ngfs); return 0; } else return ngfs; } Gif_Stream * Gif_CopyStreamImages(Gif_Stream *gfs) { Gif_Stream *ngfs = Gif_CopyStreamSkeleton(gfs); int i; if (!ngfs) return 0; for (i = 0; i < gfs->nimages; i++) { Gif_Image *gfi = Gif_CopyImage(gfs->images[i]); if (!gfi || !Gif_AddImage(ngfs, gfi)) { Gif_DeleteStream(ngfs); return 0; } } return ngfs; } Gif_Colormap * Gif_CopyColormap(Gif_Colormap *src) { Gif_Colormap *dest; if (!src) return 0; dest = Gif_NewFullColormap(src->ncol, src->capacity); if (!dest) return 0; memcpy(dest->col, src->col, sizeof(src->col[0]) * src->ncol); return dest; } Gif_Image * Gif_CopyImage(Gif_Image *src) { Gif_Image *dest; uint8_t *data; int i; if (!src) return 0; dest = Gif_NewImage(); if (!dest) return 0; dest->identifier = Gif_CopyString(src->identifier); if (!dest->identifier && src->identifier) goto failure; if (src->comment) { dest->comment = Gif_NewComment(); if (!dest->comment) goto failure; for (i = 0; i < src->comment->count; i++) if (!Gif_AddComment(dest->comment, src->comment->str[i], src->comment->len[i])) goto failure; } dest->local = Gif_CopyColormap(src->local); if (!dest->local && src->local) goto failure; dest->transparent = src->transparent; dest->delay = src->delay; dest->disposal = src->disposal; dest->left = src->left; dest->top = src->top; dest->width = src->width; dest->height = src->height; dest->interlace = src->interlace; if (src->img) { dest->img = Gif_NewArray(uint8_t *, dest->height + 1); dest->image_data = Gif_NewArray(uint8_t, dest->width * dest->height); dest->free_image_data = Gif_DeleteArrayFunc; if (!dest->img || !dest->image_data) goto failure; for (i = 0, data = dest->image_data; i < dest->height; i++) { memcpy(data, src->img[i], dest->width); dest->img[i] = data; data += dest->width; } dest->img[dest->height] = 0; } if (src->compressed) { if (src->free_compressed == 0) dest->compressed = src->compressed; else { dest->compressed = Gif_NewArray(uint8_t, src->compressed_len); dest->free_compressed = Gif_DeleteArrayFunc; memcpy(dest->compressed, src->compressed, src->compressed_len); } dest->compressed_len = src->compressed_len; } return dest; failure: Gif_DeleteImage(dest); return 0; } /** DELETION **/ typedef struct Gif_DeletionHook { int kind; Gif_DeletionHookFunc func; void *callback_data; struct Gif_DeletionHook *next; } Gif_DeletionHook; static Gif_DeletionHook *all_hooks; void Gif_DeleteStream(Gif_Stream *gfs) { Gif_Extension *gfex; Gif_DeletionHook *hook; int i; if (!gfs || --gfs->refcount > 0) return; Gif_DeleteColormap(gfs->global); Gif_DeleteComment(gfs->comment); for (i = 0; i < gfs->nimages; i++) Gif_DeleteImage(gfs->images[i]); Gif_DeleteArray(gfs->images); gfex = gfs->extensions; while (gfex) { Gif_Extension *next = gfex->next; gfex->stream = 0; Gif_DeleteExtension(gfex); gfex = next; } for (hook = all_hooks; hook; hook = hook->next) if (hook->kind == GIF_T_STREAM) (*hook->func)(GIF_T_STREAM, gfs, hook->callback_data); Gif_Delete(gfs); } void Gif_DeleteImage(Gif_Image *gfi) { Gif_DeletionHook *hook; if (!gfi || --gfi->refcount > 0) return; for (hook = all_hooks; hook; hook = hook->next) if (hook->kind == GIF_T_IMAGE) (*hook->func)(GIF_T_IMAGE, gfi, hook->callback_data); Gif_DeleteArray(gfi->identifier); Gif_DeleteComment(gfi->comment); Gif_DeleteColormap(gfi->local); if (gfi->image_data && gfi->free_image_data) (*gfi->free_image_data)((void *)gfi->image_data); Gif_DeleteArray(gfi->img); if (gfi->compressed && gfi->free_compressed) (*gfi->free_compressed)((void *)gfi->compressed); if (gfi->user_data && gfi->free_user_data) (*gfi->free_user_data)(gfi->user_data); Gif_Delete(gfi); } void Gif_DeleteColormap(Gif_Colormap *gfcm) { Gif_DeletionHook *hook; if (!gfcm || --gfcm->refcount > 0) return; for (hook = all_hooks; hook; hook = hook->next) if (hook->kind == GIF_T_COLORMAP) (*hook->func)(GIF_T_COLORMAP, gfcm, hook->callback_data); Gif_DeleteArray(gfcm->col); Gif_Delete(gfcm); } void Gif_DeleteComment(Gif_Comment *gfcom) { int i; if (!gfcom) return; for (i = 0; i < gfcom->count; i++) Gif_DeleteArray(gfcom->str[i]); Gif_DeleteArray(gfcom->str); Gif_DeleteArray(gfcom->len); Gif_Delete(gfcom); } void Gif_DeleteExtension(Gif_Extension *gfex) { if (!gfex) return; if (gfex->data && gfex->free_data) (*gfex->free_data)(gfex->data); Gif_DeleteArray(gfex->application); if (gfex->stream) { Gif_Stream *gfs = gfex->stream; Gif_Extension *prev, *trav; for (prev = 0, trav = gfs->extensions; trav && trav != gfex; prev = trav, trav = trav->next) ; if (trav) { if (prev) prev->next = trav->next; else gfs->extensions = trav->next; } } Gif_Delete(gfex); } /** DELETION HOOKS **/ int Gif_AddDeletionHook(int kind, void (*func)(int, void *, void *), void *cb) { Gif_DeletionHook *hook = Gif_New(Gif_DeletionHook); if (!hook) return 0; Gif_RemoveDeletionHook(kind, func, cb); hook->kind = kind; hook->func = func; hook->callback_data = cb; hook->next = all_hooks; all_hooks = hook; return 1; } void Gif_RemoveDeletionHook(int kind, void (*func)(int, void *, void *), void *cb) { Gif_DeletionHook *hook = all_hooks, *prev = 0; while (hook) { if (hook->kind == kind && hook->func == func && hook->callback_data == cb) { if (prev) prev->next = hook->next; else all_hooks = hook->next; Gif_Delete(hook); return; } prev = hook; hook = hook->next; } } int Gif_ColorEq(Gif_Color *c1, Gif_Color *c2) { return GIF_COLOREQ(c1, c2); } int Gif_FindColor(Gif_Colormap *gfcm, Gif_Color *c) { int i; for (i = 0; i < gfcm->ncol; i++) if (GIF_COLOREQ(&gfcm->col[i], c)) return i; return -1; } int Gif_AddColor(Gif_Colormap *gfcm, Gif_Color *c, int look_from) { int i; if (look_from >= 0) for (i = look_from; i < gfcm->ncol; i++) if (GIF_COLOREQ(&gfcm->col[i], c)) return i; if (gfcm->ncol >= gfcm->capacity) { gfcm->capacity *= 2; Gif_ReArray(gfcm->col, Gif_Color, gfcm->capacity); if (gfcm->col == 0) return -1; } i = gfcm->ncol; gfcm->ncol++; gfcm->col[i] = *c; return i; } Gif_Image * Gif_GetImage(Gif_Stream *gfs, int imagenumber) { if (imagenumber >= 0 && imagenumber < gfs->nimages) return gfs->images[imagenumber]; else return 0; } Gif_Image * Gif_GetNamedImage(Gif_Stream *gfs, const char *name) { int i; if (!name) return gfs->nimages ? gfs->images[0] : 0; for (i = 0; i < gfs->nimages; i++) if (gfs->images[i]->identifier && strcmp(gfs->images[i]->identifier, name) == 0) return gfs->images[i]; return 0; } Gif_Extension * Gif_GetExtension(Gif_Stream *gfs, int id, Gif_Extension *search_from) { if (!search_from) search_from = gfs->extensions; while (search_from) { if (search_from->kind == id) return search_from; search_from = search_from->next; } return 0; } void Gif_ReleaseCompressedImage(Gif_Image *gfi) { if (gfi->compressed && gfi->free_compressed) (*gfi->free_compressed)(gfi->compressed); gfi->compressed = 0; gfi->compressed_len = 0; gfi->free_compressed = 0; } void Gif_ReleaseUncompressedImage(Gif_Image *gfi) { Gif_DeleteArray(gfi->img); if (gfi->image_data && gfi->free_image_data) (*gfi->free_image_data)(gfi->image_data); gfi->img = 0; gfi->image_data = 0; gfi->free_image_data = 0; } int Gif_ClipImage(Gif_Image *gfi, int left, int top, int width, int height) { int new_width = gfi->width, new_height = gfi->height; int y; if (!gfi->img) return 0; if (gfi->left < left) { int shift = left - gfi->left; for (y = 0; y < gfi->height; y++) gfi->img[y] += shift; gfi->left += shift; new_width -= shift; } if (gfi->top < top) { int shift = top - gfi->top; for (y = gfi->height - 1; y >= shift; y++) gfi->img[y - shift] = gfi->img[y]; gfi->top += shift; new_height -= shift; } if (gfi->left + new_width >= width) new_width = width - gfi->left; if (gfi->top + new_height >= height) new_height = height - gfi->top; if (new_width < 0) new_width = 0; if (new_height < 0) new_height = 0; gfi->width = new_width; gfi->height = new_height; return 1; } int Gif_InterlaceLine(int line, int height) { height--; if (line > height / 2) return line * 2 - ( height | 1); else if (line > height / 4) return line * 4 - ((height & ~1) | 2); else if (line > height / 8) return line * 8 - ((height & ~3) | 4); else return line * 8; } int Gif_SetUncompressedImage(Gif_Image *gfi, uint8_t *image_data, void (*free_data)(void *), int data_interlaced) { /* NB does not affect compressed image (and must not) */ int i; int width = gfi->width; int height = gfi->height; uint8_t **img; Gif_ReleaseUncompressedImage(gfi); if (!image_data) return 0; img = Gif_NewArray(uint8_t *, height + 1); if (!img) return 0; if (data_interlaced) for (i = 0; i < height; i++) img[ Gif_InterlaceLine(i, height) ] = image_data + width * i; else for (i = 0; i < height; i++) img[i] = image_data + width * i; img[height] = 0; gfi->img = img; gfi->image_data = image_data; gfi->free_image_data = free_data; return 1; } int Gif_CreateUncompressedImage(Gif_Image *gfi) { uint8_t *data = Gif_NewArray(uint8_t, gfi->width * gfi->height); return Gif_SetUncompressedImage(gfi, data, Gif_DeleteArrayFunc, gfi->interlace); } void Gif_InitCompressInfo(Gif_CompressInfo *gcinfo) { gcinfo->flags = 0; } void Gif_Debug(char *x, ...) { va_list val; va_start(val, x); vfprintf(stderr, x, val); fputc(' ', stderr); va_end(val); } #ifdef __cplusplus } #endif gifsicle-1.78/src/gifview.c0000644000175000017500000011303612244134622012556 00000000000000/* -*- c-basic-offset: 2 -*- */ /* gifview.c - gifview's main loop. Copyright (C) 1997-2013 Eddie Kohler, ekohler@gmail.com This file is part of gifview, in the gifsicle package. Gifview is free software. It is distributed under the GNU Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #include #ifdef X_DISPLAY_MISSING #error "You can't compile gifview without X." #endif #include #include #include #include #include #include #include #ifdef HAVE_SYS_SELECT_H # include #endif #include #include #include #include #include #include #include /* Need _setmode under MS-DOS, to set stdin/stdout to binary mode */ /* Need _fsetmode under OS/2 for the same reason */ #if defined(_MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(__DJGPP__) # include # include #endif #ifdef __cplusplus #define EXTERN extern "C" #else #define EXTERN extern #endif /***** * TIME STUFF (from xwrits) **/ #define MICRO_PER_SEC 1000000 #define xwADDTIME(result, a, b) do { \ (result).tv_sec = (a).tv_sec + (b).tv_sec; \ if (((result).tv_usec = (a).tv_usec + (b).tv_usec) >= MICRO_PER_SEC) { \ (result).tv_sec++; \ (result).tv_usec -= MICRO_PER_SEC; \ } } while (0) #define xwSUBTIME(result, a, b) do { \ (result).tv_sec = (a).tv_sec - (b).tv_sec; \ if (((result).tv_usec = (a).tv_usec - (b).tv_usec) < 0) { \ (result).tv_sec--; \ (result).tv_usec += MICRO_PER_SEC; \ } } while (0) #define xwSETMINTIME(a, b) do { \ if ((b).tv_sec < (a).tv_sec || \ ((b).tv_sec == (a).tv_sec && (b).tv_usec < (a).tv_usec)) \ (a) = (b); \ } while (0) #define xwTIMEGEQ(a, b) ((a).tv_sec > (b).tv_sec || \ ((a).tv_sec == (b).tv_sec && (a).tv_usec >= (b).tv_usec)) #define xwTIMEGT(a, b) ((a).tv_sec > (b).tv_sec || \ ((a).tv_sec == (b).tv_sec && (a).tv_usec > (b).tv_usec)) #define xwTIMELEQ0(a) ((a).tv_sec < 0 || ((a).tv_sec == 0 && (a).tv_usec <= 0)) #ifdef X_GETTIMEOFDAY # define xwGETTIMEOFDAY(a) X_GETTIMEOFDAY(a) #elif GETTIMEOFDAY_PROTO == 0 EXTERN int gettimeofday(struct timeval *, struct timezone *); # define xwGETTIMEOFDAY(a) gettimeofday((a), 0) #elif GETTIMEOFDAY_PROTO == 1 # define xwGETTIMEOFDAY(a) gettimeofday((a)) #else # define xwGETTIMEOFDAY(a) gettimeofday((a), 0) #endif #define xwGETTIME(a) do { xwGETTIMEOFDAY(&(a)); xwSUBTIME((a), (a), genesis_time); } while (0) struct timeval genesis_time; /***** * THE VIEWER STRUCTURE **/ static unsigned pixel_memory_limit_kb = 40000; static unsigned pixel_memory_kb; typedef struct Gt_Viewer { Display *display; int screen_number; Visual *visual; int depth; Colormap colormap; Gif_XContext *gfx; Cursor arrow_cursor; Cursor wait_cursor; Window parent; int top_level; Window window; int use_window; int width; int height; int resizable; int being_deleted; Gif_Stream *gfs; const char *name; const char *title; Gif_Image **im; int nim; Pixmap pixmap; int im_pos; int was_unoptimized; Gif_XFrame *unoptimized_frames; int n_unoptimized_frames; struct Gt_Viewer *next; int can_animate; int animating; int unoptimizing; int scheduled; int preparing; struct Gt_Viewer *anim_next; struct timeval timer; int anim_loop; } Gt_Viewer; const char *program_name = "gifview"; static const char *cur_display_name = 0; static Display *cur_display = 0; static const char *cur_geometry_spec = 0; static Cursor cur_arrow_cursor = 0; static Cursor cur_wait_cursor = 0; static const char *cur_resource_name; static const char *cur_window_title = 0; static Window cur_use_window = None; static int cur_use_window_new = 0; static const char *cur_background_color = "black"; static Gt_Viewer *viewers; static Gt_Viewer *animations; static int animating = 0; static int unoptimizing = 0; static int install_colormap = 0; static int interactive = 1; static int min_delay = 0; static int fallback_delay = 0; static struct timeval preparation_time; #define DISPLAY_OPT 300 #define UNOPTIMIZE_OPT 301 #define VERSION_OPT 302 #define ANIMATE_OPT 303 #define GEOMETRY_OPT 304 #define NAME_OPT 305 #define HELP_OPT 306 #define WINDOW_OPT 307 #define INSTALL_COLORMAP_OPT 308 #define INTERACTIVE_OPT 309 #define BACKGROUND_OPT 310 #define NEW_WINDOW_OPT 311 #define TITLE_OPT 312 #define MIN_DELAY_OPT 313 #define FALLBACK_DELAY_OPT 314 #define MEMORY_LIMIT_OPT 315 #define WINDOW_TYPE (Clp_ValFirstUser) const Clp_Option options[] = { { "animate", 'a', ANIMATE_OPT, 0, Clp_Negate }, { "background", 'b', BACKGROUND_OPT, Clp_ValString, 0 }, { "bg", 't', BACKGROUND_OPT, Clp_ValString, 0 }, { "display", 'd', DISPLAY_OPT, Clp_ValStringNotOption, 0 }, { "geometry", 'g', GEOMETRY_OPT, Clp_ValString, 0 }, { "install-colormap", 'i', INSTALL_COLORMAP_OPT, 0, Clp_Negate }, { "interactive", 'e', INTERACTIVE_OPT, 0, Clp_Negate }, { "help", 0, HELP_OPT, 0, 0 }, { "memory-limit", 0, MEMORY_LIMIT_OPT, Clp_ValUnsigned, Clp_Negate }, { "min-delay", 0, MIN_DELAY_OPT, Clp_ValInt, Clp_Negate }, { "fallback-delay", 0, FALLBACK_DELAY_OPT, Clp_ValInt, Clp_Negate }, { "name", 0, NAME_OPT, Clp_ValString, 0 }, { "title", 'T', TITLE_OPT, Clp_ValString, 0 }, { "unoptimize", 'U', UNOPTIMIZE_OPT, 0, Clp_Negate }, { "version", 0, VERSION_OPT, 0, 0 }, { "window", 'w', WINDOW_OPT, WINDOW_TYPE, 0 }, { "new-window", 0, NEW_WINDOW_OPT, WINDOW_TYPE, 0 } }; /***** * Diagnostics **/ void fatal_error(char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); fputc('\n', stderr); exit(1); } void error(char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: ", program_name); vfprintf(stderr, message, val); fputc('\n', stderr); } void warning(char *message, ...) { va_list val; va_start(val, message); fprintf(stderr, "%s: warning: ", program_name); vfprintf(stderr, message, val); fputc('\n', stderr); } void short_usage(void) { fprintf(stderr, "Usage: %s [--display DISPLAY] [OPTION]... [FILE | FRAME]...\n\ Try '%s --help' for more information.\n", program_name, program_name); } void usage(void) { printf("\ 'Gifview' is a lightweight GIF viewer for X. It can display animated GIFs as\n\ slideshows, one frame at a time, or as animations.\n\ \n\ Usage: %s [--display DISPLAY] [OPTION]... [FILE | FRAME]...\n\n", program_name); printf("\ Options are:\n\ -a, --animate Animate multiframe GIFs.\n\ -U, --unoptimize Unoptimize displayed GIFs.\n\ -d, --display DISPLAY Set display to DISPLAY.\n\ --name NAME Set application resource name to NAME.\n\ -g, --geometry GEOMETRY Set window geometry.\n\ -T, --title TITLE Set window title.\n"); printf("\ -w, --window WINDOW Show GIF in existing WINDOW.\n\ --new-window WINDOW Show GIF in new child of existing WINDOW.\n\ -i, --install-colormap Use a private colormap.\n\ --bg, --background COLOR Use COLOR for transparent pixels.\n\ --min-delay DELAY Set minimum frame delay to DELAY/100 sec.\n\ --fallback-delay DELAY Set fallback frame delay to DELAY/100 sec.\n\ +e, --no-interactive Ignore buttons and keystrokes.\n"); printf("\ --memory-limit LIM Cache at most LIM megabytes of animation.\n\ --help Print this message and exit.\n\ --version Print version number and exit.\n\ \n\ Frame selections: #num, #num1-num2, #num1-, #name\n\n"); printf("\ Keystrokes:\n\ [N]/[Space] Go to next frame. [P]/[B] Go to previous frame.\n\ [R]/[<] Go to first frame. [>] Go to last frame.\n\ [ESC] Stop animation. [S]/[A] Toggle animation.\n\ [U] Toggle unoptimization. [Backspace]/[W] Delete window.\n\ [Q] Quit.\n\ \n\ Left mouse button goes to next frame, right mouse button deletes window.\n\ \n\ Report bugs to .\n"); } /***** * Window creation **/ #if defined(__cplusplus) || defined(c_plusplus) #define VISUAL_CLASS c_class #else #define VISUAL_CLASS class #endif static void choose_visual(Gt_Viewer *viewer) { Display *display = viewer->display; int screen_number = viewer->screen_number; VisualID default_visualid = DefaultVisual(display, screen_number)->visualid; XVisualInfo visi_template; int nv, i; XVisualInfo *v, *best_v = 0; Gt_Viewer *trav; /* Look for an existing Gt_Viewer with the same display and screen number */ if (!install_colormap) for (trav = viewers; trav; trav = trav->next) if (trav != viewer && trav->display == display && trav->screen_number == screen_number) { viewer->visual = trav->visual; viewer->depth = trav->depth; viewer->colormap = trav->colormap; viewer->gfx = trav->gfx; viewer->gfx->refcount++; return; } /* Find the default visual's XVisualInfo & put it in best_v */ visi_template.screen = screen_number; v = XGetVisualInfo(display, VisualScreenMask, &visi_template, &nv); for (i = 0; i < nv && !best_v; i++) if (v[i].visualid == default_visualid) best_v = &v[i]; if (!best_v) { /* This should never happen. If we can't find the default visual's XVisualInfo, we just use the default visual */ viewer->visual = DefaultVisual(display, screen_number); viewer->depth = DefaultDepth(display, screen_number); viewer->colormap = DefaultColormap(display, screen_number); } else { /* Which visual to choose? This isn't exactly a simple decision, since we want to avoid colormap flashing while choosing a nice visual. So here's the algorithm: Prefer the default visual, or take a TrueColor visual with strictly greater depth. */ for (i = 0; i < nv; i++) if (v[i].depth > best_v->depth && v[i].VISUAL_CLASS == TrueColor) best_v = &v[i]; viewer->visual = best_v->visual; viewer->depth = best_v->depth; if (best_v->visualid != default_visualid || (best_v->VISUAL_CLASS == PseudoColor && install_colormap)) viewer->colormap = XCreateColormap(display, RootWindow(display, screen_number), viewer->visual, AllocNone); else viewer->colormap = DefaultColormap(display, screen_number); } viewer->gfx = Gif_NewXContextFromVisual (display, screen_number, viewer->visual, viewer->depth, viewer->colormap); viewer->gfx->refcount++; if (v) XFree(v); } Gt_Viewer * new_viewer(Display *display, Gif_Stream *gfs, const char *name) { Gt_Viewer *viewer; int i; /* Make the Gt_Viewer structure */ viewer = Gif_New(Gt_Viewer); viewer->display = display; if (cur_use_window) { XWindowAttributes attr; if (cur_use_window == (Window)(-1)) { /* means use root window */ viewer->screen_number = DefaultScreen(display); cur_use_window = RootWindow(display, viewer->screen_number); } XGetWindowAttributes(display, cur_use_window, &attr); viewer->screen_number = -1; for (i = 0; i < ScreenCount(display); i++) if (ScreenOfDisplay(display, i) == attr.screen) viewer->screen_number = i; assert(viewer->screen_number >= 0); viewer->visual = attr.visual; viewer->depth = attr.depth; viewer->colormap = attr.colormap; viewer->gfx = Gif_NewXContextFromVisual (display, viewer->screen_number, viewer->visual, viewer->depth, viewer->colormap); viewer->gfx->refcount++; /* Before -- use root window, if that's what we were given; otherwise, create a child of the window we were given */ /* 13.Nov.2001 - don't make a child of the window we were given! */ if (cur_use_window_new) { viewer->window = None; viewer->use_window = 0; } else { viewer->window = cur_use_window; viewer->use_window = 1; } viewer->parent = cur_use_window; viewer->top_level = 0; viewer->resizable = 0; } else { viewer->screen_number = DefaultScreen(display); choose_visual(viewer); viewer->window = None; viewer->parent = RootWindow(display, viewer->screen_number); viewer->use_window = 0; viewer->top_level = 1; viewer->resizable = 1; } /* assign background color */ if (cur_background_color) { XColor color; if (!XParseColor(viewer->display, viewer->colormap, cur_background_color, &color)) { error("invalid background color '%s'", cur_background_color); cur_background_color = 0; } else if (!XAllocColor(viewer->display, viewer->colormap, &color)) warning("can't allocate background color"); else { unsigned long pixel = color.pixel; Gif_XContext *gfx = viewer->gfx; if (pixel != gfx->transparent_pixel && gfx->refcount > 1) { /* copy X context */ viewer->gfx = Gif_NewXContextFromVisual (gfx->display, gfx->screen_number, gfx->visual, gfx->depth, gfx->colormap); viewer->gfx->refcount++; gfx->refcount--; } viewer->gfx->transparent_pixel = pixel; } } if (!cur_arrow_cursor) { cur_arrow_cursor = XCreateFontCursor(display, XC_left_ptr); cur_wait_cursor = XCreateFontCursor(display, XC_watch); } viewer->arrow_cursor = cur_arrow_cursor; viewer->wait_cursor = cur_wait_cursor; viewer->being_deleted = 0; viewer->gfs = gfs; gfs->refcount++; viewer->name = name; viewer->title = cur_window_title; viewer->nim = Gif_ImageCount(gfs); viewer->im = Gif_NewArray(Gif_Image *, viewer->nim); for (i = 0; i < viewer->nim; i++) viewer->im[i] = gfs->images[i]; viewer->pixmap = None; viewer->im_pos = -1; viewer->was_unoptimized = 0; viewer->unoptimized_frames = Gif_NewXFrames(gfs); viewer->n_unoptimized_frames = 0; viewer->next = viewers; viewers = viewer; viewer->animating = 0; viewer->unoptimizing = unoptimizing; viewer->scheduled = 0; viewer->preparing = 0; viewer->anim_next = 0; viewer->anim_loop = 0; viewer->timer.tv_sec = viewer->timer.tv_usec = 0; return viewer; } void delete_viewer(Gt_Viewer *viewer) { Gt_Viewer *prev = 0, *trav; if (viewer->pixmap && !viewer->was_unoptimized) XFreePixmap(viewer->display, viewer->pixmap); for (trav = viewers; trav != viewer; prev = trav, trav = trav->next) ; if (prev) prev->next = viewer->next; else viewers = viewer->next; Gif_DeleteXFrames(viewer->gfx, viewer->gfs, viewer->unoptimized_frames); Gif_DeleteStream(viewer->gfs); Gif_DeleteArray(viewer->im); Gif_DeleteXContext(viewer->gfx); Gif_Delete(viewer); } static Gt_Viewer * next_viewer(Gif_Stream *gfs, const char *name) { Gt_Viewer *viewer = new_viewer(cur_display, gfs, name); cur_use_window = None; return viewer; } static Gt_Viewer * get_input_stream(const char *name) { FILE *f; Gif_Stream *gfs = 0; if (name == 0 || strcmp(name, "-") == 0) { #ifndef OUTPUT_GIF_TO_TERMINAL extern int isatty(int); if (isatty(fileno(stdin))) { error(": is a terminal"); return NULL; } #endif f = stdin; #if defined(_MSDOS) || defined(_WIN32) _setmode(_fileno(stdin), _O_BINARY); #elif defined(__DJGPP__) setmode(fileno(stdin), O_BINARY); #elif defined(__EMX__) _fsetmode(stdin, "b"); #endif name = ""; } else f = fopen(name, "rb"); if (!f) { error("%s: %s", name, strerror(errno)); return 0; } gfs = Gif_FullReadFile(f, GIF_READ_COMPRESSED, 0, 0); fclose(f); if (!gfs || Gif_ImageCount(gfs) == 0) { error("'%s' doesn't seem to contain a GIF", name); Gif_DeleteStream(gfs); return 0; } if (!cur_display) { cur_display = XOpenDisplay(cur_display_name); if (!cur_display) { error("can't open display"); return 0; } } return next_viewer(gfs, name); } /***** * Schedule stuff **/ void switch_animating(Gt_Viewer *viewer, int animating) { int i; Gif_Stream *gfs = viewer->gfs; if (animating == viewer->animating || !viewer->can_animate) return; for (i = 0; i < gfs->nimages; i++) viewer->im[i] = gfs->images[i]; viewer->animating = animating; if (!animating) viewer->timer.tv_sec = viewer->timer.tv_usec = 0; } void unschedule(Gt_Viewer *viewer) { Gt_Viewer *prev, *trav; if (!viewer->scheduled) return; for (prev = 0, trav = animations; trav; prev = trav, trav = trav->anim_next) if (trav == viewer) break; if (trav) { if (prev) prev->anim_next = viewer->anim_next; else animations = viewer->anim_next; } viewer->scheduled = 0; viewer->timer.tv_sec = viewer->timer.tv_usec = 0; } void schedule(Gt_Viewer *viewer) { Gt_Viewer *prev, *trav; if (viewer->scheduled) unschedule(viewer); prev = 0; for (trav = animations; trav; prev = trav, trav = trav->anim_next) if (xwTIMEGEQ(trav->timer, viewer->timer)) break; if (prev) { viewer->anim_next = trav; prev->anim_next = viewer; } else { viewer->anim_next = animations; animations = viewer; } viewer->scheduled = 1; } void schedule_next_frame(Gt_Viewer *viewer) { struct timeval interval; int delay = viewer->im[viewer->im_pos]->delay; int next_pos = viewer->im_pos + 1; if (delay < 1) delay = fallback_delay; if (delay < min_delay) delay = min_delay; if (next_pos == viewer->nim) next_pos = 0; if (viewer->timer.tv_sec == 0 && viewer->timer.tv_usec == 0) xwGETTIME(viewer->timer); interval.tv_sec = delay / 100; interval.tv_usec = (delay % 100) * (MICRO_PER_SEC / 100); if (delay == 0) interval.tv_usec = 2000; xwADDTIME(viewer->timer, viewer->timer, interval); /* 1.Aug.2002 - leave some time to prepare the frame if necessary */ if (viewer->unoptimized_frames[next_pos].pixmap) { xwSUBTIME(viewer->timer, viewer->timer, preparation_time); viewer->preparing = 1; } schedule(viewer); } /***** * X stuff **/ int parse_geometry(const char *const_g, XSizeHints *sh, int screen_width, int screen_height) { char *g = (char *)const_g; sh->flags = 0; if (isdigit(*g)) { sh->flags |= USSize; sh->width = strtol(g, &g, 10); if (g[0] == 'x' && isdigit(g[1])) sh->height = strtol(g + 1, &g, 10); else goto error; } else if (!*g) goto error; if (*g == '+' || *g == '-') { int x_minus, y_minus; sh->flags |= USPosition | PWinGravity; x_minus = *g == '-'; sh->x = strtol(g + 1, &g, 10); if (x_minus) sh->x = screen_width - sh->x - sh->width; y_minus = *g == '-'; if (*g == '-' || *g == '+') sh->y = strtol(g + 1, &g, 10); else goto error; if (y_minus) sh->y = screen_height - sh->y - sh->height; if (x_minus) sh->win_gravity = y_minus ? SouthEastGravity : NorthEastGravity; else sh->win_gravity = y_minus ? SouthWestGravity : NorthWestGravity; } else if (*g) goto error; return 1; error: warning("bad geometry specification"); sh->flags = 0; return 0; } static Atom wm_delete_window_atom; static Atom wm_protocols_atom; void create_viewer_window(Gt_Viewer *viewer, int w, int h) { Display *display = viewer->display; char *stringlist[2]; XTextProperty window_name, icon_name; XClassHint classh; XSizeHints *sizeh = XAllocSizeHints(); /* sets all fields to 0 */ /* Set the window's geometry */ sizeh->width = w; sizeh->height = h; if (cur_geometry_spec) { int scr_width = DisplayWidth(viewer->display, viewer->screen_number); int scr_height = DisplayHeight(viewer->display, viewer->screen_number); parse_geometry(cur_geometry_spec, sizeh, scr_width, scr_height); } /* Open the display and create the window */ if (!viewer->window) { XSetWindowAttributes x_set_attr; unsigned long x_set_attr_mask; x_set_attr.colormap = viewer->colormap; x_set_attr.backing_store = NotUseful; x_set_attr.save_under = False; x_set_attr.border_pixel = 0; x_set_attr.background_pixel = 0; x_set_attr_mask = CWColormap | CWBorderPixel | CWBackPixel | CWBackingStore | CWSaveUnder; viewer->window = XCreateWindow (display, viewer->parent, sizeh->x, sizeh->y, sizeh->width, sizeh->height, 0, viewer->depth, InputOutput, viewer->visual, x_set_attr_mask, &x_set_attr); XDefineCursor(display, viewer->window, viewer->arrow_cursor); } /* If user gave us geometry, don't change the size later */ if (sizeh->flags & USSize) viewer->resizable = 0; viewer->width = w; viewer->height = h; /* Set the window's title and class (for window manager resources) */ if (viewer->top_level) { stringlist[0] = "gifview"; stringlist[1] = 0; XStringListToTextProperty(stringlist, 1, &window_name); XStringListToTextProperty(stringlist, 1, &icon_name); classh.res_name = (char *)cur_resource_name; classh.res_class = "Gifview"; XSetWMProperties(display, viewer->window, &window_name, &icon_name, NULL, 0, sizeh, NULL, &classh); XFree(window_name.value); XFree(icon_name.value); if (!wm_delete_window_atom) { wm_delete_window_atom = XInternAtom(display, "WM_DELETE_WINDOW", False); wm_protocols_atom = XInternAtom(display, "WM_PROTOCOLS", False); } XSetWMProtocols(display, viewer->window, &wm_delete_window_atom, 1); } if (interactive) XSelectInput(display, viewer->window, ButtonPressMask | KeyPressMask | StructureNotifyMask); else XSelectInput(display, viewer->window, StructureNotifyMask); XFree(sizeh); } void pre_delete_viewer(Gt_Viewer *viewer) { if (viewer->being_deleted) return; viewer->being_deleted = 1; if (viewer->scheduled) unschedule(viewer); if (viewer->window && !viewer->use_window) XDestroyWindow(viewer->display, viewer->window); else delete_viewer(viewer); } Gt_Viewer * find_viewer(Display *display, Window window) { Gt_Viewer *v; for (v = viewers; v; v = v->next) if (v->display == display && v->window == window) return v; return 0; } void set_viewer_name(Gt_Viewer *viewer, int slow_number) { Gif_Image *gfi; char *strs[2]; char *identifier; XTextProperty name_prop; int im_pos = (slow_number >= 0 ? slow_number : viewer->im_pos); int len; if (!viewer->top_level || im_pos >= viewer->nim || viewer->being_deleted) return; gfi = viewer->im[im_pos]; len = strlen(viewer->title) + strlen(viewer->name) + 14; identifier = (slow_number >= 0 ? (char *)0 : gfi->identifier); if (identifier) len += 2 + strlen(identifier); strs[0] = Gif_NewArray(char, len); if (strcmp(viewer->title, "gifview") != 0) strcpy(strs[0], viewer->title); else if (slow_number >= 0) sprintf(strs[0], "gifview: %s [#%d]", viewer->name, im_pos); else if (viewer->nim == 1 && identifier) sprintf(strs[0], "gifview: %s #%s", viewer->name, identifier); else if (viewer->animating || viewer->nim == 1) sprintf(strs[0], "gifview: %s", viewer->name); else if (!identifier) sprintf(strs[0], "gifview: %s #%d", viewer->name, im_pos); else sprintf(strs[0], "gifview: %s #%d #%s", viewer->name, im_pos, identifier); strs[1] = 0; XStringListToTextProperty(strs, 1, &name_prop); XSetWMName(viewer->display, viewer->window, &name_prop); XSetWMIconName(viewer->display, viewer->window, &name_prop); XFree(name_prop.value); Gif_DeleteArray(strs[0]); } static unsigned screen_memory_kb(const Gt_Viewer* viewer) { return 1 + ((unsigned) (viewer->gfs->screen_width * viewer->gfs->screen_height) / 334); } static Pixmap unoptimized_frame(Gt_Viewer *viewer, int frame, int slow) { /* create a new unoptimized frame if necessary */ if (!viewer->unoptimized_frames[frame].pixmap) { (void) Gif_XNextImage(viewer->gfx, viewer->gfs, frame, viewer->unoptimized_frames); pixel_memory_kb += screen_memory_kb(viewer); viewer->unoptimized_frames[viewer->n_unoptimized_frames].user_data = frame; ++viewer->n_unoptimized_frames; if (slow) { set_viewer_name(viewer, frame); XFlush(viewer->display); } } /* kill some old frames if over the memory limit */ while (pixel_memory_limit_kb != (unsigned) -1 && pixel_memory_limit_kb < pixel_memory_kb && viewer->n_unoptimized_frames > 1) { int killidx, killframe, i = 0; do { killidx = random() % viewer->n_unoptimized_frames; killframe = viewer->unoptimized_frames[killidx].user_data; ++i; } while (killframe == frame || (i < 10 && killframe > frame && killframe < frame + 5) || (i < 10 && (killframe % 50) == 0)); XFreePixmap(viewer->display, viewer->unoptimized_frames[killframe].pixmap); viewer->unoptimized_frames[killframe].pixmap = None; --viewer->n_unoptimized_frames; viewer->unoptimized_frames[killidx].user_data = viewer->unoptimized_frames[viewer->n_unoptimized_frames].user_data; pixel_memory_kb -= screen_memory_kb(viewer); } return viewer->unoptimized_frames[frame].pixmap; } void prepare_frame(Gt_Viewer *viewer, int frame) { Display *display = viewer->display; Window window = viewer->window; int changed_cursor = 0; if (viewer->being_deleted || !viewer->animating) return; if (frame < 0 || frame > viewer->nim - 1) frame = 0; /* Change cursor if we need to wait. */ if ((viewer->animating || viewer->unoptimizing) && !viewer->unoptimized_frames[frame].pixmap) { if (frame > viewer->im_pos + 10 || frame < viewer->im_pos) { changed_cursor = 1; XDefineCursor(display, window, viewer->wait_cursor); XFlush(display); } } /* Prepare the frame */ (void) unoptimized_frame(viewer, frame, changed_cursor && !viewer->animating); /* Restore cursor */ if (changed_cursor) XDefineCursor(display, window, viewer->arrow_cursor); /* schedule actual view of window */ xwADDTIME(viewer->timer, viewer->timer, preparation_time); viewer->preparing = 0; schedule(viewer); } void view_frame(Gt_Viewer *viewer, int frame) { Display *display = viewer->display; Window window = viewer->window; Pixmap old_pixmap = viewer->pixmap; int need_set_name = 0; if (viewer->being_deleted) return; if (frame < 0) frame = 0; if (frame > viewer->nim - 1 && viewer->animating) { int loopcount = viewer->gfs->loopcount; if (loopcount == 0 || loopcount > viewer->anim_loop) { viewer->anim_loop++; frame = 0; } else { switch_animating(viewer, 0); need_set_name = 1; } } if (frame > viewer->nim - 1) frame = viewer->nim - 1; if (frame != viewer->im_pos) { Gif_Image *gfi = viewer->im[frame]; int width, height, changed_cursor = 0; /* Change cursor if we need to wait. */ if ((viewer->animating || viewer->unoptimizing) && !viewer->unoptimized_frames[frame].pixmap) { if (frame > viewer->im_pos + 10 || frame < viewer->im_pos) { changed_cursor = 1; XDefineCursor(display, window, viewer->wait_cursor); XFlush(display); } } /* 5/26/98 Do some noodling around to try and use memory most effectively. If animating, keep the uncompressed frame; otherwise, throw it away. */ if (viewer->animating || viewer->unoptimizing) viewer->pixmap = unoptimized_frame(viewer, frame, changed_cursor); else viewer->pixmap = Gif_XImage(viewer->gfx, viewer->gfs, gfi); /* put the image on the window */ if (viewer->animating || viewer->unoptimizing) width = viewer->gfs->screen_width, height = viewer->gfs->screen_height; else width = Gif_ImageWidth(gfi), height = Gif_ImageHeight(gfi); if (!window) { create_viewer_window(viewer, width, height); window = viewer->window; } XSetWindowBackgroundPixmap(display, window, viewer->pixmap); if (old_pixmap || viewer->use_window) /* clear existing window */ XClearWindow(display, window); /* Only change size after changing pixmap. */ if ((viewer->width != width || viewer->height != height) && viewer->resizable) { XWindowChanges winch; winch.width = viewer->width = width; winch.height = viewer->height = height; XReconfigureWMWindow (display, window, viewer->screen_number, CWWidth | CWHeight, &winch); } /* Get rid of old pixmaps */ if (!viewer->was_unoptimized && old_pixmap) XFreePixmap(display, old_pixmap); viewer->was_unoptimized = viewer->animating || viewer->unoptimizing; /* Restore cursor */ if (changed_cursor) XDefineCursor(display, window, viewer->arrow_cursor); /* Do we need a new name? */ if ((!viewer->animating && Gif_ImageCount(viewer->gfs) > 1) || old_pixmap == None) need_set_name = 1; } viewer->im_pos = frame; viewer->preparing = 0; if (need_set_name) set_viewer_name(viewer, -1); if (!old_pixmap && !viewer->use_window) /* first image; map the window */ XMapRaised(display, window); else if (viewer->animating) /* only schedule next frame if image is already mapped */ schedule_next_frame(viewer); } /***** * Command line arguments: marking frames, being done with streams **/ int frame_argument(Gt_Viewer *viewer, const char *arg) { const char *c = arg; int n1 = 0; /* Get a number range (#x, #x-y, #x-, or #-y). First, read x. */ if (isdigit(c[0])) n1 = strtol(arg, (char **)&c, 10); /* It really was a number range only if c is now at the end of the argument. */ if (c[0] != 0) { Gif_Image *gfi = Gif_GetNamedImage(viewer->gfs, c); if (!gfi) error("no frame named '%s'", c); else n1 = Gif_ImageNumber(viewer->gfs, gfi); } else { if (n1 < 0 || n1 >= viewer->nim) { error("no frame number %d", n1); n1 = 0; } } return n1; } void input_stream_done(Gt_Viewer *viewer, int first_frame) { viewer->can_animate = Gif_ImageCount(viewer->gfs) > 1; switch_animating(viewer, animating && viewer->can_animate); if (first_frame < 0) first_frame = 0; view_frame(viewer, first_frame); } void key_press(Gt_Viewer *viewer, XKeyEvent *e) { char buf[32]; KeySym key; int nbuf = XLookupString(e, buf, 32, &key, 0); if (nbuf > 1) buf[0] = 0; /* ignore multikey sequences */ if (key == XK_space || key == XK_F || key == XK_f || key == XK_N || key == XK_n) /* space, N or F: one frame ahead */ view_frame(viewer, viewer->im_pos + 1); else if (key == XK_B || key == XK_b || key == XK_P || key == XK_p) /* B or P: one frame back */ view_frame(viewer, viewer->im_pos - 1); else if (key == XK_W || key == XK_w || key == XK_BackSpace) /* backspace: delete viewer */ pre_delete_viewer(viewer); else if (key == XK_Q || key == XK_q) /* Q: quit applicaton */ exit(0); else if (key == XK_S || key == XK_s || key == XK_a || key == XK_A) { /* S or A: toggle animation */ switch_animating(viewer, !viewer->animating); if (viewer->animating) { int pos = viewer->im_pos; if (viewer->im_pos >= viewer->nim - 1) { pos = 0; viewer->anim_loop = 0; } view_frame(viewer, pos); } else unschedule(viewer); set_viewer_name(viewer, -1); } else if (key == XK_U || key == XK_u) { /* U: toggle unoptimizing */ int pos = viewer->im_pos; viewer->unoptimizing = !viewer->unoptimizing; if (!viewer->animating) { viewer->im_pos = -1; view_frame(viewer, pos); set_viewer_name(viewer, -1); } } else if (key == XK_R || key == XK_r || (nbuf == 1 && buf[0] == '<')) { /* R or <: reset to first frame */ unschedule(viewer); viewer->anim_loop = 0; view_frame(viewer, 0); } else if (nbuf == 1 && buf[0] == '>') { /* >: reset to last frame */ unschedule(viewer); viewer->anim_loop = 0; view_frame(viewer, viewer->nim - 1); } else if (key == XK_Escape && viewer->animating) { /* Escape: stop animation */ switch_animating(viewer, 0); unschedule(viewer); set_viewer_name(viewer, -1); } else if (key == XK_Z || key == XK_z) { /* Z: trigger resizability */ viewer->resizable = !viewer->resizable; } } void loop(void) { struct timeval now, stop_loop, stop_delta; fd_set xfds; XEvent e; int pending; Gt_Viewer *v; Display *display = viewers->display; int x_socket = ConnectionNumber(display); stop_delta.tv_sec = 0; stop_delta.tv_usec = 200000; xwGETTIME(now); FD_ZERO(&xfds); while (viewers) { /* Check for any animations */ /* 13.Feb.2001 - Use the 'pending' counter to avoid a tight loop if all the frames in an animation have delay 0. Reported by Franc,ois Petitjean. */ /* 1.Aug.2002 - Switch to running the loop for max 0.2s. */ xwADDTIME(stop_loop, now, stop_delta); while (animations && xwTIMEGEQ(now, animations->timer) && xwTIMEGEQ(stop_loop, now)) { v = animations; animations = v->anim_next; v->scheduled = 0; if (v->preparing) prepare_frame(v, v->im_pos + 1); else { if (xwTIMEGEQ(now, v->timer)) v->timer = now; view_frame(v, v->im_pos + 1); } xwGETTIME(now); } pending = XPending(display); if (!pending) { /* select() until event arrives */ struct timeval timeout, *timeout_ptr; int retval; if (animations) { xwSUBTIME(timeout, animations->timer, now); timeout_ptr = &timeout; } else timeout_ptr = 0; FD_SET(x_socket, &xfds); retval = select(x_socket + 1, &xfds, 0, 0, timeout_ptr); pending = (retval <= 0 ? 0 : FD_ISSET(x_socket, &xfds)); } if (pending) while (XPending(display)) { XNextEvent(display, &e); v = find_viewer(e.xany.display, e.xany.window); if (v) { if (interactive) { if (e.type == ButtonPress && e.xbutton.button == 1) /* Left mouse button: go to next frame */ view_frame(v, v->im_pos + 1); else if (e.type == ButtonPress && e.xbutton.button == 3) /* Right mouse button: delete window */ pre_delete_viewer(v); else if (e.type == KeyPress) /* Key press: call function */ key_press(v, &e.xkey); } if (e.type == ClientMessage && e.xclient.message_type == wm_protocols_atom && (Atom)(e.xclient.data.l[0]) == wm_delete_window_atom) /* WM_DELETE_WINDOW message: delete window */ pre_delete_viewer(v); else if (e.type == MapNotify && v->animating && v->scheduled == 0) /* Window was just mapped; now, start animating it */ schedule_next_frame(v); else if (e.type == DestroyNotify) /* Once the window has been destroyed, delete related state */ delete_viewer(v); } } xwGETTIME(now); } } int main(int argc, char *argv[]) { Gt_Viewer *viewer = 0; int viewer_given = 0; int any_errors = 0; int first_frame = -1; Clp_Parser *clp = Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); Clp_SetOptionChar(clp, '+', Clp_ShortNegated); Clp_AddStringListType (clp, WINDOW_TYPE, Clp_AllowNumbers | Clp_StringListLong, "root", (long) -1, (const char*) 0); program_name = cur_resource_name = cur_window_title = Clp_ProgramName(clp); xwGETTIMEOFDAY(&genesis_time); preparation_time.tv_sec = 0; preparation_time.tv_usec = 200000; while (1) { int opt = Clp_Next(clp); switch (opt) { case DISPLAY_OPT: if (cur_display) fatal_error("'--display' must come before all other options"); cur_display_name = clp->vstr; cur_display = 0; cur_arrow_cursor = cur_wait_cursor = None; break; case TITLE_OPT: cur_window_title = clp->vstr; break; case GEOMETRY_OPT: cur_geometry_spec = clp->vstr; break; case NAME_OPT: cur_resource_name = clp->vstr; break; case UNOPTIMIZE_OPT: unoptimizing = clp->negated ? 0 : 1; break; case BACKGROUND_OPT: cur_background_color = clp->vstr; break; case ANIMATE_OPT: animating = clp->negated ? 0 : 1; break; case INSTALL_COLORMAP_OPT: install_colormap = clp->negated ? 0 : 1; break; case WINDOW_OPT: cur_use_window = clp->val.ul; cur_use_window_new = 0; break; case NEW_WINDOW_OPT: cur_use_window = clp->val.ul; cur_use_window_new = 1; break; case INTERACTIVE_OPT: interactive = clp->negated ? 0 : 1; break; case MIN_DELAY_OPT: min_delay = clp->negated ? 0 : clp->val.i; break; case FALLBACK_DELAY_OPT: fallback_delay = clp->negated ? 0 : clp->val.i; break; case MEMORY_LIMIT_OPT: if (clp->negated || clp->val.u >= ((unsigned) -1 / 1000)) pixel_memory_limit_kb = (unsigned) -1; else pixel_memory_limit_kb = clp->val.u * 1000; break; case VERSION_OPT: printf("gifview (LCDF Gifsicle) %s\n", VERSION); printf("Copyright (C) 1997-2013 Eddie Kohler\n\ This is free software; see the source for copying conditions.\n\ There is NO warranty, not even for merchantability or fitness for a\n\ particular purpose.\n"); exit(0); break; case HELP_OPT: usage(); exit(0); break; case Clp_NotOption: if (clp->vstr[0] == '#') { if (!viewer_given) { viewer = get_input_stream(0); viewer_given = 1; } if (viewer && first_frame >= 0) { /* copy viewer if 2 frame specs given */ input_stream_done(viewer, first_frame); viewer = next_viewer(viewer->gfs, viewer->name); } if (viewer) first_frame = frame_argument(viewer, clp->vstr + 1); } else { if (viewer) input_stream_done(viewer, first_frame); first_frame = -1; viewer = get_input_stream(clp->vstr); viewer_given = 1; } break; case Clp_Done: goto done; case Clp_BadOption: any_errors = 1; break; default: break; } } done: if (!viewer_given) { if (any_errors) { short_usage(); exit(1); } viewer = get_input_stream(0); } if (viewer) input_stream_done(viewer, first_frame); if (viewers) loop(); #ifdef DMALLOC dmalloc_report(); #endif return 0; } gifsicle-1.78/src/gifread.c0000644000175000017500000005425212242717703012530 00000000000000/* gifread.c - Functions to read GIFs. Copyright (C) 1997-2013 Eddie Kohler, kohler@cs.ucla.edu This file is part of the LCDF GIF library. The LCDF GIF library is free software. It is distributed under the GNU General Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #ifdef HAVE_CONFIG_H # include #elif !defined(__cplusplus) /* Assume we don't have inline by default */ # define inline #endif #include #include #include #include #ifdef __cplusplus extern "C" { #endif typedef struct { Gif_Stream *stream; Gif_Code *prefix; uint8_t *suffix; uint16_t *length; uint16_t width; uint16_t height; uint8_t *image; uint8_t *maximage; unsigned decodepos; Gif_ReadErrorHandler handler; void *handler_thunk; } Gif_Context; typedef struct Gif_Reader { FILE *f; const uint8_t *v; uint32_t w; uint32_t length; int is_record; int is_eoi; uint8_t (*byte_getter)(struct Gif_Reader *); void (*block_getter)(uint8_t *, uint32_t, struct Gif_Reader *); uint32_t (*offseter)(struct Gif_Reader *); int (*eofer)(struct Gif_Reader *); } Gif_Reader; #define gifgetc(grr) ((char)(*grr->byte_getter)(grr)) #define gifgetbyte(grr) ((*grr->byte_getter)(grr)) #define gifgetblock(ptr, size, grr) ((*grr->block_getter)(ptr, size, grr)) #define gifgetoffset(grr) ((*grr->offseter)(grr)) #define gifeof(grr) ((*grr->eofer)(grr)) static inline uint16_t gifgetunsigned(Gif_Reader *grr) { uint8_t one = gifgetbyte(grr); uint8_t two = gifgetbyte(grr); return one | (two << 8); } static uint8_t file_byte_getter(Gif_Reader *grr) { int i = getc(grr->f); return i == EOF ? 0 : (uint8_t)i; } static void file_block_getter(uint8_t *p, uint32_t s, Gif_Reader *grr) { size_t nread = fread(p, 1, s, grr->f); if (nread < s) memset(p + nread, 0, s - nread); } static uint32_t file_offseter(Gif_Reader *grr) { return ftell(grr->f); } static int file_eofer(Gif_Reader *grr) { int c = getc(grr->f); if (c == EOF) return 1; else { ungetc(c, grr->f); return 0; } } static uint8_t record_byte_getter(Gif_Reader *grr) { return grr->w ? (grr->w--, *grr->v++) : 0; } static void record_block_getter(uint8_t *p, uint32_t s, Gif_Reader *grr) { uint32_t ncopy = s; if (ncopy > grr->w) ncopy = grr->w; memcpy(p, grr->v, ncopy); grr->w -= ncopy, grr->v += ncopy; if (ncopy < s) memset(p + ncopy, 0, s - ncopy); } static uint32_t record_offseter(Gif_Reader *grr) { return grr->length - grr->w; } static int record_eofer(Gif_Reader *grr) { return grr->w == 0; } static void make_data_reader(Gif_Reader *grr, const uint8_t *data, uint32_t length) { grr->v = data; grr->length = length; grr->w = length; grr->is_record = 1; grr->byte_getter = record_byte_getter; grr->block_getter = record_block_getter; grr->offseter = record_offseter; grr->eofer = record_eofer; } static void gif_read_error(Gif_Context *gfc, int is_error, const char *text) { gfc->stream->errors++; if (gfc->handler) gfc->handler(is_error, text, gfc->stream->nimages, gfc->handler_thunk); } static uint8_t one_code(Gif_Context *gfc, Gif_Code code) { uint8_t *suffixes = gfc->suffix; Gif_Code *prefixes = gfc->prefix; uint8_t *ptr; int lastsuffix; uint16_t codelength = gfc->length[code]; gfc->decodepos += codelength; ptr = gfc->image + gfc->decodepos; if (ptr > gfc->maximage || !codelength) { gif_read_error(gfc, 1, (!codelength ? "bad code" : "too much image data")); /* 5/26/98 It's not good enough simply to count an error, because in the read_image_data function, if code == next_code, we will store a byte in gfc->image[gfc->decodepos-1]. Thus, fix decodepos so it's w/in the image. */ gfc->decodepos = gfc->maximage - gfc->image; return 0; } /* codelength will always be greater than 0. */ do { lastsuffix = suffixes[code]; *--ptr = lastsuffix; code = prefixes[code]; } while (--codelength > 0); /* return the first pixel in the code, which, since we walked backwards through the code, was the last suffix we processed. */ return lastsuffix; } static int read_image_block(Gif_Reader *grr, uint8_t *buffer, int *bit_pos_store, int *bit_len_store, int bits_needed) { int bit_position = *bit_pos_store; int bit_length = *bit_len_store; uint8_t block_len; while (bit_position + bits_needed > bit_length) { /* Read in the next data block. */ if (bit_position >= 8) { /* Need to shift down the upper, unused part of 'buffer' */ int i = bit_position / 8; buffer[0] = buffer[i]; buffer[1] = buffer[i+1]; bit_position -= i * 8; bit_length -= i * 8; } block_len = gifgetbyte(grr); GIF_DEBUG(("\nimage_block(%d)", block_len)); if (block_len == 0) return 0; gifgetblock(buffer + bit_length / 8, block_len, grr); bit_length += block_len * 8; } *bit_pos_store = bit_position; *bit_len_store = bit_length; return 1; } static void read_image_data(Gif_Context *gfc, Gif_Reader *grr) { /* we need a bit more than GIF_MAX_BLOCK in case a single code is split across blocks */ uint8_t buffer[GIF_MAX_BLOCK + 5]; int i; uint32_t accum; int bit_position; int bit_length; Gif_Code code; Gif_Code old_code; Gif_Code clear_code; Gif_Code eoi_code; Gif_Code next_code; #define CUR_BUMP_CODE (1 << bits_needed) #define CUR_CODE_MASK ((1 << bits_needed) - 1) int min_code_size; int bits_needed; gfc->decodepos = 0; min_code_size = gifgetbyte(grr); GIF_DEBUG(("\n\nmin_code_size(%d)", min_code_size)); if (min_code_size >= GIF_MAX_CODE_BITS) { gif_read_error(gfc, 1, "min_code_size too big"); min_code_size = GIF_MAX_CODE_BITS - 1; } else if (min_code_size < 2) { gif_read_error(gfc, 1, "min_code_size too small"); min_code_size = 2; } clear_code = 1 << min_code_size; for (code = 0; code < clear_code; code++) { gfc->prefix[code] = 49428; gfc->suffix[code] = (uint8_t)code; gfc->length[code] = 1; } eoi_code = clear_code + 1; next_code = eoi_code; bits_needed = min_code_size + 1; code = clear_code; bit_length = bit_position = 0; /* Thus the 'Read in the next data block.' code below will be invoked on the first time through: exactly right! */ while (1) { old_code = code; /* GET A CODE INTO THE 'code' VARIABLE. * * 9.Dec.1998 - Rather than maintain a byte pointer and a bit offset into * the current byte (and the processing associated with that), we maintain * one number: the offset, in bits, from the beginning of 'buffer'. This * much cleaner choice was inspired by Patrick J. Naughton * 's GIF-reading code, which does the same thing. * His code distributed as part of XV in xvgif.c. */ if (bit_position + bits_needed > bit_length) /* Read in the next data block. */ if (!read_image_block(grr, buffer, &bit_position, &bit_length, bits_needed)) goto zero_length_block; i = bit_position / 8; accum = buffer[i] + (buffer[i+1] << 8); if (bits_needed >= 8) accum |= (buffer[i+2]) << 16; code = (Gif_Code)((accum >> (bit_position % 8)) & CUR_CODE_MASK); bit_position += bits_needed; GIF_DEBUG(("%d", code)); /* CHECK FOR SPECIAL OR BAD CODES: clear_code, eoi_code, or a code that is * too large. */ if (code == clear_code) { GIF_DEBUG(("clear")); bits_needed = min_code_size + 1; next_code = eoi_code; continue; } else if (code == eoi_code) break; else if (code > next_code && next_code && next_code != clear_code) { /* code > next_code: a (hopefully recoverable) error. Bug fix, 5/27: Do this even if old_code == clear_code, and set code to 0 to prevent errors later. (If we didn't zero code, we'd later set old_code = code; then we had old_code >= next_code; so the prefixes array got all screwed up!) Bug fix, 4/12/2010: It is not an error if next_code == clear_code. This happens at the end of a large GIF: see the next comment ("If no meaningful next code should be defined...."). */ gif_read_error(gfc, 1, "unexpected code"); code = 0; } /* PROCESS THE CURRENT CODE and define the next code. If no meaningful * next code should be defined, then we have set next_code to either * 'eoi_code' or 'clear_code' -- so we'll store useless prefix/suffix data * in a useless place. */ /* *First,* set up the prefix and length for the next code (in case code == next_code). */ gfc->prefix[next_code] = old_code; gfc->length[next_code] = gfc->length[old_code] + 1; /* Use one_code to process code. It's nice that it returns the first pixel in code: that's what we need. */ gfc->suffix[next_code] = one_code(gfc, code); /* Special processing if code == next_code: we didn't know code's final suffix when we called one_code, but we do now. */ if (code == next_code) gfc->image[gfc->decodepos - 1] = gfc->suffix[next_code]; /* Increment next_code except for the 'clear_code' special case (that's when we're reading at the end of a GIF) */ if (next_code != clear_code) { next_code++; if (next_code == CUR_BUMP_CODE) { if (bits_needed < GIF_MAX_CODE_BITS) bits_needed++; else next_code = clear_code; } } } /* read blocks until zero-length reached. */ i = gifgetbyte(grr); GIF_DEBUG(("\nafter_image(%d)\n", i)); while (i > 0) { gifgetblock(buffer, i, grr); i = gifgetbyte(grr); GIF_DEBUG(("\nafter_image(%d)\n", i)); } /* zero-length block reached. */ zero_length_block: if (gfc->image + gfc->decodepos < gfc->maximage) gif_read_error(gfc, 1, "not enough image data for image size"); else if (gfc->image + gfc->decodepos > gfc->maximage) gif_read_error(gfc, 1, "too much image data for image size"); } static Gif_Colormap * read_color_table(int size, Gif_Reader *grr) { Gif_Colormap *gfcm = Gif_NewFullColormap(size, size); Gif_Color *c; if (!gfcm) return 0; GIF_DEBUG(("colormap(%d)", size)); for (c = gfcm->col; size; size--, c++) { c->gfc_red = gifgetbyte(grr); c->gfc_green = gifgetbyte(grr); c->gfc_blue = gifgetbyte(grr); c->haspixel = 0; } return gfcm; } static int read_logical_screen_descriptor(Gif_Stream *gfs, Gif_Reader *grr) /* returns 0 on memory error */ { uint8_t packed; /* we don't care about logical screen width or height */ gfs->screen_width = gifgetunsigned(grr); gfs->screen_height = gifgetunsigned(grr); packed = gifgetbyte(grr); gfs->background = gifgetbyte(grr); /* don't care about pixel aspect ratio */ gifgetbyte(grr); if (packed & 0x80) { /* have a global color table */ int ncol = 1 << ((packed & 0x07) + 1); gfs->global = read_color_table(ncol, grr); if (!gfs->global) return 0; gfs->global->refcount = 1; } return 1; } static int read_compressed_image(Gif_Image *gfi, Gif_Reader *grr, int read_flags) { if (grr->is_record) { const uint8_t *first = grr->v; uint32_t pos; /* scan over image */ pos = 1; /* skip min code size */ while (pos < grr->w) { int amt = grr->v[pos]; pos += amt + 1; if (amt == 0) break; } if (pos > grr->w) pos = grr->w; gfi->compressed_len = pos; if (read_flags & GIF_READ_CONST_RECORD) { gfi->compressed = (uint8_t *)first; gfi->free_compressed = 0; } else { gfi->compressed = Gif_NewArray(uint8_t, gfi->compressed_len); gfi->free_compressed = Gif_DeleteArrayFunc; if (!gfi->compressed) return 0; memcpy(gfi->compressed, first, gfi->compressed_len); } /* move reader over that image */ grr->v += pos; grr->w -= pos; } else { /* non-record; have to read it block by block. */ uint32_t comp_cap = 1024; uint32_t comp_len; uint8_t *comp = Gif_NewArray(uint8_t, comp_cap); int i; if (!comp) return 0; /* min code size */ i = gifgetbyte(grr); comp[0] = i; comp_len = 1; i = gifgetbyte(grr); while (i > 0) { /* add 2 before check so we don't have to check after loop when appending 0 block */ if (comp_len + i + 2 > comp_cap) { comp_cap *= 2; Gif_ReArray(comp, uint8_t, comp_cap); if (!comp) return 0; } comp[comp_len] = i; gifgetblock(comp + comp_len + 1, i, grr); comp_len += i + 1; i = gifgetbyte(grr); } comp[comp_len++] = 0; gfi->compressed = comp; gfi->compressed_len = comp_len; gfi->free_compressed = Gif_DeleteArrayFunc; } return 1; } static int uncompress_image(Gif_Context *gfc, Gif_Image *gfi, Gif_Reader *grr) { if (!Gif_CreateUncompressedImage(gfi)) return 0; gfc->width = gfi->width; gfc->height = gfi->height; gfc->image = gfi->image_data; gfc->maximage = gfi->image_data + gfi->width * gfi->height; read_image_data(gfc, grr); return 1; } int Gif_FullUncompressImage(Gif_Image *gfi, Gif_ReadErrorHandler h, void *hthunk) { Gif_Context gfc; Gif_Stream fake_gfs; Gif_Reader grr; int ok = 0; /* return right away if image is already uncompressed. this might screw over people who expect re-uncompressing to restore the compressed version. */ if (gfi->img) return 2; if (gfi->image_data) /* we have uncompressed data, but not an 'img' array; this shouldn't happen */ return 0; fake_gfs.errors = 0; gfc.stream = &fake_gfs; gfc.prefix = Gif_NewArray(Gif_Code, GIF_MAX_CODE); gfc.suffix = Gif_NewArray(uint8_t, GIF_MAX_CODE); gfc.length = Gif_NewArray(uint16_t, GIF_MAX_CODE); gfc.handler = h; gfc.handler_thunk = hthunk; if (gfi && gfc.prefix && gfc.suffix && gfc.length && gfi->compressed) { make_data_reader(&grr, gfi->compressed, gfi->compressed_len); ok = uncompress_image(&gfc, gfi, &grr); } Gif_DeleteArray(gfc.prefix); Gif_DeleteArray(gfc.suffix); Gif_DeleteArray(gfc.length); return ok && !fake_gfs.errors; } static int read_image(Gif_Reader *grr, Gif_Context *gfc, Gif_Image *gfi, int read_flags) /* returns 0 on memory error */ { uint8_t packed; gfi->left = gifgetunsigned(grr); gfi->top = gifgetunsigned(grr); gfi->width = gifgetunsigned(grr); gfi->height = gifgetunsigned(grr); packed = gifgetbyte(grr); GIF_DEBUG(("<%ux%u>", gfi->width, gfi->height)); if (packed & 0x80) { /* have a local color table */ int ncol = 1 << ((packed & 0x07) + 1); gfi->local = read_color_table(ncol, grr); if (!gfi->local) return 0; gfi->local->refcount = 1; } gfi->interlace = (packed & 0x40) != 0; /* Keep the compressed data if asked */ if (read_flags & GIF_READ_COMPRESSED) { if (!read_compressed_image(gfi, grr, read_flags)) return 0; if (read_flags & GIF_READ_UNCOMPRESSED) { Gif_Reader new_grr; make_data_reader(&new_grr, gfi->compressed, gfi->compressed_len); if (!uncompress_image(gfc, gfi, &new_grr)) return 0; } } else if (read_flags & GIF_READ_UNCOMPRESSED) { if (!uncompress_image(gfc, gfi, grr)) return 0; } else { /* skip over the image */ uint8_t buffer[GIF_MAX_BLOCK]; int i = gifgetbyte(grr); while (i > 0) { gifgetblock(buffer, i, grr); i = gifgetbyte(grr); } } return 1; } static void read_graphic_control_extension(Gif_Context *gfc, Gif_Image *gfi, Gif_Reader *grr) { uint8_t len; uint8_t crap[GIF_MAX_BLOCK]; len = gifgetbyte(grr); if (len == 4) { uint8_t packed = gifgetbyte(grr); gfi->disposal = (packed >> 2) & 0x07; gfi->delay = gifgetunsigned(grr); gfi->transparent = gifgetbyte(grr); if (!(packed & 0x01)) /* transparent color doesn't exist */ gfi->transparent = -1; len -= 4; } if (len > 0) { gif_read_error(gfc, 1, "odd graphic extension format"); gifgetblock(crap, len, grr); } len = gifgetbyte(grr); while (len > 0) { gif_read_error(gfc, 1, "odd graphic extension format"); gifgetblock(crap, len, grr); len = gifgetbyte(grr); } } static char *last_name; static char * suck_data(char *data, int *store_len, Gif_Reader *grr) { uint8_t len = gifgetbyte(grr); int total_len = 0; while (len > 0) { Gif_ReArray(data, char, total_len + len + 1); if (!data) return 0; gifgetblock((uint8_t *)data, len, grr); total_len += len; data[total_len] = 0; len = gifgetbyte(grr); } if (store_len) *store_len = total_len; return data; } static int read_unknown_extension(Gif_Stream *gfs, int kind, char *app_name, int position, Gif_Reader *grr) { uint8_t block_len = gifgetbyte(grr); uint8_t *data = 0; uint8_t data_len = 0; Gif_Extension *gfex = 0; while (block_len > 0) { if (data) Gif_ReArray(data, uint8_t, data_len + block_len + 1); else data = Gif_NewArray(uint8_t, block_len + 1); if (!data) goto done; gifgetblock(data + data_len, block_len, grr); data_len += block_len; block_len = gifgetbyte(grr); } if (data) gfex = Gif_NewExtension(kind, app_name); if (gfex) { gfex->data = data; gfex->free_data = Gif_DeleteArrayFunc; gfex->length = data_len; data[data_len] = 0; Gif_AddExtension(gfs, gfex, position); } done: if (!gfex) Gif_DeleteArray(data); while (block_len > 0) { uint8_t buffer[GIF_MAX_BLOCK]; gifgetblock(buffer, block_len, grr); block_len = gifgetbyte(grr); } return gfex != 0; } static int read_application_extension(Gif_Context *gfc, int position, Gif_Reader *grr) { Gif_Stream *gfs = gfc->stream; uint8_t buffer[GIF_MAX_BLOCK + 1]; uint8_t len = gifgetbyte(grr); gifgetblock(buffer, len, grr); /* Read the Netscape loop extension. */ if (len == 11 && memcmp(buffer, "NETSCAPE2.0", 11) == 0) { len = gifgetbyte(grr); if (len == 3) { gifgetbyte(grr); /* throw away the 1 */ gfs->loopcount = gifgetunsigned(grr); len = gifgetbyte(grr); if (len) gif_read_error(gfc, 1, "bad loop extension"); } else gif_read_error(gfc, 1, "bad loop extension"); while (len > 0) { gifgetblock(buffer, len, grr); len = gifgetbyte(grr); } return 1; } else { buffer[len] = 0; return read_unknown_extension(gfs, 0xFF, (char *)buffer, position, grr); } } static int read_comment_extension(Gif_Image *gfi, Gif_Reader *grr) { int len; Gif_Comment *gfcom = gfi->comment; char *m = suck_data(0, &len, grr); if (m) { if (!gfcom) gfcom = gfi->comment = Gif_NewComment(); if (!gfcom || !Gif_AddCommentTake(gfcom, m, len)) return 0; } return 1; } static Gif_Stream * read_gif(Gif_Reader *grr, int read_flags, Gif_ReadErrorHandler handler, void *handler_thunk) { Gif_Stream *gfs; Gif_Image *gfi; Gif_Image *new_gfi; Gif_Context gfc; int extension_position = 0; int unknown_block_type = 0; if (gifgetc(grr) != 'G' || gifgetc(grr) != 'I' || gifgetc(grr) != 'F') return 0; (void)gifgetc(grr); (void)gifgetc(grr); (void)gifgetc(grr); gfs = Gif_NewStream(); gfi = Gif_NewImage(); gfc.stream = gfs; gfc.prefix = Gif_NewArray(Gif_Code, GIF_MAX_CODE); gfc.suffix = Gif_NewArray(uint8_t, GIF_MAX_CODE); gfc.length = Gif_NewArray(uint16_t, GIF_MAX_CODE); gfc.handler = handler; gfc.handler_thunk = handler_thunk; if (!gfs || !gfi || !gfc.prefix || !gfc.suffix || !gfc.length) goto done; GIF_DEBUG(("\nGIF")); if (!read_logical_screen_descriptor(gfs, grr)) goto done; GIF_DEBUG(("logscrdesc")); while (!gifeof(grr)) { uint8_t block = gifgetbyte(grr); switch (block) { case ',': /* image block */ GIF_DEBUG(("imageread %d", gfs->nimages)); gfi->identifier = last_name; last_name = 0; if (!read_image(grr, &gfc, gfi, read_flags) || !Gif_AddImage(gfs, gfi)) { Gif_DeleteImage(gfi); goto done; } new_gfi = Gif_NewImage(); if (!new_gfi) goto done; gfi = new_gfi; extension_position++; break; case ';': /* terminator */ GIF_DEBUG(("term\n")); goto done; case '!': /* extension */ block = gifgetbyte(grr); GIF_DEBUG(("ext(0x%02X)", block)); switch (block) { case 0xF9: read_graphic_control_extension(&gfc, gfi, grr); break; case 0xCE: last_name = suck_data(last_name, 0, grr); break; case 0xFE: if (!read_comment_extension(gfi, grr)) goto done; break; case 0xFF: read_application_extension(&gfc, extension_position, grr); break; default: read_unknown_extension(gfs, block, 0, extension_position, grr); break; } break; default: if (!unknown_block_type) { char buf[256]; sprintf(buf, "unknown block type %d at file offset %d", block, gifgetoffset(grr) - 1); gif_read_error(&gfc, 1, buf); unknown_block_type = 1; } break; } } done: /* Move comments after last image into stream. */ if (gfs && gfi) { gfs->comment = gfi->comment; gfi->comment = 0; } Gif_DeleteImage(gfi); Gif_DeleteArray(last_name); Gif_DeleteArray(gfc.prefix); Gif_DeleteArray(gfc.suffix); Gif_DeleteArray(gfc.length); if (gfs && gfs->errors == 0 && !(read_flags & GIF_READ_TRAILING_GARBAGE_OK) && !grr->eofer(grr)) { gif_read_error(&gfc, 0, "trailing garbage after GIF ignored"); /* but clear error count, since the GIF itself was all right */ gfs->errors = 0; } return gfs; } Gif_Stream * Gif_FullReadFile(FILE *f, int read_flags, Gif_ReadErrorHandler h, void *hthunk) { Gif_Reader grr; if (!f) return 0; grr.f = f; grr.is_record = 0; grr.byte_getter = file_byte_getter; grr.block_getter = file_block_getter; grr.offseter = file_offseter; grr.eofer = file_eofer; return read_gif(&grr, read_flags, h, hthunk); } Gif_Stream * Gif_FullReadRecord(const Gif_Record *gifrec, int read_flags, Gif_ReadErrorHandler h, void *hthunk) { Gif_Reader grr; if (!gifrec) return 0; make_data_reader(&grr, gifrec->data, gifrec->length); if (read_flags & GIF_READ_CONST_RECORD) read_flags |= GIF_READ_COMPRESSED; return read_gif(&grr, read_flags, h, hthunk); } #undef Gif_ReadFile #undef Gif_ReadRecord Gif_Stream * Gif_ReadFile(FILE *f) { return Gif_FullReadFile(f, GIF_READ_UNCOMPRESSED, 0, 0); } Gif_Stream * Gif_ReadRecord(const Gif_Record *gifrec) { return Gif_FullReadRecord(gifrec, GIF_READ_UNCOMPRESSED, 0, 0); } #ifdef __cplusplus } #endif gifsicle-1.78/src/gifx.c0000644000175000017500000005247012242717703012064 00000000000000/* gifx.c - Functions to turn GIFs in memory into X Pixmaps. Copyright (C) 1997-2013 Eddie Kohler, kohler@cs.ucla.edu This file is part of the LCDF GIF library. The LCDF GIF library is free software. It is distributed under the GNU General Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define SAFELS(a,b) ((b) < 0 ? (a) >> -(b) : (a) << (b)) struct Gif_XColormap { Gif_XContext *x_context; Gif_Colormap *colormap; int allocated; int claimed; uint16_t npixels; unsigned long *pixels; Gif_XColormap *next; }; static unsigned long crap_pixels[256]; static void load_closest(Gif_XContext *gfx) { XColor *color; uint16_t ncolor; uint16_t ncolormap; int i; if (gfx->closest) return; ncolormap = ncolor = gfx->ncolormap; if (ncolor > 256) ncolor = 256; color = Gif_NewArray(XColor, ncolor); if (ncolormap > 256) for (i = 0; i < ncolor; i++) color[i].pixel = (rand() >> 4) % ncolormap; else for (i = 0; i < ncolor; i++) color[i].pixel = i; XQueryColors(gfx->display, gfx->colormap, color, ncolor); gfx->closest = Gif_NewArray(Gif_Color, ncolor); for (i = 0; i < ncolor; i++) { Gif_Color *c = &gfx->closest[i]; c->haspixel = 1; c->gfc_red = color[i].red >> 8; c->gfc_green = color[i].green >> 8; c->gfc_blue = color[i].blue >> 8; c->pixel = color[i].pixel; } gfx->nclosest = ncolor; Gif_DeleteArray(color); } static unsigned long allocate_closest(Gif_XContext *gfx, Gif_Color *c) { Gif_Color *closer; Gif_Color *got = 0; uint32_t distance = 0x4000000; int i; load_closest(gfx); for (i = 0, closer = gfx->closest; i < gfx->nclosest; i++, closer++) { int redd = c->gfc_red - closer->gfc_red; int greend = c->gfc_green - closer->gfc_green; int blued = c->gfc_blue - closer->gfc_blue; uint32_t d = redd * redd + greend * greend + blued * blued; if (d < distance) { distance = d; got = closer; } } if (!got) return 0; if (!got->haspixel) { XColor xcol; xcol.red = got->gfc_red | (got->gfc_red << 8); xcol.green = got->gfc_green | (got->gfc_green << 8); xcol.blue = got->gfc_blue | (got->gfc_blue << 8); if (XAllocColor(gfx->display, gfx->colormap, &xcol) == 0) { /* Probably was a read/write color cell. Get rid of it!! */ *got = gfx->closest[gfx->nclosest - 1]; gfx->nclosest--; return allocate_closest(gfx, c); } got->pixel = xcol.pixel; got->haspixel = 1; } return got->pixel; } static void allocate_colors(Gif_XColormap *gfxc) { Gif_XContext *gfx = gfxc->x_context; uint16_t size = gfxc->colormap->ncol; Gif_Color *c = gfxc->colormap->col; unsigned long *pixels = gfxc->pixels; XColor xcol; int i; if (!gfxc->allocated) { if (size > gfxc->npixels) size = gfxc->npixels; for (i = 0; i < size; i++, c++) { xcol.red = c->gfc_red | (c->gfc_red << 8); xcol.green = c->gfc_green | (c->gfc_green << 8); xcol.blue = c->gfc_blue | (c->gfc_blue << 8); if (XAllocColor(gfx->display, gfx->colormap, &xcol)) pixels[i] = xcol.pixel; else pixels[i] = allocate_closest(gfx, c); } gfxc->allocated = 1; gfxc->claimed = 0; } } static void deallocate_colors(Gif_XColormap *gfxc) { Gif_XContext *gfx = gfxc->x_context; if (gfxc->allocated && !gfxc->claimed) { XFreeColors(gfx->display, gfx->colormap, gfxc->pixels, gfxc->npixels, 0); gfxc->allocated = 0; } } static Gif_XColormap * create_x_colormap_extension(Gif_XContext *gfx, Gif_Colormap *gfcm) { Gif_XColormap *gfxc; unsigned long *pixels; if (!gfcm) return 0; gfxc = Gif_New(Gif_XColormap); pixels = gfxc ? Gif_NewArray(unsigned long, 256) : 0; if (pixels) { gfxc->x_context = gfx; gfxc->colormap = gfcm; gfxc->allocated = 0; gfxc->npixels = gfcm->ncol; gfxc->pixels = pixels; gfxc->next = gfx->xcolormap; gfx->xcolormap = gfxc; return gfxc; } else { Gif_Delete(gfxc); Gif_DeleteArray(pixels); return 0; } } static Gif_XColormap * find_x_colormap_extension(Gif_XContext *gfx, Gif_Colormap *gfcm, int create) { Gif_XColormap *gfxc = gfx->xcolormap; if (!gfcm) return 0; while (gfxc) { if (gfxc->colormap == gfcm) return gfxc; gfxc = gfxc->next; } if (create) return create_x_colormap_extension(gfx, gfcm); else return 0; } int Gif_XAllocateColors(Gif_XContext *gfx, Gif_Colormap *gfcm) { Gif_XColormap *gfxc = find_x_colormap_extension(gfx, gfcm, 1); if (gfxc) { allocate_colors(gfxc); return 1; } else return 0; } void Gif_XDeallocateColors(Gif_XContext *gfx, Gif_Colormap *gfcm) { Gif_XColormap *gfxc = find_x_colormap_extension(gfx, gfcm, 0); if (gfxc) deallocate_colors(gfxc); } unsigned long * Gif_XClaimStreamColors(Gif_XContext *gfx, Gif_Stream *gfs, int *np_store) { int i; int npixels = 0; unsigned long *pixels; Gif_Colormap *global = gfs->global; *np_store = 0; for (i = 0; i < gfs->nimages; i++) { Gif_Image *gfi = gfs->images[i]; Gif_Colormap *gfcm = (gfi->local ? gfi->local : global); Gif_XColormap *gfxc = find_x_colormap_extension(gfx, gfcm, 0); if (gfxc && gfxc->allocated && gfxc->claimed == 0) { gfxc->claimed = 2; npixels += gfxc->npixels; if (gfcm == global) global = 0; } } if (!npixels) return 0; pixels = Gif_NewArray(unsigned long, npixels); if (!pixels) return 0; *np_store = npixels; npixels = 0; global = gfs->global; for (i = 0; i < gfs->nimages; i++) { Gif_Image *gfi = gfs->images[i]; Gif_Colormap *gfcm = (gfi->local ? gfi->local : global); Gif_XColormap *gfxc = find_x_colormap_extension(gfx, gfcm, 0); if (gfxc && gfxc->allocated && gfxc->claimed == 2) { memcpy(pixels + npixels, gfxc->pixels, gfxc->npixels); npixels += gfxc->npixels; gfxc->claimed = 1; if (gfcm == global) global = 0; } } return pixels; } /* Getting pixmaps */ #define BYTESIZE 8 static int put_sub_image_colormap(Gif_XContext *gfx, Gif_Image *gfi, Gif_Colormap *gfcm, int left, int top, int width, int height, Pixmap pixmap, int pixmap_x, int pixmap_y) { XImage *ximage; uint8_t *xdata; int i, j, k; int bytes_per_line; unsigned long saved_transparent = 0; int release_uncompressed = 0; uint16_t nct; unsigned long *pixels; /* Find the correct image and colormap */ if (!gfi) return 0; if (!gfx->image_gc) gfx->image_gc = XCreateGC(gfx->display, pixmap, 0, 0); if (!gfx->image_gc) return 0; /* Make sure the image is uncompressed */ if (!gfi->img && !gfi->image_data && gfi->compressed) { Gif_UncompressImage(gfi); release_uncompressed = 1; } /* Check subimage dimensions */ if (width <= 0 || height <= 0 || left < 0 || top < 0 || left+width <= 0 || top+height <= 0 || left+width > gfi->width || top+height > gfi->height) return 0; /* Allocate colors from the colormap; make sure the transparent color * has the given pixel value */ if (gfcm) { Gif_XColormap *gfxc = find_x_colormap_extension(gfx, gfcm, 1); if (!gfxc) return 0; allocate_colors(gfxc); pixels = gfxc->pixels; nct = gfxc->npixels; } else { for (i = 0; i < 256; i++) crap_pixels[i] = gfx->foreground_pixel; pixels = crap_pixels; nct = 256; } if (gfi->transparent >= 0 && gfi->transparent < 256) { saved_transparent = pixels[ gfi->transparent ]; pixels[ gfi->transparent ] = gfx->transparent_pixel; } /* Set up the X image */ if (gfx->depth <= 8) i = 8; else if (gfx->depth <= 16) i = 16; else i = 32; ximage = XCreateImage(gfx->display, gfx->visual, gfx->depth, gfx->depth == 1 ? XYBitmap : ZPixmap, 0, NULL, width, height, i, 0); ximage->bitmap_bit_order = ximage->byte_order = LSBFirst; bytes_per_line = ximage->bytes_per_line; xdata = Gif_NewArray(uint8_t, bytes_per_line * height); ximage->data = (char *)xdata; /* The main loop */ if (ximage->bits_per_pixel % 8 == 0) { /* Optimize for cases where a pixel is exactly one or more bytes */ int bytes_per_pixel = ximage->bits_per_pixel / 8; for (j = 0; j < height; j++) { uint8_t *line = gfi->img[top + j] + left; uint8_t *writer = xdata + bytes_per_line * j; for (i = 0; i < width; i++) { unsigned long pixel; if (line[i] < nct) pixel = pixels[line[i]]; else pixel = pixels[0]; for (k = 0; k < bytes_per_pixel; k++) { *writer++ = pixel; pixel >>= 8; } } } } else { /* Other bits-per-pixel */ int bits_per_pixel = ximage->bits_per_pixel; uint32_t bits_per_pixel_mask = (1UL << bits_per_pixel) - 1; for (j = 0; j < height; j++) { int imshift = 0; uint32_t impixel = 0; uint8_t *line = gfi->img[top + j] + left; uint8_t *writer = xdata + bytes_per_line * j; for (i = 0; i < width; i++) { unsigned long pixel; if (line[i] < nct) pixel = pixels[line[i]]; else pixel = pixels[0]; impixel |= SAFELS(pixel & bits_per_pixel_mask, imshift); while (imshift + bits_per_pixel >= BYTESIZE) { *writer++ = impixel; imshift -= BYTESIZE; impixel = SAFELS(pixel, imshift); } imshift += bits_per_pixel; } if (imshift) *writer++ = impixel; } } /* Restore saved transparent pixel value */ if (gfi->transparent >= 0 && gfi->transparent < 256) pixels[ gfi->transparent ] = saved_transparent; /* Put it onto the pixmap */ XPutImage(gfx->display, pixmap, gfx->image_gc, ximage, 0, 0, pixmap_x, pixmap_y, width, height); Gif_DeleteArray(xdata); ximage->data = 0; /* avoid freeing it again in XDestroyImage */ XDestroyImage(ximage); if (release_uncompressed) Gif_ReleaseUncompressedImage(gfi); return 1; } Pixmap Gif_XSubImageColormap(Gif_XContext *gfx, Gif_Image *gfi, Gif_Colormap *gfcm, int left, int top, int width, int height) { Pixmap pixmap = XCreatePixmap(gfx->display, gfx->drawable, width, height, gfx->depth); if (pixmap) { if (put_sub_image_colormap(gfx, gfi, gfcm, left, top, width, height, pixmap, 0, 0)) return pixmap; else XFreePixmap(gfx->display, pixmap); } return None; } Pixmap Gif_XImage(Gif_XContext *gfx, Gif_Stream *gfs, Gif_Image *gfi) { Gif_Colormap *gfcm; if (!gfi && gfs->nimages) gfi = gfs->images[0]; if (!gfi) return None; gfcm = gfi->local; if (!gfcm) gfcm = gfs->global; return Gif_XSubImageColormap(gfx, gfi, gfcm, 0, 0, gfi->width, gfi->height); } Pixmap Gif_XImageColormap(Gif_XContext *gfx, Gif_Stream *gfs, Gif_Colormap *gfcm, Gif_Image *gfi) { if (!gfi && gfs->nimages) gfi = gfs->images[0]; if (!gfi) return None; return Gif_XSubImageColormap(gfx, gfi, gfcm, 0, 0, gfi->width, gfi->height); } Pixmap Gif_XSubImage(Gif_XContext *gfx, Gif_Stream *gfs, Gif_Image *gfi, int left, int top, int width, int height) { Gif_Colormap *gfcm; if (!gfi && gfs->nimages) gfi = gfs->images[0]; if (!gfi) return None; gfcm = gfi->local; if (!gfcm) gfcm = gfs->global; return Gif_XSubImageColormap(gfx, gfi, gfcm, left, top, width, height); } Pixmap Gif_XSubMask(Gif_XContext *gfx, Gif_Image *gfi, int left, int top, int width, int height) { Pixmap pixmap = None; XImage *ximage; uint8_t *xdata; int i, j; int transparent; int bytes_per_line; int release_uncompressed = 0; /* Find the correct image */ if (!gfi) return None; /* Check subimage dimensions */ if (width <= 0 || height <= 0 || left < 0 || top < 0 || left+width <= 0 || top+height <= 0 || left+width > gfi->width || top+height > gfi->height) return None; /* Make sure the image is uncompressed */ if (!gfi->img && !gfi->image_data && gfi->compressed) { Gif_UncompressImage(gfi); release_uncompressed = 1; } /* Create the X image */ ximage = XCreateImage(gfx->display, gfx->visual, 1, XYBitmap, 0, NULL, width, height, 8, 0); ximage->bitmap_bit_order = ximage->byte_order = LSBFirst; bytes_per_line = ximage->bytes_per_line; xdata = Gif_NewArray(uint8_t, bytes_per_line * height); ximage->data = (char *)xdata; transparent = gfi->transparent; /* The main loop */ for (j = 0; j < height; j++) { int imshift = 0; uint32_t impixel = 0; uint8_t *line = gfi->img[top + j] + left; uint8_t *writer = xdata + bytes_per_line * j; for (i = 0; i < width; i++) { if (line[i] == transparent) impixel |= 1 << imshift; if (++imshift >= BYTESIZE) { *writer++ = impixel; imshift = 0; impixel = 0; } } if (imshift) *writer++ = impixel; } /* Create the pixmap */ pixmap = XCreatePixmap(gfx->display, gfx->drawable, width, height, 1); if (!gfx->mask_gc) gfx->mask_gc = XCreateGC(gfx->display, pixmap, 0, 0); if (pixmap && gfx->mask_gc) XPutImage(gfx->display, pixmap, gfx->mask_gc, ximage, 0, 0, 0, 0, width, height); Gif_DeleteArray(xdata); ximage->data = 0; /* avoid freeing it again in XDestroyImage */ XDestroyImage(ximage); if (release_uncompressed) Gif_ReleaseUncompressedImage(gfi); return pixmap; } Pixmap Gif_XMask(Gif_XContext *gfx, Gif_Stream *gfs, Gif_Image *gfi) { if (!gfi && gfs->nimages) gfi = gfs->images[0]; if (!gfi) return None; return Gif_XSubMask(gfx, gfi, 0, 0, gfi->width, gfi->height); } static Pixmap screen_pixmap(Gif_XContext *gfx, Gif_Stream *gfs) { return XCreatePixmap(gfx->display, gfx->drawable, gfs->screen_width, gfs->screen_height, gfx->depth); } static int apply_background(Gif_XContext *gfx, Gif_Stream *gfs, int i, Pixmap pixmap) { Gif_Image *gfi = gfs->images[i >= 0 ? i : 0]; Gif_Colormap *gfcm = (gfi->local ? gfi->local : gfs->global); unsigned long bg_pixel; /* find bg_pixel */ if (gfs->global && gfs->background < gfs->global->ncol && gfs->images[0]->transparent < 0) { Gif_XColormap *gfxc = find_x_colormap_extension(gfx, gfcm, 1); if (!gfxc) return -1; allocate_colors(gfxc); bg_pixel = gfxc->pixels[gfs->background]; } else bg_pixel = gfx->transparent_pixel; /* install it as the foreground color on gfx->image_gc */ if (!gfx->image_gc) gfx->image_gc = XCreateGC(gfx->display, pixmap, 0, 0); if (!gfx->image_gc) return -1; XSetForeground(gfx->display, gfx->image_gc, bg_pixel); gfx->transparent_pixel = bg_pixel; /* clear the image portion */ if (i < 0) XFillRectangle(gfx->display, pixmap, gfx->image_gc, 0, 0, gfs->screen_width, gfs->screen_height); else /*if (gfi->transparent < 0)*/ XFillRectangle(gfx->display, pixmap, gfx->image_gc, gfi->left, gfi->top, gfi->width, gfi->height); /*else { Pixmap mask = Gif_XMask(gfx, gfs, gfi); if (mask == None) return -1; XSetClipMask(gfx->display, gfx->image_gc, mask); XSetClipOrigin(gfx->display, gfx->image_gc, gfi->left, gfi->top); XFillRectangle(gfx->display, pixmap, gfx->image_gc, gfi->left, gfi->top, gfi->width, gfi->height); XSetClipMask(gfx->display, gfx->image_gc, None); XFreePixmap(gfx->display, mask); }*/ return 0; } static int apply_image(Gif_XContext *gfx, Gif_Stream *gfs, Gif_Image *gfi, Pixmap pixmap) { Pixmap image = Gif_XImage(gfx, gfs, gfi), mask; if (image == None) return -1; if (gfi->transparent >= 0) { mask = Gif_XMask(gfx, gfs, gfi); if (mask == None) { XFreePixmap(gfx->display, image); return -1; } XSetClipMask(gfx->display, gfx->image_gc, mask); XSetClipOrigin(gfx->display, gfx->image_gc, gfi->left, gfi->top); XCopyArea(gfx->display, image, pixmap, gfx->image_gc, 0, 0, gfi->width, gfi->height, gfi->left, gfi->top); XSetClipMask(gfx->display, gfx->image_gc, None); XFreePixmap(gfx->display, mask); } else { XCopyArea(gfx->display, image, pixmap, gfx->image_gc, 0, 0, gfi->width, gfi->height, gfi->left, gfi->top); } XFreePixmap(gfx->display, image); return 0; } static int fullscreen(Gif_Stream *gfs, Gif_Image *gfi, int require_opaque) { return (gfi->left == 0 && gfi->top == 0 && gfi->width == gfs->screen_width && gfi->height == gfs->screen_height && (!require_opaque || gfi->transparent < 0)); } Gif_XFrame * Gif_NewXFrames(Gif_Stream *gfs) { int i, last_postdisposal = -1; Gif_XFrame *fs = Gif_NewArray(Gif_XFrame, gfs->nimages); if (!fs) return 0; for (i = 0; i < gfs->nimages; ++i) { Gif_Image *gfi = gfs->images[i]; fs[i].pixmap = None; if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) fs[i].postdisposal = last_postdisposal; else fs[i].postdisposal = i; last_postdisposal = fs[i].postdisposal; } return fs; } void Gif_DeleteXFrames(Gif_XContext *gfx, Gif_Stream *gfs, Gif_XFrame *fs) { int i; for (i = 0; i < gfs->nimages; ++i) if (fs[i].pixmap) XFreePixmap(gfx->display, fs[i].pixmap); Gif_DeleteArray(fs); } Pixmap Gif_XNextImage(Gif_XContext *gfx, Gif_Stream *gfs, int i, Gif_XFrame *frames) { Pixmap result = None; unsigned long old_transparent = gfx->transparent_pixel; Gif_Image *gfi; int previ, scani; /* return already rendered pixmap if any */ if (frames[i].pixmap != None) return frames[i].pixmap; /* render fullscreen image */ gfi = gfs->images[i]; if (fullscreen(gfs, gfi, 1)) { frames[i].pixmap = Gif_XImage(gfx, gfs, gfi); return frames[i].pixmap; } /* image is not full screen, need to find background */ previ = i - 1; if (previ >= 0) previ = frames[previ].postdisposal; /* scan backwards for a renderable image */ scani = previ; while (scani >= 0 && frames[scani].pixmap == None && !fullscreen(gfs, gfs->images[scani], 1)) --scani; /* create the pixmap */ result = screen_pixmap(gfx, gfs); if (result == None) return None; /* scan forward to produce background */ gfi = (scani >= 0 ? gfs->images[scani] : 0); if (gfi && (gfi->disposal != GIF_DISPOSAL_BACKGROUND || !fullscreen(gfs, gfi, 1))) { /* perhaps we need to create an image (if so, must be fullscreen) */ if (frames[scani].pixmap == None) { frames[scani].pixmap = Gif_XImage(gfx, gfs, gfi); if (frames[scani].pixmap == None) goto error_exit; } XCopyArea(gfx->display, frames[scani].pixmap, result, gfx->image_gc, 0, 0, gfs->screen_width, gfs->screen_height, 0, 0); } if (!gfi || gfi->disposal == GIF_DISPOSAL_BACKGROUND) { if (apply_background(gfx, gfs, scani, result) < 0) goto error_exit; } while (scani < previ) { ++scani; gfi = gfs->images[scani]; if (gfi->disposal == GIF_DISPOSAL_BACKGROUND) { if (apply_background(gfx, gfs, scani, result) < 0) goto error_exit; } else if (gfi->disposal != GIF_DISPOSAL_PREVIOUS) { if (apply_image(gfx, gfs, gfs->images[scani], result) < 0) goto error_exit; } } /* apply image */ if (gfs->screen_width != 0 && gfs->screen_height != 0) { if (apply_image(gfx, gfs, gfs->images[i], result) < 0) goto error_exit; } frames[i].pixmap = result; return frames[i].pixmap; error_exit: XFreePixmap(gfx->display, result); gfx->transparent_pixel = old_transparent; return None; } /** CREATING AND DESTROYING XCONTEXTS **/ static void delete_xcolormap(Gif_XColormap *gfxc) { Gif_XContext *gfx = gfxc->x_context; Gif_XColormap *prev = 0, *trav = gfx->xcolormap; while (trav != gfxc && trav) { prev = trav; trav = trav->next; } if (gfx->free_deleted_colormap_pixels) deallocate_colors(gfxc); if (prev) prev->next = gfxc->next; else gfx->xcolormap = gfxc->next; Gif_DeleteArray(gfxc->pixels); Gif_Delete(gfxc); } static void delete_colormap_hook(int dummy, void *colormap_x, void *callback_x) { Gif_Colormap *gfcm = (Gif_Colormap *)colormap_x; Gif_XContext *gfx = (Gif_XContext *)callback_x; Gif_XColormap *gfxc; (void) dummy; for (gfxc = gfx->xcolormap; gfxc; gfxc = gfxc->next) if (gfxc->colormap == gfcm) { delete_xcolormap(gfxc); return; } } Gif_XContext * Gif_NewXContextFromVisual(Display *display, int screen_number, Visual *visual, int depth, Colormap colormap) { Gif_XContext *gfx; gfx = Gif_New(Gif_XContext); gfx->display = display; gfx->screen_number = screen_number; gfx->drawable = RootWindow(display, screen_number); gfx->visual = visual; gfx->colormap = colormap; gfx->ncolormap = visual->map_entries; gfx->depth = depth; gfx->closest = 0; gfx->nclosest = 0; gfx->free_deleted_colormap_pixels = 0; gfx->xcolormap = 0; gfx->image_gc = None; gfx->mask_gc = None; gfx->transparent_pixel = 0UL; gfx->foreground_pixel = 1UL; gfx->refcount = 0; Gif_AddDeletionHook(GIF_T_COLORMAP, delete_colormap_hook, gfx); return gfx; } Gif_XContext * Gif_NewXContext(Display *display, Window window) { XWindowAttributes attr; XGetWindowAttributes(display, window, &attr); return Gif_NewXContextFromVisual(display, XScreenNumberOfScreen(attr.screen), attr.visual, attr.depth, attr.colormap); } void Gif_DeleteXContext(Gif_XContext *gfx) { if (!gfx) return; if (--gfx->refcount > 0) return; while (gfx->xcolormap) delete_xcolormap(gfx->xcolormap); if (gfx->image_gc) XFreeGC(gfx->display, gfx->image_gc); if (gfx->mask_gc) XFreeGC(gfx->display, gfx->mask_gc); Gif_DeleteArray(gfx->closest); Gif_Delete(gfx); Gif_RemoveDeletionHook(GIF_T_COLORMAP, delete_colormap_hook, gfx); } #ifdef __cplusplus } #endif gifsicle-1.78/src/merge.c0000644000175000017500000002442112237442106012215 00000000000000/* merge.c - Functions which actually combine and manipulate GIF image data. Copyright (C) 1997-2013 Eddie Kohler, ekohler@gmail.com This file is part of gifsicle. Gifsicle is free software. It is distributed under the GNU Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #include #include "gifsicle.h" #include #include #include #include #include #include /* First merging stage: Mark the used colors in all colormaps. */ void unmark_colors(Gif_Colormap *gfcm) { int i; if (gfcm) for (i = 0; i < gfcm->ncol; i++) gfcm->col[i].haspixel = 0; } void unmark_colors_2(Gif_Colormap *gfcm) { int i; for (i = 0; i < gfcm->ncol; i++) { gfcm->col[i].pixel = 256; gfcm->col[i].haspixel = 0; } } void mark_used_colors(Gif_Stream *gfs, Gif_Image *gfi, Gt_Crop *crop, int compress_immediately) { Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global; Gif_Color *col = gfcm->col; int ncol = gfcm->ncol; int transp = gfi->transparent; int i, j, l, t, r, b, nleft; /* Mark color used for transparency. */ if (transp >= 0 && transp < ncol) col[transp].haspixel |= 2; /* Only mark colors until we've seen all of them. The left variable keeps track of how many are left. */ for (i = nleft = 0; i < ncol; ++i) if (!(col[i].haspixel & 1) && i != transp) ++nleft; if (nleft == 0) return; if (gfi->img || Gif_UncompressImage(gfi) == 2) compress_immediately = 0; /* Loop over every pixel (until we've seen all colors) */ if (crop) { Gt_Crop c; combine_crop(&c, crop, gfi); l = c.x; t = c.y; r = l + c.w; b = t + c.h; } else { l = t = 0; r = gfi->width; b = gfi->height; } for (j = t; j != b; ++j) { uint8_t *data = gfi->img[j] + l; for (i = l; i != r; ++i, ++data) if (*data < ncol && !(col[*data].haspixel & 1) && *data != transp) { col[*data].haspixel |= 1; --nleft; if (nleft == 0) goto done; } } done: if (compress_immediately) Gif_ReleaseUncompressedImage(gfi); } int find_color_index(Gif_Color *c, int nc, Gif_Color *color) { int index; for (index = 0; index < nc; index++) if (GIF_COLOREQ(&c[index], color)) return index; return -1; } int merge_colormap_if_possible(Gif_Colormap *dest, Gif_Colormap *src) { Gif_Color *srccol = src->col; Gif_Color *destcol = dest->col; int ndestcol = dest->ncol; int dest_userflags = dest->userflags; int i, x; int trivial_map = 1; for (i = 0; i < src->ncol; i++) { if (srccol[i].haspixel & 1) { /* Store an image color cell's mapping to the global colormap in its 'pixel' slot. This is useful caching: oftentimes many input frames will share a colormap */ int mapto = (srccol[i].pixel < 256 ? (int)srccol[i].pixel : -1); if (mapto == -1) mapto = find_color_index(destcol, ndestcol, &srccol[i]); if (mapto == -1 && ndestcol < 256) { /* add the color */ mapto = ndestcol; destcol[mapto] = srccol[i]; ndestcol++; } if (mapto == -1) /* check for a pure-transparent color */ for (x = 0; x < ndestcol; x++) if (destcol[x].haspixel == 2) { mapto = x; destcol[mapto] = srccol[i]; break; } if (mapto == -1) /* give up and require a local colormap */ goto local_colormap_required; assert(mapto >= 0 && mapto < ndestcol); assert(GIF_COLOREQ(&destcol[mapto], &srccol[i])); srccol[i].pixel = mapto; destcol[mapto].haspixel = 1; if (mapto != i) trivial_map = 0; } else if (srccol[i].haspixel & 2) { /* a dedicated transparent color; if trivial_map & at end of colormap insert it with haspixel == 2. (strictly not necessary; we do it to try to keep the map trivial.) */ if (trivial_map && i == ndestcol) { destcol[ndestcol] = srccol[i]; ndestcol++; } } } /* success! save new number of colors */ dest->ncol = ndestcol; dest->userflags = dest_userflags; return 1; /* failure: a local colormap is required */ local_colormap_required: if (warn_local_colormaps == 1) { static int context = 0; warning(1, "so many colors that local colormaps were required"); if (!context) warncontext(1, "(You may want to try '--colors 256'.)"); warn_local_colormaps = 2; context = 1; } /* 9.Dec.1998 - This must have been a longstanding bug! We MUST clear the cached mappings of any pixels in the source colormap we assigned this time through, since we are throwing those colors away. We assigned it this time through if the cached mapping is >= dest->ncol. */ for (x = 0; x < i; x++) if ((srccol[x].haspixel & 1) && srccol[x].pixel >= (uint32_t)dest->ncol) srccol[x].pixel = 256; return 0; } void merge_stream(Gif_Stream *dest, Gif_Stream *src, int no_comments) { int i; assert(dest->global); /* unmark colors in global and local colormaps -- 12/9 */ if (src->global) unmark_colors_2(src->global); for (i = 0; i < src->nimages; i++) if (src->images[i]->local) unmark_colors_2(src->images[i]->local); if (dest->loopcount < 0) dest->loopcount = src->loopcount; if (src->comment && !no_comments) { if (!dest->comment) dest->comment = Gif_NewComment(); merge_comments(dest->comment, src->comment); } } void merge_comments(Gif_Comment *destc, Gif_Comment *srcc) { int i; for (i = 0; i < srcc->count; i++) Gif_AddComment(destc, srcc->str[i], srcc->len[i]); } Gif_Image * merge_image(Gif_Stream *dest, Gif_Stream *src, Gif_Image *srci, int same_compressed_ok) { Gif_Colormap *imagecm; Gif_Color *imagecol; int islocal; int i; Gif_Colormap *localcm = 0; Gif_Colormap *destcm = dest->global; uint8_t map[256]; /* map[input pixel value] == output pixval */ int trivial_map = 1; /* does the map take input pixval --> the same pixel value for all colors in the image? */ uint8_t used[256]; /* used[output pixval K] == 1 iff K was used in the image */ Gif_Image *desti; /* mark colors that were actually used in this image */ islocal = srci->local != 0; imagecm = islocal ? srci->local : src->global; if (!imagecm) fatal_error("no global or local colormap for source image"); imagecol = imagecm->col; { int ncol = imagecm->ncol, nleft = 256 - ncol; int w = srci->width, h = srci->height, i, j; for (i = 0; i != ncol; ++i) imagecol[i].haspixel &= ~4; for (j = 0; j != h; ++j) { uint8_t *data = srci->img[j]; for (i = 0; i != w; ++i, ++data) if (*data < ncol && !(imagecol[*data].haspixel & 4)) { imagecol[*data].haspixel |= 4; --nleft; if (nleft == 0) goto done_mark; } } done_mark: if (srci->transparent >= 0 && srci->transparent < ncol) imagecol[srci->transparent].haspixel &= ~4; } /* map[old_pixel_value] == new_pixel_value */ for (i = 0; i < 256; i++) map[i] = used[i] = 0; /* Merge the colormap */ if (merge_colormap_if_possible(dest->global, imagecm)) { /* Create 'map' and 'used' for global colormap. */ for (i = 0; i < imagecm->ncol; i++) if (imagecol[i].haspixel & 4) { map[i] = imagecol[i].pixel; if (map[i] != i) trivial_map = 0; used[map[i]] = 1; } } else { /* Need a local colormap. */ int ncol = 0; destcm = localcm = Gif_NewFullColormap(0, 256); for (i = 0; i < imagecm->ncol; i++) if (imagecol[i].haspixel & 4) { map[i] = ncol; if (ncol != i) trivial_map = 0; used[ncol] = 1; localcm->col[ ncol++ ] = imagecol[i]; } localcm->ncol = ncol; } /* Decide on a transparent index */ if (srci->transparent >= 0) { int found_transparent = -1; /* try to keep the map trivial -- prefer same transparent index */ if (trivial_map && !used[srci->transparent]) found_transparent = srci->transparent; else for (i = destcm->ncol - 1; i >= 0; i--) if (!used[i]) found_transparent = i; /* 1.Aug.1999 - Allow for the case that the transparent index is bigger than the number of colors we've created thus far. */ if (found_transparent < 0 || found_transparent >= destcm->ncol) { Gif_Color *c; found_transparent = destcm->ncol; /* 1.Aug.1999 - Don't update destcm->ncol -- we want the output colormap to be as small as possible. */ c = &destcm->col[found_transparent]; if (srci->transparent < imagecm->ncol) *c = imagecol[srci->transparent]; c->haspixel = 2; assert(c->haspixel == 2 && found_transparent < 256); } map[srci->transparent] = found_transparent; if (srci->transparent != found_transparent) trivial_map = 0; } assert(destcm->ncol <= 256); /* Make the new image. */ desti = Gif_NewImage(); desti->identifier = Gif_CopyString(srci->identifier); if (srci->transparent > -1) desti->transparent = map[srci->transparent]; desti->delay = srci->delay; desti->disposal = srci->disposal; desti->left = srci->left; desti->top = srci->top; desti->interlace = srci->interlace; desti->width = srci->width; desti->height = srci->height; desti->local = localcm; if (srci->comment) { desti->comment = Gif_NewComment(); merge_comments(desti->comment, srci->comment); } if (trivial_map && same_compressed_ok && srci->compressed) { desti->compressed_len = srci->compressed_len; desti->compressed = Gif_NewArray(uint8_t, srci->compressed_len); desti->free_compressed = Gif_DeleteArrayFunc; memcpy(desti->compressed, srci->compressed, srci->compressed_len); } else { int i, j; Gif_CreateUncompressedImage(desti); if (trivial_map) for (j = 0; j < desti->height; j++) memcpy(desti->img[j], srci->img[j], desti->width); else for (j = 0; j < desti->height; j++) { uint8_t *srcdata = srci->img[j]; uint8_t *destdata = desti->img[j]; for (i = 0; i < desti->width; i++, srcdata++, destdata++) *destdata = map[*srcdata]; } } Gif_AddImage(dest, desti); return desti; } gifsicle-1.78/src/dmalloc.c0000644000175000017500000001026512237442106012532 00000000000000#include #include typedef struct bucket { size_t size; const char *file; int line; struct bucket *next; } bucket; #define NBUCK 5779 static bucket *buckets[NBUCK]; static int event_number; static FILE *verbose_out = 0; size_t dmalloc_live_memory; void * debug_malloc_id(size_t k, const char *file, int line) { void *p = malloc(k + sizeof(bucket)); bucket *b = (bucket *)p; int bnum = (((unsigned long)p) >> 4) % NBUCK; if (p == 0) { fprintf(stderr, "dmalloc:%s:%d: virtual memory exhausted (wanted %ld)\n", file, line, (long) k); abort(); } b->size = k; b->next = buckets[bnum]; b->file = file; b->line = line; buckets[bnum] = b; dmalloc_live_memory += k; p = (void *)(((char *)p) + sizeof(bucket)); /* memset(p, 99, b->size); */ if (verbose_out) fprintf(verbose_out, "%5d: %p +%-7d (%s:%d) ++ %ld\n", event_number, p, b->size, file, line, (long) dmalloc_live_memory); event_number++; return p; } void * debug_realloc_id(void *p, size_t k, const char *file, int line) { bucket *b_in = (bucket *)(((char *)p) - sizeof(bucket)); bucket *b; bucket *prev; bucket *new_b; int bnum = (((unsigned long)b_in) >> 4) % NBUCK; if (p == 0) return debug_malloc_id(k, file, line); for (b = buckets[bnum], prev = 0; b && b != b_in; prev = b, b = b->next) ; if (b == 0) { fprintf(stderr, "debug_realloc given bad pointer %p\n", p); abort(); } dmalloc_live_memory += k - b->size; if (verbose_out) fprintf(verbose_out, "%5d: %p +%-7ld (%s:%d) >> ", event_number, p, (long) b->size, b->file, b->line); new_b = (bucket *)realloc(b, k + sizeof(bucket)); if (new_b == 0) { fprintf(stderr, "dmalloc:%s:%d: virtual memory exhausted (wanted %ld)\n", file, line, (long) k); abort(); } new_b->size = k; if (new_b != b) { if (prev) prev->next = new_b->next; else buckets[bnum] = new_b->next; bnum = (((unsigned long)new_b) >> 4) % NBUCK; new_b->next = buckets[bnum]; buckets[bnum] = new_b; p = (void *)(((char *)new_b) + sizeof(bucket)); } if (verbose_out) fprintf(verbose_out, "%p +%-7ld (%s:%d)\n", p, (long) k, file, line); event_number++; return p; } void debug_free_id(void *p, const char *file, int line) { bucket *b_in = (bucket *)(((char *)p) - sizeof(bucket)); bucket *b; bucket *prev; int chain_length = 0; int bnum = (((unsigned long)b_in) >> 4) % NBUCK; if (p == 0) return; for (b = buckets[bnum], prev = 0; b && b != b_in; prev = b, b = b->next) chain_length++; if (b == 0) { fprintf(stderr, "my_free given bad pointer %p\n", p); abort(); } dmalloc_live_memory -= b->size; if (prev) prev->next = b->next; else buckets[bnum] = b->next; /* memset(p, 97, b->size); */ if (verbose_out) fprintf(verbose_out, "%5d: %p +%-7ld (%s:%d) -- %s:%d %ld\n", event_number, p, (long) b->size, b->file, b->line, file, line, (long) dmalloc_live_memory); event_number++; free(b_in); } #undef debug_malloc #undef debug_realloc #undef debug_free void * debug_malloc(size_t k) { return debug_malloc_id(k, "", 0); } void * debug_realloc(void *p, size_t k) { return debug_realloc_id(p, k, "", 0); } void debug_free(void *p) { debug_free_id(p, "", 0); } void dmalloc_info(void *p) { bucket *b_in = (bucket *)(((char *)p) - sizeof(bucket)); bucket *b; int bnum = (((unsigned long)b_in) >> 4) % NBUCK; if (p == 0) fprintf(stderr, "dmalloc: 0x0\n"); else { for (b = buckets[bnum]; b && b != b_in; b = b->next) ; if (b == 0) { fprintf(stderr, "dmalloc: %p: not my pointer\n", p); } else { fprintf(stderr, "dmalloc: %p +%-7ld (%s:%d)\n", p, (long) b->size, b->file, b->line); } } } void dmalloc_report(void) { int i; bucket *b; fprintf(stderr, "dmalloc: %d bytes allocated\n", dmalloc_live_memory); for (i = 0; i < NBUCK; i++) for (b = buckets[i]; b; b = b->next) fprintf(stderr, "dmalloc: %p +%-7ld (%s:%d)\n", (void *)(((char *)b) + sizeof(bucket)), (long) b->size, b->file, b->line); } void dmalloc_verbose(const char *out_name) { if (out_name) verbose_out = fopen(out_name, "w"); else verbose_out = stdout; } gifsicle-1.78/src/Makefile.am0000644000175000017500000000162012244135227013003 00000000000000## Process this file with automake to produce Makefile.in AUTOMAKE_OPTIONS = foreign check-news bin_PROGRAMS = gifsicle @OTHERPROGRAMS@ EXTRA_PROGRAMS = gifview gifdiff LDADD = @MALLOC_O@ @LIBOBJS@ gifsicle_LDADD = $(LDADD) @GIFWRITE_O@ gifview_LDADD = $(LDADD) @X_LIBS@ @X_PRE_LIBS@ -lX11 @X_EXTRA_LIBS@ gifsicle_DEPENDENCIES = @GIFWRITE_O@ @MALLOC_O@ @LIBOBJS@ gifview_DEPENDENCIES = @MALLOC_O@ @LIBOBJS@ gifdiff_DEPENDENCIES = @MALLOC_O@ @LIBOBJS@ WERROR = @WERROR@ gifsicle_SOURCES = clp.c \ giffunc.c gifread.c gifunopt.c \ gifsicle.h merge.c optimize.c quantize.c support.c xform.c \ gifsicle.c gifview_SOURCES = clp.c \ giffunc.c gifread.c gifx.c \ gifview.c gifdiff_SOURCES = clp.c \ giffunc.c gifread.c \ gifdiff.c AM_CPPFLAGS = $(X_CFLAGS) $(WERROR) -I$(top_srcdir)/include EXTRA_DIST = dmalloc.h dmalloc.c fmalloc.c gifwrite.c ungifwrt.c \ Makefile.bcc Makefile.w32 win32cfg.h gifsicle-1.78/src/xform.c0000644000175000017500000003015712243663074012262 00000000000000/* xform.c - Image transformation functions for gifsicle. Copyright (C) 1997-2013 Eddie Kohler, ekohler@gmail.com This file is part of gifsicle. Gifsicle is free software. It is distributed under the GNU Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #include #include "gifsicle.h" #include #include #include #include #include #include #ifdef HAVE_UNISTD_H # include #endif /****** * color transforms **/ Gt_ColorTransform * append_color_transform(Gt_ColorTransform *list, color_transform_func func, void *data) { Gt_ColorTransform *trav; Gt_ColorTransform *xform = Gif_New(Gt_ColorTransform); xform->next = 0; xform->func = func; xform->data = data; for (trav = list; trav && trav->next; trav = trav->next) ; if (trav) { trav->next = xform; return list; } else return xform; } Gt_ColorTransform * delete_color_transforms(Gt_ColorTransform *list, color_transform_func func) { Gt_ColorTransform *prev = 0, *trav = list; while (trav) { Gt_ColorTransform *next = trav->next; if (trav->func == func) { if (prev) prev->next = next; else list = next; Gif_Delete(trav); } else prev = trav; trav = next; } return list; } void apply_color_transforms(Gt_ColorTransform *list, Gif_Stream *gfs) { int i; Gt_ColorTransform *xform; for (xform = list; xform; xform = xform->next) { if (gfs->global) xform->func(gfs->global, xform->data); for (i = 0; i < gfs->nimages; i++) if (gfs->images[i]->local) xform->func(gfs->images[i]->local, xform->data); } } typedef struct Gt_ColorChange { struct Gt_ColorChange *next; Gif_Color old_color; Gif_Color new_color; } Gt_ColorChange; void color_change_transformer(Gif_Colormap *gfcm, void *thunk) { int i, have; Gt_ColorChange *first_change = (Gt_ColorChange *)thunk; Gt_ColorChange *change; /* change colors named by color */ for (i = 0; i < gfcm->ncol; i++) for (change = first_change; change; change = change->next) { if (!change->old_color.haspixel) have = GIF_COLOREQ(&gfcm->col[i], &change->old_color); else have = (change->old_color.pixel == (uint32_t)i); if (have) { gfcm->col[i] = change->new_color; break; /* ignore remaining color changes */ } } } Gt_ColorTransform * append_color_change(Gt_ColorTransform *list, Gif_Color old_color, Gif_Color new_color) { Gt_ColorTransform *xform; Gt_ColorChange *change = Gif_New(Gt_ColorChange); change->old_color = old_color; change->new_color = new_color; change->next = 0; for (xform = list; xform && xform->next; xform = xform->next) ; if (!xform || xform->func != &color_change_transformer) return append_color_transform(list, &color_change_transformer, change); else { Gt_ColorChange *prev = (Gt_ColorChange *)(xform->data); while (prev->next) prev = prev->next; prev->next = change; return list; } } void pipe_color_transformer(Gif_Colormap *gfcm, void *thunk) { int i, status; FILE *f; Gif_Color *col = gfcm->col; Gif_Colormap *new_cm = 0; char *command = (char *)thunk; #ifdef HAVE_MKSTEMP # ifdef P_tmpdir char tmp_file[] = P_tmpdir "/gifsicle.XXXXXX"; # else char tmp_file[] = "/tmp/gifsicle.XXXXXX"; # endif #else char *tmp_file = tmpnam(0); #endif char *new_command; #ifdef HAVE_MKSTEMP if (mkstemp(tmp_file) < 0) fatal_error("can't create temporary file!"); #else if (!tmp_file) fatal_error("can't create temporary file!"); #endif new_command = Gif_NewArray(char, strlen(command) + strlen(tmp_file) + 4); sprintf(new_command, "%s >%s", command, tmp_file); f = popen(new_command, "w"); if (!f) fatal_error("can't run color transformation command: %s", strerror(errno)); Gif_DeleteArray(new_command); for (i = 0; i < gfcm->ncol; i++) fprintf(f, "%d %d %d\n", col[i].gfc_red, col[i].gfc_green, col[i].gfc_blue); errno = 0; status = pclose(f); if (status < 0) { error(1, "color transformation error: %s", strerror(errno)); goto done; } else if (status > 0) { error(1, "color transformation command failed"); goto done; } f = fopen(tmp_file, "r"); if (!f || feof(f)) { error(1, "color transformation command generated no output", command); if (f) fclose(f); goto done; } new_cm = read_colormap_file("", f); fclose(f); if (new_cm) { int nc = new_cm->ncol; if (nc < gfcm->ncol) { nc = gfcm->ncol; warning(1, "too few colors in color transformation results"); } else if (nc > gfcm->ncol) warning(1, "too many colors in color transformation results"); for (i = 0; i < nc; i++) col[i] = new_cm->col[i]; } done: remove(tmp_file); Gif_DeleteColormap(new_cm); } /***** * crop image; returns true if the image exists **/ void combine_crop(Gt_Crop *dstcrop, const Gt_Crop *srccrop, const Gif_Image *gfi) { dstcrop->x = srccrop->x - gfi->left; dstcrop->y = srccrop->y - gfi->top; dstcrop->w = srccrop->w; dstcrop->h = srccrop->h; /* Check that the rectangle actually intersects with the image. */ if (dstcrop->x < 0) dstcrop->w += dstcrop->x, dstcrop->x = 0; if (dstcrop->y < 0) dstcrop->h += dstcrop->y, dstcrop->y = 0; if (dstcrop->w > 0 && dstcrop->x + dstcrop->w > gfi->width) dstcrop->w = gfi->width - dstcrop->x; if (dstcrop->h > 0 && dstcrop->y + dstcrop->h > gfi->height) dstcrop->h = gfi->height - dstcrop->y; if (dstcrop->w < 0) dstcrop->w = 0; if (dstcrop->h < 0) dstcrop->h = 0; } int crop_image(Gif_Image *gfi, Gt_Crop *crop, int preserve_total_crop) { Gt_Crop c; int j; uint8_t **img; combine_crop(&c, crop, gfi); if (c.w > 0 && c.h > 0) { img = Gif_NewArray(uint8_t *, c.h + 1); for (j = 0; j < c.h; j++) img[j] = gfi->img[c.y + j] + c.x; img[c.h] = 0; gfi->left += c.x - crop->left_offset; gfi->top += c.y - crop->top_offset; } else if (preserve_total_crop) { c.w = c.h = 1; img = Gif_NewArray(uint8_t *, c.h + 1); img[0] = gfi->img[0]; img[1] = 0; gfi->transparent = img[0][0]; } else { /* Empty image */ c.w = c.h = 0; img = 0; } Gif_DeleteArray(gfi->img); gfi->img = img; gfi->width = c.w; gfi->height = c.h; return gfi->img != 0; } /***** * flip and rotate **/ void flip_image(Gif_Image *gfi, int screen_width, int screen_height, int is_vert) { int x, y; int width = gfi->width; int height = gfi->height; uint8_t **img = gfi->img; /* horizontal flips */ if (!is_vert) { uint8_t *buffer = Gif_NewArray(uint8_t, width); uint8_t *trav; for (y = 0; y < height; y++) { memcpy(buffer, img[y], width); trav = img[y] + width - 1; for (x = 0; x < width; x++) *trav-- = buffer[x]; } gfi->left = screen_width - (gfi->left + width); Gif_DeleteArray(buffer); } /* vertical flips */ if (is_vert) { uint8_t **buffer = Gif_NewArray(uint8_t *, height); memcpy(buffer, img, height * sizeof(uint8_t *)); for (y = 0; y < height; y++) img[y] = buffer[height - y - 1]; gfi->top = screen_height - (gfi->top + height); Gif_DeleteArray(buffer); } } void rotate_image(Gif_Image *gfi, int screen_width, int screen_height, int rotation) { int x, y; int width = gfi->width; int height = gfi->height; uint8_t **img = gfi->img; uint8_t *new_data = Gif_NewArray(uint8_t, width * height); uint8_t *trav = new_data; /* this function can only rotate by 90 or 270 degrees */ assert(rotation == 1 || rotation == 3); if (rotation == 1) { for (x = 0; x < width; x++) for (y = height - 1; y >= 0; y--) *trav++ = img[y][x]; x = gfi->left; gfi->left = screen_height - (gfi->top + height); gfi->top = x; } else { for (x = width - 1; x >= 0; x--) for (y = 0; y < height; y++) *trav++ = img[y][x]; y = gfi->top; gfi->top = screen_width - (gfi->left + width); gfi->left = y; } Gif_ReleaseUncompressedImage(gfi); gfi->width = height; gfi->height = width; Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0); } /***** * scale **/ static void scale_image(Gif_Stream *gfs, Gif_Image *gfi, uint16_t* xoff, uint16_t* yoff) { uint8_t *new_data, *in_line, *out_data; int new_width, new_height; int was_compressed = (gfi->img == 0); int i, j, k; /* Fri 9 Jan 1999: Fix problem with resizing animated GIFs: we scaled from left edge of the *subimage* to right edge of the subimage, causing consistency problems when several subimages overlap. Solution: always use scale factors relating to the *whole image* (the screen size). */ /* calculate new width and height based on the four edges (left, right, top, bottom). This is better than simply multiplying the width and height by the scale factors because it avoids roundoff inconsistencies between frames on animated GIFs. Don't allow 0-width or 0-height images; GIF doesn't support them well. */ if (xoff[gfi->left + gfi->width] <= xoff[gfi->left] || yoff[gfi->top + gfi->height] <= yoff[gfi->top]) { new_width = new_height = 1; gfi->transparent = 0; gfi->disposal = GIF_DISPOSAL_ASIS; new_data = Gif_NewArray(uint8_t, 1); new_data[0] = 0; goto done; } xoff += gfi->left; yoff += gfi->top; new_width = xoff[gfi->width] - xoff[0]; new_height = yoff[gfi->height] - yoff[0]; if (was_compressed) Gif_UncompressImage(gfi); new_data = Gif_NewArray(uint8_t, new_width * new_height); out_data = new_data; for (j = 0; j < gfi->height; ++j) if (yoff[j] != yoff[j+1]) { in_line = gfi->img[j]; for (i = 0; i < gfi->width; ++i, ++in_line) for (k = xoff[i]; k != xoff[i+1]; ++k, ++out_data) *out_data = *in_line; for (i = yoff[j] + 1; i != yoff[j+1]; ++i, out_data += new_width) memcpy(out_data, out_data - new_width, new_width); } done: Gif_ReleaseUncompressedImage(gfi); Gif_ReleaseCompressedImage(gfi); gfi->left = xoff[0]; gfi->top = yoff[0]; gfi->width = new_width; gfi->height = new_height; Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0); if (was_compressed) { Gif_FullCompressImage(gfs, gfi, &gif_write_info); Gif_ReleaseUncompressedImage(gfi); } } void resize_stream(Gif_Stream *gfs, double new_width, double new_height, int fit) { double xfactor, yfactor; uint16_t* xarr; int i, nw, nh; Gif_CalculateScreenSize(gfs, 0); if (new_width < 0.5 && new_height < 0.5) /* do nothing */ return; else if (new_width < 0.5) new_width = (int) (gfs->screen_width * new_height / gfs->screen_height + 0.5); else if (new_height < 0.5) new_height = (int) (gfs->screen_height * new_width / gfs->screen_width + 0.5); if (new_width >= GIF_MAX_SCREEN_WIDTH + 0.5 || new_height >= GIF_MAX_SCREEN_HEIGHT + 0.5) fatal_error("new image is too large (max size 65535x65535)"); nw = (int) (new_width + 0.5); nh = (int) (new_height + 0.5); xfactor = (double) nw / gfs->screen_width; yfactor = (double) nh / gfs->screen_height; if (fit && nw >= gfs->screen_width && nh >= gfs->screen_height) return; else if (fit && xfactor < yfactor) { nh = (int) (gfs->screen_height * xfactor + 0.5); yfactor = (double) nh / gfs->screen_height; } else if (fit && yfactor < xfactor) { nw = (int) (gfs->screen_width * yfactor + 0.5); xfactor = (double) nw / gfs->screen_width; } xarr = Gif_NewArray(uint16_t, gfs->screen_width + gfs->screen_height + 2); for (i = 0; i != gfs->screen_width + 1; ++i) xarr[i] = (int) (i * xfactor + 0.5); for (i = 0; i != gfs->screen_height + 1; ++i) xarr[gfs->screen_width + 1 + i] = (int) (i * yfactor + 0.5); for (i = 0; i < gfs->nimages; i++) scale_image(gfs, gfs->images[i], &xarr[0], &xarr[gfs->screen_width + 1]); Gif_DeleteArray(xarr); gfs->screen_width = nw; gfs->screen_height = nh; } gifsicle-1.78/src/gifsicle.c0000644000175000017500000014742312245034333012711 00000000000000/* -*- c-basic-offset: 2 -*- */ /* gifsicle.c - gifsicle's main loop. Copyright (C) 1997-2013 Eddie Kohler, ekohler@cs.ucla.edu This file is part of gifsicle. Gifsicle is free software. It is distributed under the GNU Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #include #include "gifsicle.h" #include #include #include #include #include #include /* Need _setmode under MS-DOS, to set stdin/stdout to binary mode */ /* Need _fsetmode under OS/2 for the same reason */ #if defined(_MSDOS) || defined(_WIN32) || defined(__EMX__) || defined(__DJGPP__) # include # include #endif #define static_assert(x, msg) switch ((int) (x)) case 0: case !!((int) (x)): Gt_Frame def_frame; Gt_Frameset *frames = 0; int first_input_frame = 0; Gt_Frameset *nested_frames = 0; Gif_Stream *input = 0; const char *input_name = 0; static int unoptimizing = 0; static int gif_read_flags = 0; static int nextfile = 0; Gif_CompressInfo gif_write_info; static int frames_done = 0; static int files_given = 0; int warn_local_colormaps = 1; static Gt_ColorTransform *input_transforms; static Gt_ColorTransform *output_transforms; int mode = BLANK_MODE; int nested_mode = 0; static int infoing = 0; int verbosing = 0; #define CHANGED(next, flag) (((next) & 1<<(flag)) != 0) #define UNCHECKED_MARK_CH(where, what) \ next_##where |= 1< frame_spec_2) { i = frame_spec_1; frame_spec_1 = frame_spec_2; frame_spec_2 = i; } switch (kind) { case DELETE_OPT: mode = DELETING; break; case REPLACE_OPT: for (i = frame_spec_1; i < frame_spec_2; i++) FRAME(frames, i).use = 0; /* We want to use the last frame's delay, but nothing else about it. */ FRAME(frames, i).use = -1; /* FALLTHRU */ case INSERT_OPT: /* Define a nested frameset (or use an existing one). */ fset = FRAME(frames, frame_spec_2).nest; if (!fset) fset = new_frameset(8); FRAME(frames, frame_spec_2).nest = fset; /* Later: Merge frames at the end of the nested frameset. */ mode = INSERTING; nested_frames = frames; frames = fset; break; case APPEND_OPT: /* Just merge frames at the end of this frameset. */ mode = INSERTING; break; } } static void frame_change_done(void) { if (nested_mode) mode = nested_mode; if (nested_frames) frames = nested_frames; nested_mode = 0; nested_frames = 0; } static void show_frame(int imagenumber, int usename) { Gif_Image *gfi; Gt_Frame *frame; if (!input || !(gfi = Gif_GetImage(input, imagenumber))) return; switch (mode) { case MERGING: case INSERTING: case EXPLODING: case INFOING: case BATCHING: if (!frames_done) clear_frameset(frames, first_input_frame); frame = add_frame(frames, -1, input, gfi); if (usename) frame->explode_by_name = 1; break; case DELETING: frame = &FRAME(frames, first_input_frame + imagenumber); frame->use = 0; break; } next_frame = 0; frames_done = 1; } /***** * input a stream **/ static int gifread_error_count; static void gifread_error(int is_error, const char *message, int which_image, void *thunk) { static int last_is_error = 0; static int last_which_image = 0; static char last_message[256]; static int different_error_count = 0; static int same_error_count = 0; const char *filename = (const char *)thunk; /* ignore warnings if "no_warning" */ if (no_warnings && is_error == 0) return; if (gifread_error_count == 0) { last_which_image = -1; last_message[0] = 0; different_error_count = 0; } gifread_error_count++; if (last_message[0] && different_error_count <= 10 && (last_which_image != which_image || message == 0 || strcmp(message, last_message) != 0)) { const char *etype = last_is_error ? "error" : "warning"; error(0, "While reading '%s' frame #%d:", filename, last_which_image); if (same_error_count == 1) error(0, " %s: %s", etype, last_message); else if (same_error_count > 0) error(0, " %s: %s (%d times)", etype, last_message, same_error_count); same_error_count = 0; last_message[0] = 0; } if (message) { if (last_message[0] == 0) different_error_count++; same_error_count++; strcpy(last_message, message); last_which_image = which_image; last_is_error = is_error; } else last_message[0] = 0; if (different_error_count == 11 && message) { error(0, "(more errors while reading '%s')", filename); different_error_count++; } } struct StoredFile { FILE *f; struct StoredFile *next; char name[1]; }; static struct StoredFile *stored_files = 0; static FILE * open_giffile(const char *name) { struct StoredFile *sf; FILE *f; if (name == 0 || strcmp(name, "-") == 0) { #ifndef OUTPUT_GIF_TO_TERMINAL extern int isatty(int); if (isatty(fileno(stdin))) { error(0, ": is a terminal"); return NULL; } #endif #if defined(_MSDOS) || defined(_WIN32) _setmode(_fileno(stdin), _O_BINARY); #elif defined(__DJGPP__) setmode(fileno(stdin), O_BINARY); #elif defined(__EMX__) _fsetmode(stdin, "b"); #endif return stdin; } if (nextfile) for (sf = stored_files; sf; sf = sf->next) if (strcmp(name, sf->name) == 0) return sf->f; f = fopen(name, "rb"); if (f && nextfile) { sf = (struct StoredFile *) malloc(sizeof(struct StoredFile) + strlen(name)); sf->f = f; sf->next = stored_files; stored_files = sf; strcpy(sf->name, name); } else if (!f) error(0, "%s: %s", name, strerror(errno)); return f; } static void close_giffile(FILE *f, int final) { struct StoredFile **sf_pprev, *sf; if (!final && nextfile) { int c = getc(f); if (c == EOF) final = 1; else ungetc(c, f); } for (sf_pprev = &stored_files; (sf = *sf_pprev); sf_pprev = &sf->next) if (sf->f == f) { if (final) { fclose(f); *sf_pprev = sf->next; free((void *) sf); } return; } if (f != stdin) fclose(f); } void input_stream(const char *name) { static char *component_namebuf = 0; FILE *f; Gif_Stream *gfs; int i; int saved_next_frame = next_frame; int componentno = 0; const char *main_name = 0; Gt_Frame old_def_frame; input = 0; input_name = name; frames_done = 0; next_frame = 0; next_input = 0; if (next_output) combine_output_options(); files_given++; set_mode(BLANK_MODE); f = open_giffile(name); if (!f) return; if (f == stdin) { name = ""; input_name = 0; } main_name = name; retry_file: /* change filename for component files */ componentno++; if (componentno > 1) { free(component_namebuf); component_namebuf = malloc(strlen(main_name) + 10); sprintf(component_namebuf, "%s~%d", main_name, componentno); name = component_namebuf; } /* check for empty file */ i = getc(f); if (i == EOF) { if (!(gif_read_flags & GIF_READ_TRAILING_GARBAGE_OK)) error(0, "%s: empty file", name); else if (nextfile) error(0, "%s: no more images in file", name); close_giffile(f, 1); return; } ungetc(i, f); if (verbosing) verbose_open('<', name); /* read file */ gifread_error_count = 0; gfs = Gif_FullReadFile(f, gif_read_flags | GIF_READ_COMPRESSED, gifread_error, (void *)name); gifread_error(-1, 0, -1, (void *)name); /* print out last error message */ if (!gfs || (Gif_ImageCount(gfs) == 0 && gfs->errors > 0)) { if (componentno == 1) error(0, "%s: file not in GIF format", name); else error(0, "%s: trailing garbage ignored", main_name); Gif_DeleteStream(gfs); if (verbosing) verbose_close('>'); close_giffile(f, 1); return; } /* special processing for components after the first */ if (componentno > 1) { if (mode == BATCHING || mode == INSERTING) fatal_error("%s: --multifile is useful only in merge mode"); input_done(); } input = gfs; /* Processing when we've got a new input frame */ set_mode(BLANK_MODE); if (active_output_data.output_name == 0) { /* Don't override explicit output names. This code works 'cause output_name is reset to 0 after each output. */ if (mode == BATCHING) active_output_data.output_name = input_name; else if (mode == EXPLODING) { /* Explode into current directory. */ const char *explode_name = (input_name ? input_name : "#stdin#"); const char *slash = strrchr(explode_name, PATHNAME_SEPARATOR); if (slash) active_output_data.output_name = slash + 1; else active_output_data.output_name = explode_name; } } /* This code rather sucks. Here's the problem: Since we consider options strictly sequentially, one at a time, we can't tell the difference between these: --name=X g.gif h.gif // name on g.gif #0 --name=X g.gif #2 h.gif // name on g.gif #2 g.gif --name=X #2 h.gif // name on g.gif #2 g.gif --name=X h.gif // name on h.gif #0 !!! Here's the solution. Mark when we CHANGE an option. After processing an input GIF, mark all the options as 'unchanged' -- but leave the VALUES as is. Then when we read the next frame, CLEAR the unchanged options. So it's like so: (* means changed, . means not.) [-.] --name=X [X*] g.gif [X.] #2 [-.] h.gif == name on g.gif #2 [-.] g.gif [-.] --name=X [X*] #2 [-.] h.gif == name on g.gif #2 [-.] --name=X [X*] g.gif [X.|-.] h.gif == name on g.gif #0 [-.] g.gif [-.] --name=X [X*] h.gif == name on h.gif #0 */ /* Clear old options from the last input stream */ if (!CHANGED(saved_next_frame, CH_NAME)) def_frame.name = 0; if (!CHANGED(saved_next_frame, CH_COMMENT)) def_frame.comment = 0; if (!CHANGED(saved_next_frame, CH_EXTENSION)) def_frame.extensions = 0; def_frame.input_filename = input_name; old_def_frame = def_frame; first_input_frame = frames->count; if (gfs->nimages > 1) def_frame.position_is_offset = 1; for (i = 0; i < gfs->nimages; i++) add_frame(frames, -1, gfs, gfs->images[i]); def_frame = old_def_frame; if (unoptimizing) if (!Gif_FullUnoptimize(gfs, GIF_UNOPTIMIZE_SIMPLEST_DISPOSAL)) { static int context = 0; warning(1, "GIF too complex to unoptimize", name); if (!context) { warncontext(1, "(The reason was local color tables or complex transparency."); warncontext(1, "Try running the GIF through 'gifsicle --colors=255' first.)"); } context = 1; } apply_color_transforms(input_transforms, gfs); gfs->refcount++; /* Read more files. */ if ((gif_read_flags & GIF_READ_TRAILING_GARBAGE_OK) && !nextfile) goto retry_file; close_giffile(f, 0); } void input_done(void) { if (!input) return; if (verbosing) verbose_close('>'); Gif_DeleteStream(input); input = 0; if (mode == DELETING) frame_change_done(); if (mode == BATCHING || mode == EXPLODING) output_frames(); } /***** * colormap stuff **/ static void set_new_fixed_colormap(const char *name) { int i; if (name && strcmp(name, "web") == 0) { Gif_Colormap *cm = Gif_NewFullColormap(216, 256); Gif_Color *col = cm->col; for (i = 0; i < 216; i++) { col[i].gfc_red = (i / 36) * 0x33; col[i].gfc_green = ((i / 6) % 6) * 0x33; col[i].gfc_blue = (i % 6) * 0x33; } def_output_data.colormap_fixed = cm; } else if (name && (strcmp(name, "gray") == 0 || strcmp(name, "grey") == 0)) { Gif_Colormap *cm = Gif_NewFullColormap(256, 256); Gif_Color *col = cm->col; for (i = 0; i < 256; i++) col[i].gfc_red = col[i].gfc_green = col[i].gfc_blue = i; def_output_data.colormap_fixed = cm; } else if (name && strcmp(name, "bw") == 0) { Gif_Colormap *cm = Gif_NewFullColormap(2, 256); cm->col[0].gfc_red = cm->col[0].gfc_green = cm->col[0].gfc_blue = 0; cm->col[1].gfc_red = cm->col[1].gfc_green = cm->col[1].gfc_blue = 255; def_output_data.colormap_fixed = cm; } else def_output_data.colormap_fixed = read_colormap_file(name, 0); } static void do_colormap_change(Gif_Stream *gfs) { if (active_output_data.colormap_fixed || active_output_data.colormap_size > 0) kc_set_gamma(active_output_data.colormap_gamma_type, active_output_data.colormap_gamma); if (active_output_data.colormap_fixed) colormap_stream(gfs, active_output_data.colormap_fixed, &active_output_data); if (active_output_data.colormap_size > 0) { int nhist; Gif_Color *hist; Gif_Colormap* (*adapt_func)(Gif_Color*, int, Gt_OutputData*); Gif_Colormap *new_cm; /* set up the histogram */ { int i, any_locals = 0; for (i = 0; i < gfs->nimages; i++) if (gfs->images[i]->local) any_locals = 1; hist = histogram(gfs, &nhist); if (nhist <= active_output_data.colormap_size && !any_locals && !active_output_data.colormap_fixed) { warning(1, "trivial adaptive palette (only %d colors in source)", nhist); return; } } switch (active_output_data.colormap_algorithm) { case COLORMAP_DIVERSITY: adapt_func = &colormap_flat_diversity; break; case COLORMAP_BLEND_DIVERSITY: adapt_func = &colormap_blend_diversity; break; case COLORMAP_MEDIAN_CUT: adapt_func = &colormap_median_cut; break; default: fatal_error("can't happen"); } new_cm = (*adapt_func)(hist, nhist, &active_output_data); colormap_stream(gfs, new_cm, &active_output_data); Gif_DeleteArray(hist); Gif_DeleteColormap(new_cm); } } /***** * output GIF images **/ static void write_stream(const char *output_name, Gif_Stream *gfs) { FILE *f; if (output_name) f = fopen(output_name, "wb"); else { #ifndef OUTPUT_GIF_TO_TERMINAL extern int isatty(int); if (isatty(fileno(stdout))) { error(0, ": is a terminal"); return; } #endif #if defined(_MSDOS) || defined(_WIN32) _setmode(_fileno(stdout), _O_BINARY); #elif defined(__DJGPP__) setmode(fileno(stdout), O_BINARY); #elif defined(__EMX__) _fsetmode(stdout, "b"); #endif f = stdout; output_name = ""; } if (f) { Gif_FullWriteFile(gfs, &gif_write_info, f); fclose(f); any_output_successful = 1; } else error(0, "%s: %s", output_name, strerror(errno)); } static void merge_and_write_frames(const char *outfile, int f1, int f2) { Gif_Stream *out; int compress_immediately; int colormap_change; int huge_stream; assert(!nested_mode); if (verbosing) verbose_open('[', outfile ? outfile : "#stdout#"); active_output_data.active_output_name = outfile; colormap_change = active_output_data.colormap_size > 0 || active_output_data.colormap_fixed; warn_local_colormaps = !colormap_change; compress_immediately = 1; if (!active_output_data.conserve_memory && (active_output_data.scaling || (active_output_data.optimizing & GT_OPT_MASK) || colormap_change)) compress_immediately = 0; out = merge_frame_interval(frames, f1, f2, &active_output_data, compress_immediately, &huge_stream); if (out) { if (active_output_data.scaling == GT_SCALING_RESIZE) resize_stream(out, active_output_data.resize_width, active_output_data.resize_height, 0); else if (active_output_data.scaling == GT_SCALING_SCALE) resize_stream(out, active_output_data.scale_x * out->screen_width, active_output_data.scale_y * out->screen_height, 0); else if (active_output_data.scaling == GT_SCALING_RESIZE_FIT) resize_stream(out, active_output_data.resize_width, active_output_data.resize_height, 1); if (colormap_change) do_colormap_change(out); if (output_transforms) apply_color_transforms(output_transforms, out); if (active_output_data.optimizing & GT_OPT_MASK) optimize_fragments(out, active_output_data.optimizing, huge_stream); write_stream(outfile, out); Gif_DeleteStream(out); } if (verbosing) verbose_close(']'); active_output_data.active_output_name = 0; } static void output_information(const char *outfile) { FILE *f; int i, j; Gt_Frame *fr; Gif_Stream *gfs; if (infoing == 2) f = stderr; else if (outfile == 0) f = stdout; else { f = fopen(outfile, "w"); if (!f) { error(0, "%s: %s", outfile, strerror(errno)); return; } } for (i = 0; i < frames->count; i++) FRAME(frames, i).stream->userflags = 97; for (i = 0; i < frames->count; i++) if (FRAME(frames, i).stream->userflags == 97) { fr = &FRAME(frames, i); gfs = fr->stream; gfs->userflags = 0; stream_info(f, gfs, fr->input_filename, fr->info_flags); for (j = i; j < frames->count; j++) if (FRAME(frames, j).stream == gfs) { fr = &FRAME(frames, j); image_info(f, gfs, fr->image, fr->info_flags); } } if (f != stderr && f != stdout) fclose(f); } void output_frames(void) { /* Use the current output name, not the stored output name. This supports 'gifsicle a.gif -o xxx'. It's not like any other option, but seems right: it fits the natural order -- input, then output. */ int i; const char *outfile = active_output_data.output_name; active_output_data.output_name = 0; /* Output information only now. */ if (infoing) output_information(outfile); if (infoing != 1 && frames->count > 0) switch (mode) { case MERGING: case BATCHING: case INFOING: merge_and_write_frames(outfile, 0, -1); break; case EXPLODING: { /* Use the current output name for consistency, even though that means we can't explode different frames to different names. Not a big deal anyway; they can always repeat the gif on the cmd line. */ int max_nimages = 0; for (i = 0; i < frames->count; i++) { Gt_Frame *fr = &FRAME(frames, i); if (fr->stream->nimages > max_nimages) max_nimages = fr->stream->nimages; } if (!outfile) /* Watch out! */ outfile = "-"; for (i = 0; i < frames->count; i++) { Gt_Frame *fr = &FRAME(frames, i); int imagenumber = Gif_ImageNumber(fr->stream, fr->image); char *explodename; const char *imagename = 0; if (fr->explode_by_name) imagename = fr->name ? fr->name : fr->image->identifier; explodename = explode_filename(outfile, imagenumber, imagename, max_nimages); merge_and_write_frames(explodename, i, i); } break; } case INSERTING: /* do nothing */ break; } active_next_output = 0; clear_frameset(frames, 0); /* cropping: clear the 'crop->ready' information, which depended on the last input image. */ if (def_frame.crop) def_frame.crop->ready = 0; } /***** * parsing arguments **/ int frame_argument(Clp_Parser *clp, const char *arg) { /* Returns 0 iff you should try a file named 'arg'. */ int val = parse_frame_spec(clp, arg, -1, 0); if (val == -97) return 0; else if (val > 0) { int i, delta = (frame_spec_1 <= frame_spec_2 ? 1 : -1); for (i = frame_spec_1; i != frame_spec_2 + delta; i += delta) show_frame(i, frame_spec_name != 0); if (next_output) combine_output_options(); return 1; } else return 1; } static int handle_extension(Clp_Parser *clp, int is_app) { Gif_Extension *gfex; const char *extension_type = clp->vstr; const char *extension_body = Clp_Shift(clp, 1); if (!extension_body) { Clp_OptionError(clp, "%O requires two arguments"); return 0; } UNCHECKED_MARK_CH(frame, CH_EXTENSION); if (is_app) gfex = Gif_NewExtension(255, extension_type); else if (!isdigit(extension_type[0]) && extension_type[1] == 0) gfex = Gif_NewExtension(extension_type[0], 0); else { long l = strtol(extension_type, (char **)&extension_type, 0); if (*extension_type != 0 || l < 0 || l >= 256) fatal_error("bad extension type: must be a number between 0 and 255"); gfex = Gif_NewExtension(l, 0); } gfex->data = (uint8_t *)extension_body; gfex->length = strlen(extension_body); gfex->next = def_frame.extensions; def_frame.extensions = gfex; return 1; } /***** * option processing **/ static void initialize_def_frame(void) { /* frame defaults */ def_frame.stream = 0; def_frame.image = 0; def_frame.use = 1; def_frame.name = 0; def_frame.no_name = 0; def_frame.comment = 0; def_frame.no_comments = 0; def_frame.interlacing = -1; def_frame.transparent.haspixel = 0; def_frame.left = -1; def_frame.top = -1; def_frame.position_is_offset = 0; def_frame.crop = 0; def_frame.delay = -1; def_frame.disposal = -1; def_frame.nest = 0; def_frame.explode_by_name = 0; def_frame.no_extensions = 0; def_frame.extensions = 0; def_frame.flip_horizontal = 0; def_frame.flip_vertical = 0; def_frame.total_crop = 0; /* output defaults */ def_output_data.output_name = 0; def_output_data.screen_width = -1; def_output_data.screen_height = -1; def_output_data.background.haspixel = 0; def_output_data.loopcount = -2; def_output_data.colormap_size = 0; def_output_data.colormap_fixed = 0; def_output_data.colormap_algorithm = COLORMAP_DIVERSITY; def_output_data.dither_type = dither_none; def_output_data.dither_name = "none"; def_output_data.colormap_gamma_type = KC_GAMMA_SRGB; def_output_data.colormap_gamma = 2.2; def_output_data.optimizing = 0; def_output_data.scaling = GT_SCALING_NONE; def_output_data.conserve_memory = 0; active_output_data = def_output_data; } static void combine_output_options(void) { int recent = next_output; next_output = active_next_output; #define COMBINE_ONE_OUTPUT_OPTION(value, field) \ if (CHANGED(recent, value)) { \ MARK_CH(output, value); \ active_output_data.field = def_output_data.field; \ } COMBINE_ONE_OUTPUT_OPTION(CH_OUTPUT, output_name); if (CHANGED(recent, CH_LOGICAL_SCREEN)) { MARK_CH(output, CH_LOGICAL_SCREEN); active_output_data.screen_width = def_output_data.screen_width; active_output_data.screen_height = def_output_data.screen_height; } COMBINE_ONE_OUTPUT_OPTION(CH_BACKGROUND, background); COMBINE_ONE_OUTPUT_OPTION(CH_LOOPCOUNT, loopcount); COMBINE_ONE_OUTPUT_OPTION(CH_OPTIMIZE, optimizing); COMBINE_ONE_OUTPUT_OPTION(CH_COLORMAP, colormap_size); COMBINE_ONE_OUTPUT_OPTION(CH_COLORMAP_METHOD, colormap_algorithm); if (CHANGED(recent, CH_USE_COLORMAP)) { MARK_CH(output, CH_USE_COLORMAP); if (def_output_data.colormap_fixed) def_output_data.colormap_fixed->refcount++; Gif_DeleteColormap(active_output_data.colormap_fixed); active_output_data.colormap_fixed = def_output_data.colormap_fixed; } if (CHANGED(recent, CH_DITHER)) { MARK_CH(output, CH_DITHER); active_output_data.dither_type = def_output_data.dither_type; active_output_data.dither_data = def_output_data.dither_data; } if (CHANGED(recent, CH_GAMMA)) { MARK_CH(output, CH_GAMMA); active_output_data.colormap_gamma_type = def_output_data.colormap_gamma_type; active_output_data.colormap_gamma = def_output_data.colormap_gamma; } if (CHANGED(recent, CH_RESIZE)) { MARK_CH(output, CH_RESIZE); active_output_data.scaling = def_output_data.scaling; active_output_data.resize_width = def_output_data.resize_width; active_output_data.resize_height = def_output_data.resize_height; active_output_data.scale_x = def_output_data.scale_x; active_output_data.scale_y = def_output_data.scale_y; } COMBINE_ONE_OUTPUT_OPTION(CH_MEMORY, conserve_memory); def_output_data.colormap_fixed = 0; def_output_data.output_name = 0; active_next_output |= next_output; next_output = 0; } static void redundant_option_warning(const char *option_type) { static int context = 0; warning(0, "redundant %s option", option_type); if (!context) { warncontext(0, "(The %s option was overridden by another %s option", option_type, option_type); warncontext(0, "before it had any effect.)"); } context = 1; } static void print_useless_options(const char *type_name, int value, const char *names[]) { int explanation_printed = 0; int i; if (!value) return; for (i = 0; i < 32; i++) if (CHANGED(value, i)) { warning(0, "useless %s-related %s option", names[i], type_name); if (!explanation_printed) warncontext(0, "(It didn't affect any %s.)", type_name); explanation_printed = 1; } } static Gt_Crop * copy_crop(Gt_Crop *oc) { Gt_Crop *nc = Gif_New(Gt_Crop); /* Memory leak on crops, but this just is NOT a problem. */ if (oc) *nc = *oc; else memset(nc, 0, sizeof(Gt_Crop)); nc->ready = 0; return nc; } /***** * main **/ int main(int argc, char *argv[]) { Clp_Parser* clp; /* Check SIZEOF constants (useful for Windows). If these assertions fail, you've used the wrong Makefile. You should've used Makefile.w32 for 32-bit Windows and Makefile.w64 for 64-bit Windows. */ static_assert(sizeof(unsigned int) == SIZEOF_UNSIGNED_INT, "unsigned int has the wrong size."); static_assert(sizeof(unsigned long) == SIZEOF_UNSIGNED_LONG, "unsigned long has the wrong size."); static_assert(sizeof(void*) == SIZEOF_VOID_P, "void* has the wrong size."); clp = Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options); Clp_AddStringListType (clp, LOOP_TYPE, Clp_AllowNumbers, "infinite", 0, "forever", 0, (const char*) 0); Clp_AddStringListType (clp, DISPOSAL_TYPE, Clp_AllowNumbers, "none", GIF_DISPOSAL_NONE, "asis", GIF_DISPOSAL_ASIS, "background", GIF_DISPOSAL_BACKGROUND, "bg", GIF_DISPOSAL_BACKGROUND, "previous", GIF_DISPOSAL_PREVIOUS, (const char*) 0); Clp_AddStringListType (clp, COLORMAP_ALG_TYPE, 0, "diversity", COLORMAP_DIVERSITY, "blend-diversity", COLORMAP_BLEND_DIVERSITY, "median-cut", COLORMAP_MEDIAN_CUT, (const char*) 0); Clp_AddStringListType (clp, OPTIMIZE_TYPE, Clp_AllowNumbers, "keep-empty", GT_OPT_KEEPEMPTY + 1, "no-keep-empty", GT_OPT_KEEPEMPTY, "drop-empty", GT_OPT_KEEPEMPTY, "no-drop-empty", GT_OPT_KEEPEMPTY + 1, (const char*) 0); Clp_AddType(clp, DIMENSIONS_TYPE, 0, parse_dimensions, 0); Clp_AddType(clp, POSITION_TYPE, 0, parse_position, 0); Clp_AddType(clp, SCALE_FACTOR_TYPE, 0, parse_scale_factor, 0); Clp_AddType(clp, FRAME_SPEC_TYPE, 0, parse_frame_spec, 0); Clp_AddType(clp, COLOR_TYPE, Clp_DisallowOptions, parse_color, 0); Clp_AddType(clp, RECTANGLE_TYPE, 0, parse_rectangle, 0); Clp_AddType(clp, TWO_COLORS_TYPE, Clp_DisallowOptions, parse_two_colors, 0); Clp_SetOptionChar(clp, '+', Clp_ShortNegated); Clp_SetErrorHandler(clp, clp_error_handler); program_name = Clp_ProgramName(clp); frames = new_frameset(16); initialize_def_frame(); Gif_InitCompressInfo(&gif_write_info); #ifdef DMALLOC dmalloc_verbose("fudge"); #endif /* Yep, I'm an idiot. GIF dimensions are unsigned 16-bit integers. I assume that these numbers will fit in an 'int'. This assertion tests that assumption. Really I should go through & change everything over, but it doesn't seem worth my time. */ { uint16_t m = 0xFFFFU; int i = m; assert(i > 0 && "configuration/lameness failure! bug the author!"); } while (1) { int opt = Clp_Next(clp); switch (opt) { /* MODE OPTIONS */ case 'b': set_mode(BATCHING); break; case 'm': set_mode(MERGING); break; case 'e': set_mode(EXPLODING); def_frame.explode_by_name = 0; break; case 'E': set_mode(EXPLODING); def_frame.explode_by_name = 1; break; /* INFORMATION OPTIONS */ case INFO_OPT: if (clp->negated) infoing = 0; else /* switch between infoing == 1 (suppress regular output) and 2 (don't suppress) */ infoing = (infoing == 1 ? 2 : 1); break; case COLOR_INFO_OPT: if (clp->negated) def_frame.info_flags &= ~INFO_COLORMAPS; else { def_frame.info_flags |= INFO_COLORMAPS; if (!infoing) infoing = 1; } break; case EXTENSION_INFO_OPT: if (clp->negated) def_frame.info_flags &= ~INFO_EXTENSIONS; else { def_frame.info_flags |= INFO_EXTENSIONS; if (!infoing) infoing = 1; } break; case SIZE_INFO_OPT: if (clp->negated) def_frame.info_flags &= ~INFO_SIZES; else { def_frame.info_flags |= INFO_SIZES; if (!infoing) infoing = 1; } break; case VERBOSE_OPT: verbosing = clp->negated ? 0 : 1; break; /* FRAME CHANGE OPTIONS */ case DELETE_OPT: case REPLACE_OPT: case INSERT_OPT: case APPEND_OPT: frame_change_done(); set_frame_change(opt); break; case ALTER_DONE_OPT: frame_change_done(); break; /* IMAGE OPTIONS */ case NAME_OPT: if (clp->negated) goto no_names; MARK_CH(frame, CH_NAME); def_frame.name = clp->vstr; break; no_names: case NO_NAME_OPT: MARK_CH(frame, CH_NAME); def_frame.no_name = 1; def_frame.name = 0; break; case SAME_NAME_OPT: def_frame.no_name = 0; def_frame.name = 0; break; case COMMENT_OPT: if (clp->negated) goto no_comments; MARK_CH(frame, CH_COMMENT); if (!def_frame.comment) def_frame.comment = Gif_NewComment(); Gif_AddComment(def_frame.comment, clp->vstr, -1); break; no_comments: case NO_COMMENTS_OPT: Gif_DeleteComment(def_frame.comment); def_frame.comment = 0; def_frame.no_comments = 1; break; case SAME_COMMENTS_OPT: def_frame.no_comments = 0; break; case 'i': MARK_CH(frame, CH_INTERLACE); def_frame.interlacing = clp->negated ? 0 : 1; break; case SAME_INTERLACE_OPT: def_frame.interlacing = -1; break; case POSITION_OPT: MARK_CH(frame, CH_POSITION); def_frame.left = clp->negated ? 0 : position_x; def_frame.top = clp->negated ? 0 : position_y; break; case SAME_POSITION_OPT: def_frame.left = -1; def_frame.top = -1; break; case 't': MARK_CH(frame, CH_TRANSPARENT); if (clp->negated) def_frame.transparent.haspixel = 255; else { def_frame.transparent = parsed_color; def_frame.transparent.haspixel = parsed_color.haspixel ? 2 : 1; } break; case SAME_TRANSPARENT_OPT: def_frame.transparent.haspixel = 0; break; case BACKGROUND_OPT: MARK_CH(output, CH_BACKGROUND); if (clp->negated) { def_output_data.background.haspixel = 2; def_output_data.background.pixel = 0; } else { def_output_data.background = parsed_color; def_output_data.background.haspixel = parsed_color.haspixel ? 2 : 1; } break; case SAME_BACKGROUND_OPT: MARK_CH(output, CH_BACKGROUND); def_output_data.background.haspixel = 0; break; case LOGICAL_SCREEN_OPT: MARK_CH(output, CH_LOGICAL_SCREEN); if (clp->negated) def_output_data.screen_width = def_output_data.screen_height = 0; else { def_output_data.screen_width = dimensions_x; def_output_data.screen_height = dimensions_y; } break; case SAME_LOGICAL_SCREEN_OPT: MARK_CH(output, CH_LOGICAL_SCREEN); def_output_data.screen_width = def_output_data.screen_height = -1; break; case CROP_OPT: if (clp->negated) goto no_crop; MARK_CH(frame, CH_CROP); { Gt_Crop *crop = copy_crop(def_frame.crop); /* Memory leak on crops, but this just is NOT a problem. */ crop->spec_x = position_x; crop->spec_y = position_y; crop->spec_w = dimensions_x; crop->spec_h = dimensions_y; def_frame.crop = crop; } break; no_crop: case SAME_CROP_OPT: def_frame.crop = 0; break; case CROP_TRANSPARENCY_OPT: if (clp->negated) goto no_crop_transparency; def_frame.crop = copy_crop(def_frame.crop); def_frame.crop->transparent_edges = 1; break; no_crop_transparency: if (def_frame.crop && def_frame.crop->transparent_edges) { def_frame.crop = copy_crop(def_frame.crop); def_frame.crop->transparent_edges = 0; } break; /* extensions options */ case NO_EXTENSIONS_OPT: def_frame.no_extensions = 1; break; case SAME_EXTENSIONS_OPT: def_frame.no_extensions = 0; break; case EXTENSION_OPT: if (!handle_extension(clp, 0)) goto bad_option; break; case APP_EXTENSION_OPT: if (!handle_extension(clp, 1)) goto bad_option; break; /* IMAGE DATA OPTIONS */ case FLIP_HORIZ_OPT: MARK_CH(frame, CH_FLIP); def_frame.flip_horizontal = !clp->negated; break; case FLIP_VERT_OPT: MARK_CH(frame, CH_FLIP); def_frame.flip_vertical = !clp->negated; break; case NO_FLIP_OPT: def_frame.flip_horizontal = def_frame.flip_vertical = 0; break; case NO_ROTATE_OPT: def_frame.rotation = 0; break; case ROTATE_90_OPT: MARK_CH(frame, CH_ROTATE); def_frame.rotation = 1; break; case ROTATE_180_OPT: MARK_CH(frame, CH_ROTATE); def_frame.rotation = 2; break; case ROTATE_270_OPT: MARK_CH(frame, CH_ROTATE); def_frame.rotation = 3; break; /* ANIMATION OPTIONS */ case 'd': MARK_CH(frame, CH_DELAY); def_frame.delay = clp->negated ? 0 : clp->val.i; break; case SAME_DELAY_OPT: def_frame.delay = -1; break; case DISPOSAL_OPT: MARK_CH(frame, CH_DISPOSAL); if (clp->negated) def_frame.disposal = GIF_DISPOSAL_NONE; else if (clp->val.i < 0 || clp->val.i > 7) error(0, "disposal must be between 0 and 7"); else def_frame.disposal = clp->val.i; break; case SAME_DISPOSAL_OPT: def_frame.disposal = -1; break; case 'l': MARK_CH(output, CH_LOOPCOUNT); if (clp->negated) def_output_data.loopcount = -1; else def_output_data.loopcount = (clp->have_val ? clp->val.i : 0); break; case SAME_LOOPCOUNT_OPT: MARK_CH(output, CH_LOOPCOUNT); def_output_data.loopcount = -2; break; case OPTIMIZE_OPT: { int o; UNCHECKED_MARK_CH(output, CH_OPTIMIZE); if (clp->negated || (clp->have_val && clp->val.i < 0)) o = 0; else o = (clp->have_val ? clp->val.i : 1); if (o > GT_OPT_MASK && (o & 1)) def_output_data.optimizing |= o - 1; else if (o > GT_OPT_MASK) def_output_data.optimizing &= ~o; else def_output_data.optimizing = (def_output_data.optimizing & ~GT_OPT_MASK) | o; break; } case UNOPTIMIZE_OPT: UNCHECKED_MARK_CH(input, CH_UNOPTIMIZE); unoptimizing = clp->negated ? 0 : 1; break; /* WHOLE-GIF OPTIONS */ case CAREFUL_OPT: { if (clp->negated) gif_write_info.flags = 0; else gif_write_info.flags = GIF_WRITE_CAREFUL_MIN_CODE_SIZE | GIF_WRITE_EAGER_CLEAR; break; } case CHANGE_COLOR_OPT: { next_input |= CH_CHANGE_COLOR; if (clp->negated) input_transforms = delete_color_transforms (input_transforms, &color_change_transformer); else if (parsed_color2.haspixel) error(0, "COLOR2 must be in RGB format in '--change-color COLOR1 COLOR2'"); else input_transforms = append_color_change (input_transforms, parsed_color, parsed_color2); break; } case COLOR_TRANSFORM_OPT: next_output |= CH_COLOR_TRANSFORM; if (clp->negated) output_transforms = delete_color_transforms (output_transforms, &pipe_color_transformer); else output_transforms = append_color_transform (output_transforms, &pipe_color_transformer, (void *)clp->vstr); break; case COLORMAP_OPT: MARK_CH(output, CH_COLORMAP); if (clp->negated) def_output_data.colormap_size = 0; else { def_output_data.colormap_size = clp->val.i; if (def_output_data.colormap_size < 2 || def_output_data.colormap_size > 256) { Clp_OptionError(clp, "argument to %O must be between 2 and 256"); def_output_data.colormap_size = 0; } } break; case GRAY_OPT: MARK_CH(output, CH_USE_COLORMAP); Gif_DeleteColormap(def_output_data.colormap_fixed); set_new_fixed_colormap("gray"); break; case USE_COLORMAP_OPT: MARK_CH(output, CH_USE_COLORMAP); Gif_DeleteColormap(def_output_data.colormap_fixed); if (clp->negated) def_output_data.colormap_fixed = 0; else set_new_fixed_colormap(clp->vstr); break; case COLORMAP_ALGORITHM_OPT: MARK_CH(output, CH_COLORMAP_METHOD); def_output_data.colormap_algorithm = clp->val.i; break; case DITHER_OPT: { const char* name; if (clp->negated) name = "none"; else if (!clp->have_val) name = "default"; else name = clp->val.s; if (strcmp(name, "posterize") == 0) name = "none"; if (strcmp(name, def_output_data.dither_name) != 0 && (strcmp(name, "none") == 0 || strcmp(def_output_data.dither_name, "default") != 0)) MARK_CH(output, CH_DITHER); UNCHECKED_MARK_CH(output, CH_DITHER); if (set_dither_type(&def_output_data, name) < 0) Clp_OptionError(clp, "%<%s%> is not a valid dither", name); def_output_data.dither_name = name; break; } case GAMMA_OPT: { #if HAVE_POW char* ends; MARK_CH(output, CH_GAMMA); if (clp->negated) { def_output_data.colormap_gamma_type = KC_GAMMA_NUMERIC; def_output_data.colormap_gamma = 1; } else if (strcmp(clp->val.s, "sRGB") == 0 || strcmp(clp->val.s, "srgb") == 0) def_output_data.colormap_gamma_type = KC_GAMMA_SRGB; else { double gamma = strtod(clp->val.s, &ends); if (*clp->val.s && !*ends && !isspace((unsigned char) *clp->val.s)) { def_output_data.colormap_gamma_type = KC_GAMMA_NUMERIC; def_output_data.colormap_gamma = gamma; } else Clp_OptionError(clp, "%O should be a number or %"); } #else Clp_OptionError(clp, "this version of Gifsicle does not support %O"); #endif break; } case RESIZE_OPT: case RESIZE_FIT_OPT: MARK_CH(output, CH_RESIZE); if (clp->negated) def_output_data.scaling = GT_SCALING_NONE; else if (dimensions_x <= 0 && dimensions_y <= 0) { error(0, "one of W and H must be positive in '%s WxH'", Clp_CurOptionName(clp)); def_output_data.scaling = GT_SCALING_NONE; } else { def_output_data.scaling = (opt == RESIZE_FIT_OPT ? GT_SCALING_RESIZE_FIT : GT_SCALING_RESIZE); def_output_data.resize_width = dimensions_x; def_output_data.resize_height = dimensions_y; } break; case RESIZE_WIDTH_OPT: case RESIZE_HEIGHT_OPT: case RESIZE_FIT_WIDTH_OPT: case RESIZE_FIT_HEIGHT_OPT: MARK_CH(output, CH_RESIZE); if (clp->negated) def_output_data.scaling = GT_SCALING_NONE; else if (clp->val.u == 0) { error(0, "%s argument must be positive", Clp_CurOptionName(clp)); def_output_data.scaling = GT_SCALING_NONE; } else { unsigned dimen[2] = {0, 0}; dimen[(opt == RESIZE_HEIGHT_OPT || opt == RESIZE_FIT_HEIGHT_OPT)] = clp->val.u; if (opt == RESIZE_FIT_WIDTH_OPT || opt == RESIZE_FIT_HEIGHT_OPT) def_output_data.scaling = GT_SCALING_RESIZE_FIT; else def_output_data.scaling = GT_SCALING_RESIZE; def_output_data.resize_width = dimen[0]; def_output_data.resize_height = dimen[1]; } break; case SCALE_OPT: MARK_CH(output, CH_RESIZE); if (clp->negated) def_output_data.scaling = GT_SCALING_NONE; else if (parsed_scale_factor_x <= 0 || parsed_scale_factor_y <= 0) { error(0, "%s X and Y factors must be positive", Clp_CurOptionName(clp)); def_output_data.scaling = GT_SCALING_NONE; } else { def_output_data.scaling = 2; /* use scale factor */ def_output_data.scale_x = parsed_scale_factor_x; def_output_data.scale_y = parsed_scale_factor_y; } break; /* RANDOM OPTIONS */ case NO_WARNINGS_OPT: no_warnings = !clp->negated; break; case WARNINGS_OPT: no_warnings = clp->negated; break; case CONSERVE_MEMORY_OPT: MARK_CH(output, CH_MEMORY); def_output_data.conserve_memory = !clp->negated; break; case MULTIFILE_OPT: if (clp->negated) gif_read_flags &= ~GIF_READ_TRAILING_GARBAGE_OK; else { gif_read_flags |= GIF_READ_TRAILING_GARBAGE_OK; nextfile = 0; } break; case NEXTFILE_OPT: if (clp->negated) gif_read_flags &= ~GIF_READ_TRAILING_GARBAGE_OK; else { gif_read_flags |= GIF_READ_TRAILING_GARBAGE_OK; nextfile = 1; } break; case VERSION_OPT: #ifdef GIF_UNGIF printf("LCDF Gifsicle %s (ungif)\n", VERSION); #else printf("LCDF Gifsicle %s\n", VERSION); #endif printf("Copyright (C) 1997-2013 Eddie Kohler\n\ This is free software; see the source for copying conditions.\n\ There is NO warranty, not even for merchantability or fitness for a\n\ particular purpose.\n"); exit(EXIT_OK); break; case HELP_OPT: usage(); exit(EXIT_OK); break; case OUTPUT_OPT: MARK_CH(output, CH_OUTPUT); if (strcmp(clp->vstr, "-") == 0) def_output_data.output_name = 0; else def_output_data.output_name = clp->vstr; break; /* NONOPTIONS */ case Clp_NotOption: if (clp->vstr[0] != '#' || !frame_argument(clp, clp->vstr)) { input_done(); input_stream(clp->vstr); } break; case Clp_Done: goto done; bad_option: case Clp_BadOption: short_usage(); exit(EXIT_USER_ERR); break; default: break; } } done: if (next_output) combine_output_options(); if (!files_given) input_stream(0); frame_change_done(); input_done(); if (mode == MERGING || mode == INFOING) output_frames(); verbose_endline(); print_useless_options("frame", next_frame, frame_option_types); print_useless_options("input", next_input, input_option_types); if (any_output_successful) print_useless_options("output", active_next_output, output_option_types); blank_frameset(frames, 0, 0, 1); #ifdef DMALLOC dmalloc_report(); #endif Clp_DeleteParser(clp); return (error_count ? EXIT_ERR : EXIT_OK); } gifsicle-1.78/src/clp.c0000644000175000017500000020767412243663074011717 00000000000000/* -*- related-file-name: "../include/lcdf/clp.h" -*- */ /* clp.c - Complete source code for CLP. * This file is part of CLP, the command line parser package. * * Copyright (c) 1997-2013 Eddie Kohler, ekohler@gmail.com * * CLP is free software. It is distributed under the GNU General Public * License, Version 2, or, alternatively and at your discretion, under the * more permissive (BSD-like) Click LICENSE file as described below. * * 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, subject to the * conditions listed in the Click LICENSE file, which is available in full at * http://github.com/kohler/click/blob/master/LICENSE. The conditions * include: you must preserve this copyright notice, and you cannot mention * the copyright holders in advertising related to the Software without * their permission. The Software is provided WITHOUT ANY WARRANTY, EXPRESS * OR IMPLIED. This notice is a summary of the Click LICENSE file; the * license in that file is binding. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #if HAVE_SYS_TYPES_H # include #endif /* By default, assume we have inttypes.h, strtoul, and uintptr_t. */ #if !defined(HAVE_STRTOUL) && !defined(HAVE_CONFIG_H) # define HAVE_STRTOUL 1 #endif #if defined(HAVE_INTTYPES_H) || !defined(HAVE_CONFIG_H) # include #endif #if !defined(HAVE_UINTPTR_T) && defined(HAVE_CONFIG_H) typedef unsigned long uintptr_t; #endif #ifdef __cplusplus extern "C" { #endif /** @file clp.h * @brief Functions for parsing command line options. * * The CLP functions are used to parse command line arugments into options. * It automatically handles value parsing, error messages, long options with * minimum prefix matching, short options, and negated options. * * The CLP model works like this. * *
    *
  1. The user declares an array of Clp_Option structures that define the * options their program accepts.
  2. *
  3. The user creates a Clp_Parser object using Clp_NewParser(), passing in * the command line arguments to parse and the Clp_Option structures.
  4. *
  5. A loop repeatedly calls Clp_Next() to parse the arguments.
  6. *
* * Unlike many command line parsing libraries, CLP steps through all arguments * one at a time, rather than slurping up all options at once. This makes it * meaningful to give an option more than once. * * Here's an example. * * @code * #define ANIMAL_OPT 1 * #define VEGETABLE_OPT 2 * #define MINERALS_OPT 3 * #define USAGE_OPT 4 * * static const Clp_Option options[] = { * { "animal", 'a', ANIMAL_OPT, Clp_ValString, 0 }, * { "vegetable", 'v', VEGETABLE_OPT, Clp_ValString, Clp_Negate | Clp_Optional }, * { "minerals", 'm', MINERALS_OPT, Clp_ValInt, 0 }, * { "usage", 0, USAGE_OPT, 0, 0 } * }; * * int main(int argc, char *argv[]) { * Clp_Parser *clp = Clp_NewParser(argc, argv, * sizeof(options) / sizeof(options[0]), options); * int opt; * while ((opt = Clp_Next(clp)) != Clp_Done) * switch (opt) { * case ANIMAL_OPT: * fprintf(stderr, "animal is %s\n", clp->val.s); * break; * case VEGETABLE_OPT: * if (clp->negated) * fprintf(stderr, "no vegetables!\n"); * else if (clp->have_val) * fprintf(stderr, "vegetable is %s\n", clp->val.s); * else * fprintf(stderr, "vegetables OK\n"); * break; * case MINERALS_OPT: * fprintf(stderr, "%d minerals\n", clp->val.i); * break; * case USAGE_OPT: * fprintf(stderr, "Usage: 20q [--animal=ANIMAL] [--vegetable[=VEGETABLE]] [--minerals=N]\n"); * break; * case Clp_NotOption: * fprintf(stderr, "non-option %s\n", clp->vstr); * break; * } * } * } * @endcode * * Here are a couple of executions. * *
 * % ./20q --animal=cat
 * animal is cat
 * % ./20q --animal=cat -a dog -afish --animal bird --an=snake
 * animal is cat
 * animal is dog
 * animal is fish
 * animal is bird
 * animal is snake
 * % ./20q --no-vegetables
 * no vegetables!
 * % ./20q -v
 * vegetables OK
 * % ./20q -vkale
 * vegetable is kale
 * % ./20q -m10
 * 10 minerals
 * % ./20q -m foo
 * '-m' expects an integer, not 'foo'
 * 
*/ /* Option types for Clp_SetOptionChar */ #define Clp_DoubledLong (Clp_LongImplicit * 2) #define Clp_InitialValType 8 #define MAX_AMBIGUOUS_VALUES 4 typedef struct { int val_type; Clp_ValParseFunc func; int flags; void *user_data; } Clp_ValType; typedef struct { unsigned ilong : 1; unsigned ishort : 1; unsigned imandatory : 1; unsigned ioptional : 1; unsigned ipos : 1; unsigned ineg : 1; unsigned iprefmatch : 1; unsigned lmmpos_short : 1; unsigned lmmneg_short : 1; unsigned char ilongoff; int lmmpos; int lmmneg; } Clp_InternOption; #define Clp_OptionCharsSize 5 typedef struct { int c; int type; } Clp_Oclass; #define Clp_OclassSize 10 typedef struct Clp_Internal { const Clp_Option *opt; Clp_InternOption *iopt; int nopt; unsigned opt_generation; Clp_ValType *valtype; int nvaltype; const char * const *argv; int argc; Clp_Oclass oclass[Clp_OclassSize]; int noclass; int long1pos; int long1neg; int utf8; char option_chars[Clp_OptionCharsSize]; const char *xtext; const char *program_name; void (*error_handler)(Clp_Parser *, const char *); int option_processing; int current_option; unsigned char is_short; unsigned char whole_negated; /* true if negated by an option character */ unsigned char could_be_short; unsigned char current_short; unsigned char negated_by_no; int ambiguous; int ambiguous_values[MAX_AMBIGUOUS_VALUES]; } Clp_Internal; struct Clp_ParserState { const char * const *argv; int argc; char option_chars[Clp_OptionCharsSize]; const char *xtext; int option_processing; unsigned opt_generation; int current_option; unsigned char is_short; unsigned char whole_negated; unsigned char current_short; unsigned char negated_by_no; }; typedef struct Clp_StringList { Clp_Option *items; Clp_InternOption *iopt; int nitems; unsigned char allow_int; unsigned char val_long; int nitems_invalid_report; } Clp_StringList; static const Clp_Option clp_option_sentinel[] = { {"", 0, Clp_NotOption, 0, 0}, {"", 0, Clp_Done, 0, 0}, {"", 0, Clp_BadOption, 0, 0}, {"", 0, Clp_Error, 0, 0} }; static int parse_string(Clp_Parser *, const char *, int, void *); static int parse_int(Clp_Parser *, const char *, int, void *); static int parse_bool(Clp_Parser *, const char *, int, void *); static int parse_double(Clp_Parser *, const char *, int, void *); static int parse_string_list(Clp_Parser *, const char *, int, void *); static int ambiguity_error(Clp_Parser *, int, int *, const Clp_Option *, const Clp_InternOption *, const char *, const char *, ...); /******* * utf8 **/ #define U_REPLACEMENT 0xFFFD static char * encode_utf8(char *s, int n, int c) { if (c < 0 || c >= 0x110000 || (c >= 0xD800 && c <= 0xDFFF)) c = U_REPLACEMENT; if (c <= 0x7F && n >= 1) *s++ = c; else if (c <= 0x7FF && n >= 2) { *s++ = 0xC0 | (c >> 6); goto char1; } else if (c <= 0xFFFF && n >= 3) { *s++ = 0xE0 | (c >> 12); goto char2; } else if (n >= 4) { *s++ = 0xF0 | (c >> 18); *s++ = 0x80 | ((c >> 12) & 0x3F); char2: *s++ = 0x80 | ((c >> 6) & 0x3F); char1: *s++ = 0x80 | (c & 0x3F); } return s; } static int decode_utf8(const char *s, const char **cp) { int c; if ((unsigned char) *s <= 0x7F) /* 1 byte: 0x000000-0x00007F */ c = *s++; else if ((unsigned char) *s <= 0xC1) /* bad/overlong encoding */ goto replacement; else if ((unsigned char) *s <= 0xDF) { /* 2 bytes: 0x000080-0x0007FF */ if ((s[1] & 0xC0) != 0x80) /* bad encoding */ goto replacement; c = (*s++ & 0x1F) << 6; goto char1; } else if ((unsigned char) *s <= 0xEF) { /* 3 bytes: 0x000800-0x00FFFF */ if ((s[1] & 0xC0) != 0x80 /* bad encoding */ || (s[2] & 0xC0) != 0x80 /* bad encoding */ || ((unsigned char) *s == 0xE0 /* overlong encoding */ && (s[1] & 0xE0) == 0x80) || ((unsigned char) *s == 0xED /* encoded surrogate */ && (s[1] & 0xE0) == 0xA0)) goto replacement; c = (*s++ & 0x0F) << 12; goto char2; } else if ((unsigned char) *s <= 0xF4) { /* 4 bytes: 0x010000-0x10FFFF */ if ((s[1] & 0xC0) != 0x80 /* bad encoding */ || (s[2] & 0xC0) != 0x80 /* bad encoding */ || (s[3] & 0xC0) != 0x80 /* bad encoding */ || ((unsigned char) *s == 0xF0 /* overlong encoding */ && (s[1] & 0xF0) == 0x80) || ((unsigned char) *s == 0xF4 /* encoded value > 0x10FFFF */ && (unsigned char) s[1] >= 0x90)) goto replacement; c = (*s++ & 0x07) << 18; c += (*s++ & 0x3F) << 12; char2: c += (*s++ & 0x3F) << 6; char1: c += (*s++ & 0x3F); } else { replacement: c = U_REPLACEMENT; for (s++; (*s & 0xC0) == 0x80; s++) /* nothing */; } if (cp) *cp = s; return c; } static int utf8_charlen(const char *s) { const char *sout; (void) decode_utf8(s, &sout); return sout - s; } static int clp_utf8_charlen(const Clp_Internal *cli, const char *s) { return (cli->utf8 ? utf8_charlen(s) : 1); } /******* * Clp_NewParser, etc. **/ static int min_different_chars(const char *s, const char *t) /* Returns the minimum number of bytes required to distinguish s from t. If s is shorter than t, returns strlen(s). */ { const char *sfirst = s; while (*s && *t && *s == *t) s++, t++; if (!*s) return s - sfirst; else return s - sfirst + 1; } static int long_as_short(const Clp_Internal *cli, const Clp_Option *o, Clp_InternOption *io, int failure) { if ((cli->long1pos || cli->long1neg) && io->ilong) { const char *name = o->long_name + io->ilongoff; if (cli->utf8) { int c = decode_utf8(name, &name); if (!*name && c && c != U_REPLACEMENT) return c; } else if (name[0] && !name[1]) return (unsigned char) name[0]; } return failure; } static void compare_options(Clp_Parser *clp, const Clp_Option *o1, Clp_InternOption *io1, const Clp_Option *o2, Clp_InternOption *io2) { Clp_Internal *cli = clp->internal; int short1, shortx1; /* ignore meaningless combinations */ if ((!io1->ishort && !io1->ilong) || (!io2->ishort && !io2->ilong) || !((io1->ipos && io2->ipos) || (io1->ineg && io2->ineg)) || o1->option_id == o2->option_id) return; /* look for duplication of short options */ short1 = (io1->ishort ? o1->short_name : -1); shortx1 = long_as_short(cli, o1, io1, -2); if (short1 >= 0 || shortx1 >= 0) { int short2 = (io2->ishort ? o2->short_name : -3); int shortx2 = long_as_short(cli, o2, io2, -4); if (short1 == short2) Clp_OptionError(clp, "CLP internal error: more than 1 option has short name %<%c%>", short1); else if ((short1 == shortx2 || shortx1 == short2 || shortx1 == shortx2) && ((io1->ipos && io2->ipos && cli->long1pos) || (io1->ineg && io2->ineg && cli->long1neg))) Clp_OptionError(clp, "CLP internal error: 1-char long name conflicts with short name %<%c%>", (short1 == shortx2 ? shortx2 : shortx1)); } /* analyze longest minimum match */ if (io1->ilong) { const char *name1 = o1->long_name + io1->ilongoff; /* long name's first character matches short name */ if (io2->ishort && !io1->iprefmatch) { int name1char = (cli->utf8 ? decode_utf8(name1, 0) : (unsigned char) *name1); if (name1char == o2->short_name) { if (io1->ipos && io2->ipos) io1->lmmpos_short = 1; if (io1->ineg && io2->ineg) io1->lmmneg_short = 1; } } /* match long name to long name */ if (io2->ilong) { const char *name2 = o2->long_name + io2->ilongoff; if (strcmp(name1, name2) == 0) Clp_OptionError(clp, "CLP internal error: duplicate long name %<%s%>", name1); if (io1->ipos && io2->ipos && !strncmp(name1, name2, io1->lmmpos) && (!io1->iprefmatch || strncmp(name1, name2, strlen(name1)))) io1->lmmpos = min_different_chars(name1, name2); if (io1->ineg && io2->ineg && !strncmp(name1, name2, io1->lmmneg) && (!io1->iprefmatch || strncmp(name1, name2, strlen(name1)))) io1->lmmneg = min_different_chars(name1, name2); } } } static void calculate_lmm(Clp_Parser *clp, const Clp_Option *opt, Clp_InternOption *iopt, int nopt) { int i, j; for (i = 0; i < nopt; ++i) { iopt[i].lmmpos = iopt[i].lmmneg = 1; iopt[i].lmmpos_short = iopt[i].lmmneg_short = 0; for (j = 0; j < nopt; ++j) compare_options(clp, &opt[i], &iopt[i], &opt[j], &iopt[j]); } } /** @param argc number of arguments * @param argv argument array * @param nopt number of option definitions * @param opt option definition array * @return the parser * * The new Clp_Parser that will parse the arguments in @a argv according to * the option definitions in @a opt. * * The Clp_Parser is created with the following characteristics: * *
    *
  • The "-" character introduces short options (Clp_SetOptionChar(clp, * '-', Clp_Short)).
  • *
  • Clp_ProgramName is set from the first argument in @a argv, if any. The * first argument returned by Clp_Next() will be the second argument in @a * argv. Note that this behavior differs from Clp_SetArguments.
  • *
  • UTF-8 support is on iff the LANG environment variable contains * one of the substrings "UTF-8", "UTF8", or "utf8". Override this with * Clp_SetUTF8().
  • *
  • The Clp_ValString, Clp_ValStringNotOption, Clp_ValInt, Clp_ValUnsigned, * Clp_ValLong, Clp_ValUnsignedLong, Clp_ValBool, and Clp_ValDouble types are * installed.
  • *
  • Errors are reported to standard error.
  • *
* * You may also create a Clp_Parser with no arguments or options * (Clp_NewParser(0, 0, 0, 0)) and set the arguments and options * later. * * Returns NULL if there isn't enough memory to construct the parser. * * @note The CLP library will not modify the contents of @a argv or @a opt. * The calling program must not modify @a opt. It may modify @a argv in * limited cases. */ Clp_Parser * Clp_NewParser(int argc, const char * const *argv, int nopt, const Clp_Option *opt) { Clp_Parser *clp = (Clp_Parser *)malloc(sizeof(Clp_Parser)); Clp_Internal *cli = (Clp_Internal *)malloc(sizeof(Clp_Internal)); Clp_InternOption *iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nopt); if (cli) cli->valtype = (Clp_ValType *)malloc(sizeof(Clp_ValType) * Clp_InitialValType); if (!clp || !cli || !iopt || !cli->valtype) goto failed; clp->option = &clp_option_sentinel[-Clp_Done]; clp->negated = 0; clp->have_val = 0; clp->vstr = 0; clp->user_data = 0; clp->internal = cli; cli->opt = opt; cli->nopt = nopt; cli->iopt = iopt; cli->opt_generation = 0; cli->error_handler = 0; /* Assign program name (now so we can call Clp_OptionError) */ if (argc > 0) { const char *slash = strrchr(argv[0], '/'); cli->program_name = slash ? slash + 1 : argv[0]; } else cli->program_name = 0; /* Assign arguments, skipping program name */ Clp_SetArguments(clp, argc - 1, argv + 1); /* Initialize UTF-8 status and option classes */ { char *s = getenv("LANG"); cli->utf8 = (s && (strstr(s, "UTF-8") != 0 || strstr(s, "UTF8") != 0 || strstr(s, "utf8") != 0)); } cli->oclass[0].c = '-'; cli->oclass[0].type = Clp_Short; cli->noclass = 1; cli->long1pos = cli->long1neg = 0; /* Add default type parsers */ cli->nvaltype = 0; Clp_AddType(clp, Clp_ValString, 0, parse_string, 0); Clp_AddType(clp, Clp_ValStringNotOption, Clp_DisallowOptions, parse_string, 0); Clp_AddType(clp, Clp_ValInt, 0, parse_int, (void*) (uintptr_t) 0); Clp_AddType(clp, Clp_ValUnsigned, 0, parse_int, (void*) (uintptr_t) 1); Clp_AddType(clp, Clp_ValLong, 0, parse_int, (void*) (uintptr_t) 2); Clp_AddType(clp, Clp_ValUnsignedLong, 0, parse_int, (void*) (uintptr_t) 3); Clp_AddType(clp, Clp_ValBool, 0, parse_bool, 0); Clp_AddType(clp, Clp_ValDouble, 0, parse_double, 0); /* Set options */ Clp_SetOptions(clp, nopt, opt); return clp; failed: if (cli && cli->valtype) free(cli->valtype); if (cli) free(cli); if (clp) free(clp); if (iopt) free(iopt); return 0; } /** @param clp the parser * * All memory associated with @a clp is freed. */ void Clp_DeleteParser(Clp_Parser *clp) { int i; Clp_Internal *cli; if (!clp) return; cli = clp->internal; /* get rid of any string list types */ for (i = 0; i < cli->nvaltype; i++) if (cli->valtype[i].func == parse_string_list) { Clp_StringList *clsl = (Clp_StringList *)cli->valtype[i].user_data; free(clsl->items); free(clsl->iopt); free(clsl); } free(cli->valtype); free(cli->iopt); free(cli); free(clp); } /** @param clp the parser * @param errh error handler function * @return previous error handler function * * The error handler function is called when CLP encounters an error while * parsing the command line. It is called with the arguments "(*errh)(@a * clp, s)", where s is a description of the error terminated by * a newline. The s descriptions produced by CLP itself are prefixed * by the program name, if any. */ Clp_ErrorHandler Clp_SetErrorHandler(Clp_Parser *clp, void (*errh)(Clp_Parser *, const char *)) { Clp_Internal *cli = clp->internal; Clp_ErrorHandler old = cli->error_handler; cli->error_handler = errh; return old; } /** @param clp the parser * @param utf8 does the parser support UTF-8? * @return previous UTF-8 mode * * In UTF-8 mode, all input strings (arguments and long names for options) are * assumed to be encoded via UTF-8, and all character names * (Clp_SetOptionChar() and short names for options) may cover the whole * Unicode range. Out of UTF-8 mode, all input strings are treated as binary, * and all character names must be unsigned char values. * * Furthermore, error messages in UTF-8 mode may contain Unicode quote * characters. */ int Clp_SetUTF8(Clp_Parser *clp, int utf8) { Clp_Internal *cli = clp->internal; int old_utf8 = cli->utf8; cli->utf8 = utf8; calculate_lmm(clp, cli->opt, cli->iopt, cli->nopt); return old_utf8; } /** @param clp the parser * @param c character * @return option character treatment * * Returns an integer specifying how CLP treats arguments that begin * with character @a c. See Clp_SetOptionChar for possibilities. */ int Clp_OptionChar(Clp_Parser *clp, int c) { Clp_Internal *cli = clp->internal; int i, oclass = 0; if (cli->noclass > 0 && cli->oclass[0].c == 0) oclass = cli->oclass[0].type; for (i = 0; i < cli->noclass; ++i) if (cli->oclass[i].c == c) oclass = cli->oclass[i].type; return oclass; } /** @param clp the parser * @param c character * @param type option character treatment * @return previous option character treatment, or -1 on error * * @a type specifies how CLP treats arguments that begin with character @a c. * Possibilities are: * *
*
Clp_NotOption (or 0)
*
The argument cannot be an option.
*
Clp_Long
*
The argument is a long option.
*
Clp_Short
*
The argument is a set of short options.
*
Clp_Short|Clp_Long
*
The argument is either a long option or, if no matching long option is * found, a set of short options.
*
Clp_LongNegated
*
The argument is a negated long option. For example, after * Clp_SetOptionChar(@a clp, '^', Clp_LongNegated), the argument "^foo" is * equivalent to "--no-foo".
*
Clp_ShortNegated
*
The argument is a set of negated short options.
*
Clp_ShortNegated|Clp_LongNegated
*
The argument is either a negated long option or, if no matching long * option is found, a set of negated short options.
*
Clp_LongImplicit
*
The argument may be a long option, where the character @a c is actually * part of the long option name. For example, after Clp_SetOptionChar(@a clp, * 'f', Clp_LongImplicit), the argument "foo" may be equivalent to * "--foo".
*
* * In UTF-8 mode, @a c may be any Unicode character. Otherwise, @a c must be * an unsigned char value. The special character 0 assigns @a type to @em * every character. * * It is an error if @a c is out of range, @a type is illegal, or there are * too many character definitions stored in @a clp already. The function * returns -1 on error. * * A double hyphen "--" always introduces a long option. This behavior cannot * currently be changed with Clp_SetOptionChar(). */ int Clp_SetOptionChar(Clp_Parser *clp, int c, int type) { int i, long1pos, long1neg; int old = Clp_OptionChar(clp, c); Clp_Internal *cli = clp->internal; if (type != Clp_NotOption && type != Clp_Short && type != Clp_Long && type != Clp_ShortNegated && type != Clp_LongNegated && type != Clp_LongImplicit && type != (Clp_Short | Clp_Long) && type != (Clp_ShortNegated | Clp_LongNegated)) return -1; if (c < 0 || c >= (cli->utf8 ? 0x110000 : 256)) return -1; if (c == 0) cli->noclass = 0; for (i = 0; i < cli->noclass; ++i) if (cli->oclass[i].c == c) break; if (i == Clp_OclassSize) return -1; cli->oclass[i].c = c; cli->oclass[i].type = type; if (cli->noclass == i) cli->noclass = i + 1; long1pos = long1neg = 0; for (i = 0; i < cli->noclass; ++i) { if ((cli->oclass[i].type & Clp_Short) && (cli->oclass[i].type & Clp_Long)) long1pos = 1; if ((cli->oclass[i].type & Clp_ShortNegated) && (cli->oclass[i].type & Clp_LongNegated)) long1neg = 1; } if (long1pos != cli->long1pos || long1neg != cli->long1neg) { /* Must recheck option set */ cli->long1pos = long1pos; cli->long1neg = long1neg; calculate_lmm(clp, cli->opt, cli->iopt, cli->nopt); } return old; } /** @param clp the parser * @param nopt number of option definitions * @param opt option definition array * @return 0 on success, -1 on failure * * Installs the option definitions in @a opt. Future option parsing will * use @a opt to search for options. * * Also checks @a opt's option definitions for validity. "CLP internal * errors" are reported via Clp_OptionError() if: * *
    *
  • An option has a negative ID.
  • *
  • Two different short options have the same name.
  • *
  • Two different long options have the same name.
  • *
  • A short and a long option are ambiguous, in that some option character * might introduce either a short or a long option (e.g., Clp_SetOptionChar(@a * clp, '-', Clp_Long|Clp_Short)), and a short name equals a long name.
  • *
* * If necessary memory cannot be allocated, this function returns -1 without * modifying the parser. * * @note The CLP library will not modify the contents of @a argv or @a opt. * The calling program must not modify @a opt either until another call to * Clp_SetOptions() or the parser is destroyed. */ int Clp_SetOptions(Clp_Parser *clp, int nopt, const Clp_Option *opt) { Clp_Internal *cli = clp->internal; Clp_InternOption *iopt; int i; static unsigned opt_generation = 0; if (nopt > cli->nopt) { iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nopt); if (!iopt) return -1; free(cli->iopt); cli->iopt = iopt; } cli->opt = opt; cli->nopt = nopt; cli->opt_generation = ++opt_generation; iopt = cli->iopt; cli->current_option = -1; /* Massage the options to make them usable */ for (i = 0; i < nopt; i++) { /* Ignore negative option_ids, which are internal to CLP */ if (opt[i].option_id < 0) { Clp_OptionError(clp, "CLP internal error: option %d has negative option_id", i); iopt[i].ilong = iopt[i].ishort = iopt[i].ipos = iopt[i].ineg = 0; continue; } /* Set flags based on input flags */ iopt[i].ilong = (opt[i].long_name != 0 && opt[i].long_name[0] != 0); iopt[i].ishort = (opt[i].short_name > 0 && opt[i].short_name < (cli->utf8 ? 0x110000 : 256)); iopt[i].ipos = 1; iopt[i].ineg = (opt[i].flags & Clp_Negate) != 0; iopt[i].imandatory = (opt[i].flags & Clp_Mandatory) != 0; iopt[i].ioptional = (opt[i].flags & Clp_Optional) != 0; iopt[i].iprefmatch = (opt[i].flags & Clp_PreferredMatch) != 0; iopt[i].ilongoff = 0; /* Enforce invariants */ if (opt[i].val_type <= 0) iopt[i].imandatory = iopt[i].ioptional = 0; if (opt[i].val_type > 0 && !iopt[i].ioptional) iopt[i].imandatory = 1; /* Options that start with 'no-' should be changed to OnlyNegated */ if (iopt[i].ilong && strncmp(opt[i].long_name, "no-", 3) == 0) { iopt[i].ipos = 0; iopt[i].ineg = 1; iopt[i].ilongoff = 3; if (strncmp(opt[i].long_name + 3, "no-", 3) == 0) Clp_OptionError(clp, "CLP internal error: option %d begins with \"no-no-\"", i); } else if (opt[i].flags & Clp_OnlyNegated) { iopt[i].ipos = 0; iopt[i].ineg = 1; } } /* Check option set */ calculate_lmm(clp, opt, iopt, nopt); return 0; } /** @param clp the parser * @param argc number of arguments * @param argv argument array * * Installs the arguments in @a argv for parsing. Future option parsing will * analyze @a argv. * * Unlike Clp_NewParser(), this function does not treat @a argv[0] specially. * The first subsequent call to Clp_Next() will analyze @a argv[0]. * * This function also sets option processing to on, as by * Clp_SetOptionProcessing(@a clp, 1). * * @note The CLP library will not modify the contents of @a argv. The calling * program should not generally modify the element of @a argv that CLP is * currently analyzing. */ void Clp_SetArguments(Clp_Parser *clp, int argc, const char * const *argv) { Clp_Internal *cli = clp->internal; cli->argc = argc + 1; cli->argv = argv - 1; cli->is_short = 0; cli->whole_negated = 0; cli->option_processing = 1; cli->current_option = -1; } /** @param clp the parser * @param on whether to search for options * @return previous option processing setting * * When option processing is off, every call to Clp_Next() returns * Clp_NotOption. By default the option "--" turns off option * processing and is otherwise ignored. */ int Clp_SetOptionProcessing(Clp_Parser *clp, int on) { Clp_Internal *cli = clp->internal; int old = cli->option_processing; cli->option_processing = on; return old; } /******* * functions for Clp_Option lists **/ /* the ever-glorious argcmp */ static int argcmp(const char *ref, const char *arg, int min_match, int fewer_dashes) /* Returns 0 if ref and arg don't match. Returns -1 if ref and arg match, but fewer than min_match characters. Returns len if ref and arg match min_match or more characters; len is the number of characters that matched in arg. Allows arg to contain fewer dashes than ref iff fewer_dashes != 0. Examples: argcmp("x", "y", 1, 0) --> 0 / just plain wrong argcmp("a", "ax", 1, 0) --> 0 / ...even though min_match == 1 and the 1st chars match argcmp("box", "bo", 3, 0) --> -1 / ambiguous argcmp("cat", "c=3", 1, 0) --> 1 / handles = arguments */ { const char *refstart = ref; const char *argstart = arg; assert(min_match > 0); compare: while (*ref && *arg && *arg != '=' && *ref == *arg) ref++, arg++; /* Allow arg to contain fewer dashes than ref */ if (fewer_dashes && *ref == '-' && ref[1] && ref[1] == *arg) { ref++; goto compare; } if (*arg && *arg != '=') return 0; else if (ref - refstart < min_match) return -1; else return arg - argstart; } static int find_prefix_opt(Clp_Parser *clp, const char *arg, int nopt, const Clp_Option *opt, const Clp_InternOption *iopt, int *ambiguous, int *ambiguous_values) /* Looks for an unambiguous match of 'arg' against one of the long options in 'opt'. Returns positive if it finds one; otherwise, returns -1 and possibly changes 'ambiguous' and 'ambiguous_values' to keep track of at most MAX_AMBIGUOUS_VALUES possibilities. */ { int i, fewer_dashes = 0, first_ambiguous = *ambiguous; int negated = clp && clp->negated; int first_charlen = (clp ? clp_utf8_charlen(clp->internal, arg) : 1); retry: for (i = 0; i < nopt; i++) { int len, lmm; if (!iopt[i].ilong || (negated ? !iopt[i].ineg : !iopt[i].ipos)) continue; lmm = (negated ? iopt[i].lmmneg : iopt[i].lmmpos); if (clp && clp->internal->could_be_short && (negated ? iopt[i].lmmneg_short : iopt[i].lmmpos_short)) lmm = (first_charlen >= lmm ? first_charlen + 1 : lmm); len = argcmp(opt[i].long_name + iopt[i].ilongoff, arg, lmm, fewer_dashes); if (len > 0) return i; else if (len < 0) { if (*ambiguous < MAX_AMBIGUOUS_VALUES) ambiguous_values[*ambiguous] = i; (*ambiguous)++; } } /* If there were no partial matches, try again with fewer_dashes true */ if (*ambiguous == first_ambiguous && !fewer_dashes) { fewer_dashes = 1; goto retry; } return -1; } /***** * Argument parsing **/ static int val_type_binsearch(Clp_Internal *cli, int val_type) { unsigned l = 0, r = cli->nvaltype; while (l < r) { unsigned m = l + (r - l) / 2; if (cli->valtype[m].val_type == val_type) return m; else if (cli->valtype[m].val_type < val_type) l = m + 1; else r = m; } return l; } /** @param clp the parser * @param val_type value type ID * @param flags value type flags * @param parser parser function * @param user_data user data for @a parser function * @return 0 on success, -1 on failure * * Defines argument type @a val_type in parser @a clp. The parsing function * @a parser will be passed argument values for type @a val_type. It should * parse the argument into values (usually in @a clp->val, but sometimes * elsewhere), report errors if necessary, and return whether the parse was * successful. * * Any prior argument parser match @a val_type is removed. @a val_type must * be greater than zero. * * @a flags specifies additional parsing flags. At the moment the only * relevant flag is Clp_DisallowOptions, which means that separated values * must not look like options. For example, assume argument * --a/-a has mandatory value type Clp_ValStringNotOption * (which has Clp_DisallowOptions). Then: * *
    *
  • --a=--b will parse with value --b.
  • *
  • -a--b will parse with value --b.
  • *
  • --a --b will not parse, since the mandatory value looks like * an option.
  • *
  • -a --b will not parse, since the mandatory value looks like * an option.
  • *
*/ int Clp_AddType(Clp_Parser *clp, int val_type, int flags, Clp_ValParseFunc parser, void *user_data) { Clp_Internal *cli = clp->internal; int vtpos; if (val_type <= 0 || !parser) return -1; vtpos = val_type_binsearch(cli, val_type); if (vtpos == cli->nvaltype || cli->valtype[vtpos].val_type != val_type) { if (cli->nvaltype != 0 && (cli->nvaltype % Clp_InitialValType) == 0) { Clp_ValType *new_valtype = (Clp_ValType *) realloc(cli->valtype, sizeof(Clp_ValType) * (cli->nvaltype + Clp_InitialValType)); if (!new_valtype) return -1; cli->valtype = new_valtype; } memmove(&cli->valtype[vtpos + 1], &cli->valtype[vtpos], sizeof(Clp_ValType) * (cli->nvaltype - vtpos)); cli->nvaltype++; cli->valtype[vtpos].func = 0; } if (cli->valtype[vtpos].func == parse_string_list) { Clp_StringList *clsl = (Clp_StringList *) cli->valtype[vtpos].user_data; free(clsl->items); free(clsl->iopt); free(clsl); } cli->valtype[vtpos].val_type = val_type; cli->valtype[vtpos].func = parser; cli->valtype[vtpos].flags = flags; cli->valtype[vtpos].user_data = user_data; return 0; } /******* * Default argument parsers **/ static int parse_string(Clp_Parser *clp, const char *arg, int complain, void *user_data) { (void)complain, (void)user_data; clp->val.s = arg; return 1; } static int parse_int(Clp_Parser *clp, const char *arg, int complain, void* user_data) { const char *val; uintptr_t type = (uintptr_t) user_data; if (*arg == 0 || isspace((unsigned char) *arg) || ((type & 1) && *arg == '-')) val = arg; else if (type & 1) { /* unsigned */ #if HAVE_STRTOUL clp->val.ul = strtoul(arg, (char **) &val, 0); #else /* don't bother really trying to do it right */ if (arg[0] == '-') val = arg; else clp->val.l = strtol(arg, (char **) &val, 0); #endif } else clp->val.l = strtol(arg, (char **) &val, 0); if (type <= 1) clp->val.u = (unsigned) clp->val.ul; if (*arg != 0 && *val == 0) return 1; else if (complain) { const char *message = type & 1 ? "%<%O%> expects a nonnegative integer, not %<%s%>" : "%<%O%> expects an integer, not %<%s%>"; return Clp_OptionError(clp, message, arg); } else return 0; } static int parse_double(Clp_Parser *clp, const char *arg, int complain, void *user_data) { const char *val; (void)user_data; if (*arg == 0 || isspace((unsigned char) *arg)) val = arg; else clp->val.d = strtod(arg, (char **) &val); if (*arg != 0 && *val == 0) return 1; else if (complain) return Clp_OptionError(clp, "%<%O%> expects a real number, not %<%s%>", arg); else return 0; } static int parse_bool(Clp_Parser *clp, const char *arg, int complain, void *user_data) { int i; char lcarg[6]; (void)user_data; if (strlen(arg) > 5 || strchr(arg, '=') != 0) goto error; for (i = 0; arg[i] != 0; i++) lcarg[i] = tolower((unsigned char) arg[i]); lcarg[i] = 0; if (argcmp("yes", lcarg, 1, 0) > 0 || argcmp("true", lcarg, 1, 0) > 0 || argcmp("1", lcarg, 1, 0) > 0) { clp->val.i = 1; return 1; } else if (argcmp("no", lcarg, 1, 0) > 0 || argcmp("false", lcarg, 1, 0) > 0 || argcmp("1", lcarg, 1, 0) > 0) { clp->val.i = 0; return 1; } error: if (complain) Clp_OptionError(clp, "%<%O%> expects a true-or-false value, not %<%s%>", arg); return 0; } /***** * Clp_AddStringListType **/ static int parse_string_list(Clp_Parser *clp, const char *arg, int complain, void *user_data) { Clp_StringList *sl = (Clp_StringList *)user_data; int idx, ambiguous = 0; int ambiguous_values[MAX_AMBIGUOUS_VALUES + 1]; /* actually look for a string value */ idx = find_prefix_opt (0, arg, sl->nitems, sl->items, sl->iopt, &ambiguous, ambiguous_values); if (idx >= 0) { clp->val.i = sl->items[idx].option_id; if (sl->val_long) clp->val.l = clp->val.i; return 1; } if (sl->allow_int) { if (parse_int(clp, arg, 0, (void*) (uintptr_t) (sl->val_long ? 2 : 0))) return 1; } if (complain) { const char *complaint = (ambiguous ? "ambiguous" : "invalid"); if (!ambiguous) { ambiguous = sl->nitems_invalid_report; for (idx = 0; idx < ambiguous; idx++) ambiguous_values[idx] = idx; } return ambiguity_error (clp, ambiguous, ambiguous_values, sl->items, sl->iopt, "", "option %<%O%> value %<%s%> is %s", arg, complaint); } else return 0; } static int finish_string_list(Clp_Parser *clp, int val_type, int flags, Clp_Option *items, int nitems, int itemscap) { int i; Clp_StringList *clsl = (Clp_StringList *)malloc(sizeof(Clp_StringList)); Clp_InternOption *iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nitems); if (!clsl || !iopt) goto error; clsl->items = items; clsl->iopt = iopt; clsl->nitems = nitems; clsl->allow_int = (flags & Clp_AllowNumbers) != 0; clsl->val_long = (flags & Clp_StringListLong) != 0; if (nitems < MAX_AMBIGUOUS_VALUES && nitems < itemscap && clsl->allow_int) { items[nitems].long_name = "any integer"; clsl->nitems_invalid_report = nitems + 1; } else if (nitems > MAX_AMBIGUOUS_VALUES + 1) clsl->nitems_invalid_report = MAX_AMBIGUOUS_VALUES + 1; else clsl->nitems_invalid_report = nitems; for (i = 0; i < nitems; i++) { iopt[i].ilong = iopt[i].ipos = 1; iopt[i].ishort = iopt[i].ineg = iopt[i].ilongoff = iopt[i].iprefmatch = 0; } calculate_lmm(clp, items, iopt, nitems); if (Clp_AddType(clp, val_type, 0, parse_string_list, clsl) >= 0) return 0; error: if (clsl) free(clsl); if (iopt) free(iopt); return -1; } /** @param clp the parser * @param val_type value type ID * @param flags string list flags * @return 0 on success, -1 on failure * * Defines argument type @a val_type in parser @a clp. The parsing function * sets @a clp->val.i to an integer. The value string is matched against * strings provided in the ellipsis arguments. For example, the * Clp_AddStringListType() call below has the same effect as the * Clp_AddStringListTypeVec() call: * * For example: * @code * Clp_AddStringListType(clp, 100, Clp_AllowNumbers, "cat", 1, * "cattle", 2, "dog", 3, (const char *) NULL); * * const char * const strs[] = { "cat", "cattle", "dog" }; * const int vals[] = { 1, 2, 3 }; * Clp_AddStringListTypeVec(clp, 100, Clp_AllowNumbers, 3, strs, vals); * @endcode * * @note The CLP library will not modify any of the passed-in strings. The * calling program must not modify or free them either until the parser is * destroyed. */ int Clp_AddStringListType(Clp_Parser *clp, int val_type, int flags, ...) { int nitems = 0; int itemscap = 5; Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap); va_list val; va_start(val, flags); if (!items) goto error; /* slurp up the arguments */ while (1) { int value; char *name = va_arg(val, char *); if (!name) break; if (flags & Clp_StringListLong) { long lvalue = va_arg(val, long); value = (int) lvalue; assert(value == lvalue); } else value = va_arg(val, int); if (nitems >= itemscap) { Clp_Option *new_items; itemscap *= 2; new_items = (Clp_Option *)realloc(items, sizeof(Clp_Option) * itemscap); if (!new_items) goto error; items = new_items; } items[nitems].long_name = name; items[nitems].option_id = value; items[nitems].flags = 0; nitems++; } va_end(val); if (finish_string_list(clp, val_type, flags, items, nitems, itemscap) >= 0) return 0; error: va_end(val); if (items) free(items); return -1; } /** @param clp the parser * @param val_type value type ID * @param flags string list flags * @param nstrs number of strings in list * @param strs array of strings * @param vals array of values * @return 0 on success, -1 on failure * * Defines argument type @a val_type in parser @a clp. The parsing function * sets @a clp->val.i to an integer. The value string is matched against the * @a strs. If there's a unique match, the corresponding entry from @a vals * is returned. Unique prefix matches also work. Finally, if @a flags * contains the Clp_AllowNumbers flag, then integers are also accepted. * * For example: * @code * const char * const strs[] = { "cat", "cattle", "dog" }; * const int vals[] = { 1, 2, 3 }; * Clp_AddStringListTypeVec(clp, 100, Clp_AllowNumbers, 3, strs, vals); * @endcode * * Say that option --animal takes value type 100. Then: * *
    *
  • --animal=cat will succeed and set @a clp->val.i = 1.
  • *
  • --animal=cattle will succeed and set @a clp->val.i = 2.
  • *
  • --animal=dog will succeed and set @a clp->val.i = 3.
  • *
  • --animal=d will succeed and set @a clp->val.i = 3.
  • *
  • --animal=c will fail, since c is ambiguous.
  • *
  • --animal=4 will succeed and set @a clp->val.i = 4.
  • *
* * @note The CLP library will not modify the contents of @a strs or @a vals. * The calling program can modify the @a strs array, but the actual strings * (for instance, @a strs[0] and @a strs[1]) must not be modified or freed * until the parser is destroyed. */ int Clp_AddStringListTypeVec(Clp_Parser *clp, int val_type, int flags, int nstrs, const char * const *strs, const int *vals) /* An alternate way to make a string list type. See Clp_AddStringListType for the basics; this coalesces the strings and values into two arrays, rather than spreading them out into a variable argument list. */ { int i; int itemscap = (nstrs < 5 ? 5 : nstrs); Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap); if (!items) return -1; /* copy over items */ for (i = 0; i < nstrs; i++) { items[i].long_name = strs[i]; items[i].option_id = vals[i]; items[i].flags = 0; } if (finish_string_list(clp, val_type, flags, items, nstrs, itemscap) >= 0) return 0; else { free(items); return -1; } } /******* * Returning information **/ const char * Clp_ProgramName(Clp_Parser *clp) { return clp->internal->program_name; } /** @param clp the parser * @param name new program name * @return previous program name * * The calling program should not modify or free @a name until @a clp itself * is destroyed. */ const char * Clp_SetProgramName(Clp_Parser *clp, const char *name) { const char *old = clp->internal->program_name; clp->internal->program_name = name; return old; } /****** * Clp_ParserStates **/ /** @return the parser state * * A Clp_ParserState object can store a parsing state of a Clp_Parser object. * This state specifies exactly how far the Clp_Parser has gotten in parsing * an argument list. The Clp_SaveParser() and Clp_RestoreParser() functions * can be used to save this state and then restore it later, allowing a * Clp_Parser to switch among argument lists. * * The initial state is empty, in that after Clp_RestoreParser(clp, state), * Clp_Next(clp) would return Clp_Done. * * Parser states can be saved and restored among different parser objects. * * @sa Clp_DeleteParserState, Clp_SaveParser, Clp_RestoreParser */ Clp_ParserState * Clp_NewParserState(void) { Clp_ParserState *state = (Clp_ParserState *)malloc(sizeof(Clp_ParserState)); if (state) { state->argv = 0; state->argc = 0; state->option_chars[0] = 0; state->xtext = 0; state->option_processing = 0; state->opt_generation = 0; state->current_option = -1; state->is_short = 0; state->whole_negated = 0; state->current_short = 0; state->negated_by_no = 0; } return state; } /** @param state parser state * * The memory associated with @a state is freed. */ void Clp_DeleteParserState(Clp_ParserState *state) { free(state); } /** @param clp the parser * @param state parser state * @sa Clp_NewParserState, Clp_RestoreParser */ void Clp_SaveParser(const Clp_Parser *clp, Clp_ParserState *state) { Clp_Internal *cli = clp->internal; state->argv = cli->argv; state->argc = cli->argc; memcpy(state->option_chars, cli->option_chars, Clp_OptionCharsSize); state->xtext = cli->xtext; state->option_processing = cli->option_processing; state->opt_generation = cli->opt_generation; state->current_option = cli->current_option; state->is_short = cli->is_short; state->whole_negated = cli->whole_negated; state->current_short = cli->current_short; state->negated_by_no = cli->negated_by_no; } /** @param clp the parser * @param state parser state * * The parser state in @a state is restored into @a clp. The next call to * Clp_Next() will return the same result as it would have at the time @a * state was saved (probably by Clp_SaveParser(@a clp, @a state)). * * A parser state contains information about arguments (argc and argv; see * Clp_SetArguments()) and option processing (Clp_SetOptionProcessing()), but * not about options (Clp_SetOptions()). Changes to options and value types * are preserved across Clp_RestoreParser(). * * @sa Clp_NewParserState, Clp_SaveParser */ void Clp_RestoreParser(Clp_Parser *clp, const Clp_ParserState *state) { Clp_Internal *cli = clp->internal; cli->argv = state->argv; cli->argc = state->argc; memcpy(cli->option_chars, state->option_chars, Clp_OptionCharsSize); cli->xtext = state->xtext; cli->option_processing = state->option_processing; cli->is_short = state->is_short; cli->whole_negated = state->whole_negated; cli->current_short = state->current_short; cli->negated_by_no = state->negated_by_no; if (cli->opt_generation == state->opt_generation) cli->current_option = state->current_option; else cli->current_option = -1; } /******* * Clp_Next and its helpers **/ static void set_option_text(Clp_Internal *cli, const char *text, int n_option_chars) { assert(n_option_chars < Clp_OptionCharsSize); memcpy(cli->option_chars, text, n_option_chars); cli->option_chars[n_option_chars] = 0; cli->xtext = text + n_option_chars; } static int get_oclass(Clp_Parser *clp, const char *text, int *ocharskip) { int c; if (clp->internal->utf8) { const char *s; c = decode_utf8(text, &s); *ocharskip = s - text; } else { c = (unsigned char) text[0]; *ocharskip = 1; } return Clp_OptionChar(clp, c); } static int next_argument(Clp_Parser *clp, int want_argument) /* Moves clp to the next argument. Returns 1 if it finds another option. Returns 0 if there aren't any more arguments. Returns 0, sets clp->have_val = 1, and sets clp->vstr to the argument if the next argument isn't an option. If want_argument > 0, it'll look for an argument. want_argument == 1: Accept arguments that start with Clp_NotOption or Clp_LongImplicit. want_argument == 2: Accept ALL arguments. Where is the option stored when this returns? Well, cli->argv[0] holds the whole of the next command line argument. cli->option_chars holds a string: what characters began the option? It is generally "-" or "--". cli->text holds the text of the option: for short options, cli->text[0] is the relevant character; for long options, cli->text holds the rest of the option. */ { Clp_Internal *cli = clp->internal; const char *text; int oclass, ocharskip; /* clear relevant flags */ clp->have_val = 0; clp->vstr = 0; cli->could_be_short = 0; /* if we're in a string of short options, move up one char in the string */ if (cli->is_short) { cli->xtext += clp_utf8_charlen(cli, cli->xtext); if (cli->xtext[0] == 0) cli->is_short = 0; else if (want_argument > 0) { /* handle -O[=]argument case */ clp->have_val = 1; if (cli->xtext[0] == '=') clp->vstr = cli->xtext + 1; else clp->vstr = cli->xtext; cli->is_short = 0; return 0; } } /* if in short options, we're all set */ if (cli->is_short) return 1; /** if not in short options, move to the next argument **/ cli->whole_negated = 0; cli->xtext = 0; if (cli->argc <= 1) return 0; cli->argc--; cli->argv++; text = cli->argv[0]; if (want_argument > 1) goto not_option; if (text[0] == '-' && text[1] == '-') { oclass = Clp_DoubledLong; ocharskip = 2; } else oclass = get_oclass(clp, text, &ocharskip); /* If this character could introduce either a short or a long option, try a long option first, but remember that short's a possibility for later. */ if ((oclass & (Clp_Short | Clp_ShortNegated)) && (oclass & (Clp_Long | Clp_LongNegated))) { oclass &= ~(Clp_Short | Clp_ShortNegated); if (text[ocharskip]) cli->could_be_short = 1; } switch (oclass) { case Clp_Short: cli->is_short = 1; goto check_singleton; case Clp_ShortNegated: cli->is_short = 1; cli->whole_negated = 1; goto check_singleton; case Clp_Long: goto check_singleton; case Clp_LongNegated: cli->whole_negated = 1; goto check_singleton; check_singleton: /* For options introduced with one character, option-char, '[option-char]' alone is NOT an option. */ if (!text[ocharskip]) goto not_option; set_option_text(cli, text, ocharskip); break; case Clp_LongImplicit: /* LongImplict: option_chars == "" (since all chars are part of the option); restore head -> text of option */ if (want_argument > 0) goto not_option; set_option_text(cli, text, 0); break; case Clp_DoubledLong: set_option_text(cli, text, ocharskip); break; not_option: case Clp_NotOption: cli->is_short = 0; clp->have_val = 1; clp->vstr = text; return 0; default: assert(0 /* CLP misconfiguration: bad option type */); } return 1; } static void switch_to_short_argument(Clp_Parser *clp) { Clp_Internal *cli = clp->internal; const char *text = cli->argv[0]; int ocharskip, oclass = get_oclass(clp, text, &ocharskip); assert(cli->could_be_short); cli->is_short = 1; cli->whole_negated = (oclass & Clp_ShortNegated ? 1 : 0); set_option_text(cli, cli->argv[0], ocharskip); } static int find_long(Clp_Parser *clp, const char *arg) /* If arg corresponds to one of clp's options, finds that option & returns it. If any argument is given after an = sign in arg, sets clp->have_val = 1 and clp->vstr to that argument. Sets cli->ambiguous to 1 iff there was no match because the argument was ambiguous. */ { Clp_Internal *cli = clp->internal; int optno, len, lmm; const Clp_Option *opt = cli->opt; const Clp_InternOption *iopt; int first_negative_ambiguous; /* Look for a normal option. */ optno = find_prefix_opt (clp, arg, cli->nopt, opt, cli->iopt, &cli->ambiguous, cli->ambiguous_values); if (optno >= 0) goto worked; /* If we can't find it, look for a negated option. */ /* I know this is silly, but it makes me happy to accept --no-no-option as a double negative synonym for --option. :) */ first_negative_ambiguous = cli->ambiguous; while (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-') { arg += 3; clp->negated = !clp->negated; optno = find_prefix_opt (clp, arg, cli->nopt, opt, cli->iopt, &cli->ambiguous, cli->ambiguous_values); if (optno >= 0) goto worked; } /* No valid option was found; return 0. Mark the ambiguous values found through '--no' by making them negative. */ { int i, max = cli->ambiguous; if (max > MAX_AMBIGUOUS_VALUES) max = MAX_AMBIGUOUS_VALUES; for (i = first_negative_ambiguous; i < max; i++) cli->ambiguous_values[i] = -cli->ambiguous_values[i] - 1; } return -1; worked: iopt = &cli->iopt[optno]; lmm = (clp->negated ? iopt->lmmneg : iopt->lmmpos); if (cli->could_be_short && (clp->negated ? iopt->lmmneg_short : iopt->lmmpos_short)) { int first_charlen = clp_utf8_charlen(cli, arg); lmm = (first_charlen >= lmm ? first_charlen + 1 : lmm); } len = argcmp(opt[optno].long_name + iopt->ilongoff, arg, lmm, 1); assert(len > 0); if (arg[len] == '=') { clp->have_val = 1; clp->vstr = arg + len + 1; } return optno; } static int find_short(Clp_Parser *clp, const char *text) /* If short_name corresponds to one of clp's options, returns it. */ { Clp_Internal *cli = clp->internal; const Clp_Option *opt = cli->opt; const Clp_InternOption *iopt = cli->iopt; int i, c; if (clp->internal->utf8) c = decode_utf8(text, 0); else c = (unsigned char) *text; for (i = 0; i < cli->nopt; i++) if (iopt[i].ishort && opt[i].short_name == c && (!clp->negated || iopt[i].ineg)) { clp->negated = clp->negated || !iopt[i].ipos; return i; } return -1; } /** @param clp the parser * @return option ID of next option * * Parse the next argument from the argument list, store information about * that argument in the fields of @a clp, and return the option's ID. * * If an argument was successfully parsed, that option's ID is returned. * Other possible return values are: * *
*
Clp_Done
*
There are no more arguments.
*
Clp_NotOption
*
The next argument was not an option. The argument's text is @a * clp->vstr (and @a clp->val.s).
*
Clp_BadOption
*
The next argument was a bad option: either an option that wasn't * understood, or an option lacking a required value, or an option whose value * couldn't be parsed. The option has been skipped.
*
Clp_Error
*
There was an internal error. This should never occur unless a user * messes with, for example, a Clp_Option array.
*
* * The fields of @a clp are set as follows. * *
*
negated
*
1 if the option was negated, 0 if it wasn't.
*
have_val
*
1 if the option had a value, 0 if it didn't. Note that negated options * are not allowed to have values.
*
vstr
*
The value string, if any. NULL if there was no value.
*
val
*
An option's value type will parse the value string into this * union.
*
* * The parsed argument is shifted off the argument list, so that sequential * calls to Clp_Next() step through the arugment list. */ int Clp_Next(Clp_Parser *clp) { Clp_Internal *cli = clp->internal; int optno; const Clp_Option *opt; Clp_ParserState clpsave; int vtpos, complain; /* Set up clp */ cli->current_option = -1; cli->ambiguous = 0; /* Get the next argument or option */ if (!next_argument(clp, cli->option_processing ? 0 : 2)) { clp->val.s = clp->vstr; optno = clp->have_val ? Clp_NotOption : Clp_Done; clp->option = &clp_option_sentinel[-optno]; return optno; } clp->negated = cli->whole_negated; if (cli->is_short) optno = find_short(clp, cli->xtext); else optno = find_long(clp, cli->xtext); /* If there's ambiguity between long & short options, and we couldn't find a long option, look for a short option */ if (optno < 0 && cli->could_be_short) { switch_to_short_argument(clp); optno = find_short(clp, cli->xtext); } /* If we didn't find an option... */ if (optno < 0 || (clp->negated && !cli->iopt[optno].ineg)) { /* default processing for the "--" option: turn off option processing and return the next argument */ if (strcmp(cli->argv[0], "--") == 0) { Clp_SetOptionProcessing(clp, 0); return Clp_Next(clp); } /* otherwise, report some error or other */ if (cli->ambiguous) ambiguity_error(clp, cli->ambiguous, cli->ambiguous_values, cli->opt, cli->iopt, cli->option_chars, "option %<%s%s%> is ambiguous", cli->option_chars, cli->xtext); else if (cli->is_short && !cli->could_be_short) Clp_OptionError(clp, "unrecognized option %<%s%C%>", cli->option_chars, cli->xtext); else Clp_OptionError(clp, "unrecognized option %<%s%s%>", cli->option_chars, cli->xtext); clp->option = &clp_option_sentinel[-Clp_BadOption]; return Clp_BadOption; } /* Set the current option */ cli->current_option = optno; cli->current_short = cli->is_short; cli->negated_by_no = clp->negated && !cli->whole_negated; /* The no-argument (or should-have-no-argument) case */ if (clp->negated || (!cli->iopt[optno].imandatory && !cli->iopt[optno].ioptional)) { if (clp->have_val) { Clp_OptionError(clp, "%<%O%> can%,t take an argument"); clp->option = &clp_option_sentinel[-Clp_BadOption]; return Clp_BadOption; } else { clp->option = &cli->opt[optno]; return cli->opt[optno].option_id; } } /* Get an argument if we need one, or if it's optional */ /* Sanity-check the argument type. */ opt = &cli->opt[optno]; if (opt->val_type <= 0) { clp->option = &clp_option_sentinel[-Clp_Error]; return Clp_Error; } vtpos = val_type_binsearch(cli, opt->val_type); if (vtpos == cli->nvaltype || cli->valtype[vtpos].val_type != opt->val_type) { clp->option = &clp_option_sentinel[-Clp_Error]; return Clp_Error; } /* complain == 1 only if the argument was explicitly given, or it is mandatory. */ complain = (clp->have_val != 0) || cli->iopt[optno].imandatory; Clp_SaveParser(clp, &clpsave); if (cli->iopt[optno].imandatory && !clp->have_val) { /* Mandatory argument case */ /* Allow arguments to options to start with a dash, but only if the argument type allows it by not setting Clp_DisallowOptions */ int disallow = (cli->valtype[vtpos].flags & Clp_DisallowOptions) != 0; next_argument(clp, disallow ? 1 : 2); if (!clp->have_val) { int got_option = cli->xtext != 0; Clp_RestoreParser(clp, &clpsave); if (got_option) Clp_OptionError(clp, "%<%O%> requires a non-option argument"); else Clp_OptionError(clp, "%<%O%> requires an argument"); clp->option = &clp_option_sentinel[-Clp_BadOption]; return Clp_BadOption; } } else if (cli->is_short && !clp->have_val && cli->xtext[clp_utf8_charlen(cli, cli->xtext)]) /* The -[option]argument case: Assume that the rest of the current string is the argument. */ next_argument(clp, 1); /* Parse the argument */ clp->option = opt; if (clp->have_val) { Clp_ValType *atr = &cli->valtype[vtpos]; if (atr->func(clp, clp->vstr, complain, atr->user_data) <= 0) { /* parser failed */ clp->have_val = 0; if (cli->iopt[optno].imandatory) { clp->option = &clp_option_sentinel[-Clp_BadOption]; return Clp_BadOption; } else { Clp_RestoreParser(clp, &clpsave); clp->option = opt; } } } return opt->option_id; } /** @param clp the parser * @param allow_options whether options will be allowed * * Remove and return the next argument from @a clp's argument array. If there * are no arguments left, or if the next argument is an option and @a * allow_options != 0, then returns null. */ const char * Clp_Shift(Clp_Parser *clp, int allow_options) /* Returns the next argument from the argument list without parsing it. If there are no more arguments, returns 0. */ { Clp_ParserState clpsave; Clp_SaveParser(clp, &clpsave); next_argument(clp, allow_options ? 2 : 1); if (!clp->have_val) Clp_RestoreParser(clp, &clpsave); return clp->vstr; } /******* * Clp_OptionError **/ typedef struct Clp_BuildString { char *text; char *pos; int capacity; int bad; } Clp_BuildString; static Clp_BuildString * new_build_string(void) { Clp_BuildString *bs = (Clp_BuildString *)malloc(sizeof(Clp_BuildString)); if (!bs) goto bad; bs->text = (char *)malloc(256); if (!bs->text) goto bad; bs->pos = bs->text; bs->capacity = 256; bs->bad = 0; return bs; bad: if (bs) free(bs); return 0; } static void free_build_string(Clp_BuildString *bs) { if (bs) free(bs->text); free(bs); } static int grow_build_string(Clp_BuildString *bs, int want) { char *new_text; int ipos = bs->pos - bs->text; int new_capacity = bs->capacity; while (want >= new_capacity) new_capacity *= 2; new_text = (char *)realloc(bs->text, new_capacity); if (!new_text) { bs->bad = 1; return 0; } else { bs->text = new_text; bs->pos = bs->text + ipos; bs->capacity = new_capacity; return 1; } } #define ENSURE_BUILD_STRING(bs, space) \ ((((bs)->pos - (bs)->text) + (space) >= (bs)->capacity) \ || grow_build_string((bs), ((bs)->pos - (bs)->text) + (space))) static void append_build_string(Clp_BuildString *bs, const char *s, int l) { if (l < 0) l = strlen(s); if (ENSURE_BUILD_STRING(bs, l)) { memcpy(bs->pos, s, l); bs->pos += l; } } static Clp_BuildString * Clp_VaOptionError(Clp_Parser *clp, Clp_BuildString *bs, const char *fmt, va_list val) { Clp_Internal *cli = clp->internal; const char *percent; int c; if (!bs) bs = new_build_string(); if (!bs) return 0; if (cli->program_name && cli->program_name[0]) { append_build_string(bs, cli->program_name, -1); append_build_string(bs, ": ", 2); } for (percent = strchr(fmt, '%'); percent; percent = strchr(fmt, '%')) { append_build_string(bs, fmt, percent - fmt); switch (*++percent) { case 's': { const char *s = va_arg(val, const char *); if (s) append_build_string(bs, s, -1); else append_build_string(bs, "(null)", 6); break; } case 'C': { const char *s = va_arg(val, const char *); if (cli->utf8) c = decode_utf8(s, 0); else c = (unsigned char) *s; goto char_c; } case 'c': c = va_arg(val, int); goto char_c; char_c: if (ENSURE_BUILD_STRING(bs, 4)) { if (c >= 32 && c <= 126) *bs->pos++ = c; else if (c < 32) { *bs->pos++ = '^'; *bs->pos++ = c + 64; } else if (cli->utf8 && c >= 127 && c < 0x110000) { bs->pos = encode_utf8(bs->pos, 4, c); } else if (c >= 127 && c <= 255) { sprintf(bs->pos, "\\%03o", c & 0xFF); bs->pos += 4; } else { *bs->pos++ = '\\'; *bs->pos++ = '?'; } } break; case 'd': { int d = va_arg(val, int); if (ENSURE_BUILD_STRING(bs, 32)) { sprintf(bs->pos, "%d", d); bs->pos = strchr(bs->pos, 0); } break; } case 'O': { int optno = cli->current_option; const Clp_Option *opt = &cli->opt[optno]; if (optno < 0) append_build_string(bs, "(no current option!)", -1); else if (cli->current_short) { append_build_string(bs, cli->option_chars, -1); if (ENSURE_BUILD_STRING(bs, 5)) { if (cli->utf8) bs->pos = encode_utf8(bs->pos, 5, opt->short_name); else *bs->pos++ = opt->short_name; } } else if (cli->negated_by_no) { append_build_string(bs, cli->option_chars, -1); append_build_string(bs, "no-", 3); append_build_string(bs, opt->long_name + cli->iopt[optno].ilongoff, -1); } else { append_build_string(bs, cli->option_chars, -1); append_build_string(bs, opt->long_name + cli->iopt[optno].ilongoff, -1); } break; } case '%': if (ENSURE_BUILD_STRING(bs, 1)) *bs->pos++ = '%'; break; case '`': /* backwards compatibility */ case '<': append_build_string(bs, (cli->utf8 ? "\342\200\230" : "'"), -1); break; case '\'': /* backwards compatibility */ case ',': case '>': append_build_string(bs, (cli->utf8 ? "\342\200\231" : "'"), -1); break; default: if (ENSURE_BUILD_STRING(bs, 2)) { *bs->pos++ = '%'; *bs->pos++ = *percent; } break; } fmt = ++percent; } append_build_string(bs, fmt, -1); append_build_string(bs, "\n", 1); return bs; } static void do_error(Clp_Parser *clp, Clp_BuildString *bs) { const char *text; if (bs && !bs->bad) { *bs->pos = 0; text = bs->text; } else text = "out of memory\n"; if (clp->internal->error_handler != 0) (*clp->internal->error_handler)(clp, text); else fputs(text, stderr); } /** @param clp the parser * @param format error format * * Format an error message from @a format and any additional arguments in the * ellipsis. The resulting error string by printing it to standard error or * passing it to Clp_SetErrorHandler. * * The following format characters are accepted: * *
*
%c
*
A character (type int). Control characters are printed in * caret notation. If the parser is in UTF-8 mode, the character is formatted * in UTF-8. Otherwise, special characters are printed with backslashes and * octal notation.
*
%s
*
A string (type const char *).
*
%C
*
The argument is a string (type const char *). The first * character in this string is printed. If the parser is in UTF-8 mode, this * may involve multiple bytes.
*
%d
*
An integer (type int). Printed in decimal.
*
%O
*
The current option. No values are read from the argument list; the * current option is defined in the Clp_Parser object itself.
*
%%
*
Prints a percent character.
*
%<
*
Prints an open quote string. In UTF-8 mode, prints a left single * quote. Otherwise prints a single quote.
*
%>
*
Prints a closing quote string. In UTF-8 mode, prints a right single * quote. Otherwise prints a single quote.
*
%,
*
Prints an apostrophe. In UTF-8 mode, prints a right single quote. * Otherwise prints a single quote.
*
* * Note that no flag characters, precision, or field width characters are * currently supported. * * @sa Clp_SetErrorHandler */ int Clp_OptionError(Clp_Parser *clp, const char *format, ...) { Clp_BuildString *bs; va_list val; va_start(val, format); bs = Clp_VaOptionError(clp, 0, format, val); va_end(val); do_error(clp, bs); free_build_string(bs); return 0; } static int ambiguity_error(Clp_Parser *clp, int ambiguous, int *ambiguous_values, const Clp_Option *opt, const Clp_InternOption *iopt, const char *prefix, const char *fmt, ...) { Clp_Internal *cli = clp->internal; Clp_BuildString *bs; int i; va_list val; va_start(val, fmt); bs = Clp_VaOptionError(clp, 0, fmt, val); if (!bs) goto done; if (clp->internal->program_name && clp->internal->program_name[0]) { append_build_string(bs, clp->internal->program_name, -1); append_build_string(bs, ": ", 2); } append_build_string(bs, "(Possibilities are", -1); for (i = 0; i < ambiguous && i < MAX_AMBIGUOUS_VALUES; i++) { int value = ambiguous_values[i]; const char *no_dash = ""; if (value < 0) value = -(value + 1), no_dash = "no-"; if (i == 0) append_build_string(bs, " ", 1); else if (i == ambiguous - 1) append_build_string(bs, (i == 1 ? " and " : ", and "), -1); else append_build_string(bs, ", ", 2); append_build_string(bs, (cli->utf8 ? "\342\200\230" : "'"), -1); append_build_string(bs, prefix, -1); append_build_string(bs, no_dash, -1); append_build_string(bs, opt[value].long_name + iopt[value].ilongoff, -1); append_build_string(bs, (cli->utf8 ? "\342\200\231" : "'"), -1); } if (ambiguous > MAX_AMBIGUOUS_VALUES) append_build_string(bs, ", and others", -1); append_build_string(bs, ".)\n", -1); va_end(val); done: do_error(clp, bs); free_build_string(bs); return 0; } static int copy_string(char *buf, int buflen, int bufpos, const char *what) { int l = strlen(what); if (l > buflen - bufpos - 1) l = buflen - bufpos - 1; memcpy(buf + bufpos, what, l); return l; } /** @param clp the parser * @param buf output buffer * @param len length of output buffer * @return number of characters written to the buffer, not including the terminating NUL * * A string that looks like the last option parsed by @a clp is extracted into * @a buf. The correct option characters are put into the string first, * followed by the option text. The output buffer is null-terminated unless * @a len == 0. * * @sa Clp_CurOptionName */ int Clp_CurOptionNameBuf(Clp_Parser *clp, char *buf, int len) { Clp_Internal *cli = clp->internal; int optno = cli->current_option; int pos = 0; if (optno < 0) pos += copy_string(buf, len, pos, "(no current option!)"); else if (cli->current_short) { pos += copy_string(buf, len, pos, cli->option_chars); if (cli->utf8) pos = (encode_utf8(buf + pos, len - pos - 1, cli->opt[optno].short_name) - buf); else if (pos < len - 1) buf[pos++] = cli->opt[optno].short_name; } else if (cli->negated_by_no) { pos += copy_string(buf, len, pos, cli->option_chars); pos += copy_string(buf, len, pos, "no-"); pos += copy_string(buf, len, pos, cli->opt[optno].long_name + cli->iopt[optno].ilongoff); } else { pos += copy_string(buf, len, pos, cli->option_chars); pos += copy_string(buf, len, pos, cli->opt[optno].long_name + cli->iopt[optno].ilongoff); } if (pos < len) buf[pos] = 0; return pos; } /** @param clp the parser * @return string describing the current option * * This function acts like Clp_CurOptionNameBuf(), but returns a pointer into * a static buffer that will be rewritten on the next call to * Clp_CurOptionName(). * * @note This function is not thread safe. * * @sa Clp_CurOptionName */ const char * Clp_CurOptionName(Clp_Parser *clp) { static char buf[256]; Clp_CurOptionNameBuf(clp, buf, 256); return buf; } #ifdef __cplusplus } #endif gifsicle-1.78/src/quantize.c0000644000175000017500000024210312251246352012756 00000000000000/* quantize.c - Histograms and quantization for gifsicle. Copyright (C) 1997-2013 Eddie Kohler, ekohler@gmail.com This file is part of gifsicle. Gifsicle is free software. It is distributed under the GNU Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #include #include "gifsicle.h" #include #include #include #include #include #include /* kcolor: a 3D vector, each component has 15 bits of precision */ /* 15 bits means KC_MAX * KC_MAX always fits within a signed 32-bit integer, and a 3-D squared distance always fits within an unsigned 32-bit integer. */ #define KC_MAX 0x7FFF #define KC_WHOLE 0x8000 #define KC_HALF 0x4000 #define KC_BITS 15 typedef struct kcolor { int32_t a[3]; } kcolor; /* Invariant: (0<=x<256) ==> (srgb_revgamma[srgb_gamma[x] >> 7] <= x). */ static const uint16_t srgb_gamma_table_256[256] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 99, 110, 120, 132, 144, 157, 170, 184, 198, 213, 229, 246, 263, 281, 299, 319, 338, 359, 380, 403, 425, 449, 473, 498, 524, 551, 578, 606, 635, 665, 695, 727, 759, 792, 825, 860, 895, 931, 968, 1006, 1045, 1085, 1125, 1167, 1209, 1252, 1296, 1341, 1386, 1433, 1481, 1529, 1578, 1629, 1680, 1732, 1785, 1839, 1894, 1950, 2007, 2065, 2123, 2183, 2244, 2305, 2368, 2432, 2496, 2562, 2629, 2696, 2765, 2834, 2905, 2977, 3049, 3123, 3198, 3273, 3350, 3428, 3507, 3587, 3668, 3750, 3833, 3917, 4002, 4088, 4176, 4264, 4354, 4444, 4536, 4629, 4723, 4818, 4914, 5011, 5109, 5209, 5309, 5411, 5514, 5618, 5723, 5829, 5936, 6045, 6154, 6265, 6377, 6490, 6604, 6720, 6836, 6954, 7073, 7193, 7315, 7437, 7561, 7686, 7812, 7939, 8067, 8197, 8328, 8460, 8593, 8728, 8863, 9000, 9139, 9278, 9419, 9560, 9704, 9848, 9994, 10140, 10288, 10438, 10588, 10740, 10893, 11048, 11204, 11360, 11519, 11678, 11839, 12001, 12164, 12329, 12495, 12662, 12831, 13000, 13172, 13344, 13518, 13693, 13869, 14047, 14226, 14406, 14588, 14771, 14955, 15141, 15328, 15516, 15706, 15897, 16089, 16283, 16478, 16675, 16872, 17071, 17272, 17474, 17677, 17882, 18088, 18295, 18504, 18714, 18926, 19138, 19353, 19569, 19786, 20004, 20224, 20445, 20668, 20892, 21118, 21345, 21573, 21803, 22034, 22267, 22501, 22736, 22973, 23211, 23451, 23692, 23935, 24179, 24425, 24672, 24920, 25170, 25421, 25674, 25928, 26184, 26441, 26700, 26960, 27222, 27485, 27749, 28016, 28283, 28552, 28823, 29095, 29368, 29643, 29920, 30197, 30477, 30758, 31040, 31324, 31610, 31897, 32185, 32475, 32767 }; static const uint16_t srgb_revgamma_table_256[256] = { 0, 1628, 2776, 3619, 4309, 4904, 5434, 5914, 6355, 6765, 7150, 7513, 7856, 8184, 8497, 8798, 9086, 9365, 9634, 9895, 10147, 10393, 10631, 10864, 11091, 11312, 11528, 11739, 11946, 12148, 12347, 12541, 12732, 12920, 13104, 13285, 13463, 13639, 13811, 13981, 14149, 14314, 14476, 14637, 14795, 14951, 15105, 15257, 15408, 15556, 15703, 15848, 15991, 16133, 16273, 16412, 16549, 16685, 16819, 16953, 17084, 17215, 17344, 17472, 17599, 17725, 17849, 17973, 18095, 18217, 18337, 18457, 18575, 18692, 18809, 18925, 19039, 19153, 19266, 19378, 19489, 19600, 19710, 19819, 19927, 20034, 20141, 20247, 20352, 20457, 20560, 20664, 20766, 20868, 20969, 21070, 21170, 21269, 21368, 21466, 21564, 21661, 21758, 21854, 21949, 22044, 22138, 22232, 22326, 22418, 22511, 22603, 22694, 22785, 22875, 22965, 23055, 23144, 23232, 23321, 23408, 23496, 23583, 23669, 23755, 23841, 23926, 24011, 24095, 24180, 24263, 24347, 24430, 24512, 24595, 24676, 24758, 24839, 24920, 25001, 25081, 25161, 25240, 25319, 25398, 25477, 25555, 25633, 25710, 25788, 25865, 25941, 26018, 26094, 26170, 26245, 26321, 26396, 26470, 26545, 26619, 26693, 26766, 26840, 26913, 26986, 27058, 27130, 27202, 27274, 27346, 27417, 27488, 27559, 27630, 27700, 27770, 27840, 27910, 27979, 28048, 28117, 28186, 28255, 28323, 28391, 28459, 28527, 28594, 28661, 28728, 28795, 28862, 28928, 28995, 29061, 29127, 29192, 29258, 29323, 29388, 29453, 29518, 29582, 29646, 29711, 29775, 29838, 29902, 29965, 30029, 30092, 30155, 30217, 30280, 30342, 30404, 30466, 30528, 30590, 30652, 30713, 30774, 30835, 30896, 30957, 31017, 31078, 31138, 31198, 31258, 31318, 31378, 31437, 31497, 31556, 31615, 31674, 31733, 31791, 31850, 31908, 31966, 32024, 32082, 32140, 32198, 32255, 32313, 32370, 32427, 32484, 32541, 32598, 32654, 32711 }; static uint16_t* gamma_tables[2] = { (uint16_t*) srgb_gamma_table_256, (uint16_t*) srgb_revgamma_table_256 }; static inline void kc_clear(kcolor* x) { x->a[0] = x->a[1] = x->a[2] = 0; } static inline void kc_clamp(kcolor* x) { int i; for (i = 0; i < 3; ++i) { if (x->a[i] < 0) x->a[i] = 0; if (x->a[i] > KC_MAX) x->a[i] = KC_MAX; } } static inline void kc_set8g(kcolor* x, int a0, int a1, int a2) { x->a[0] = gamma_tables[0][a0]; x->a[1] = gamma_tables[0][a1]; x->a[2] = gamma_tables[0][a2]; } static inline void kc_revgamma_transform(kcolor* x) { int d; for (d = 0; d != 3; ++d) { int c = gamma_tables[1][x->a[d] >> 7]; while (c < 0x7F80 && x->a[d] >= gamma_tables[0][(c + 0x80) >> 7]) c += 0x80; x->a[d] = c; } } static const char* USED_ATTR kc_debug_str(kcolor x) { static int whichbuf = 0; static char buf[4][8]; whichbuf = (whichbuf + 1) % 4; kc_revgamma_transform(&x); sprintf(buf[whichbuf], "#%02X%02X%02X", x.a[0] >> 7, x.a[1] >> 7, x.a[2] >> 7); return buf[whichbuf]; } void kc_set_gamma(int type, double gamma) { #if HAVE_POW static int cur_type = KC_GAMMA_SRGB; static double cur_gamma = 2.2; int i, j; if (type == cur_type && (type != KC_GAMMA_NUMERIC || gamma == cur_gamma)) return; if (type == KC_GAMMA_SRGB) { if (gamma_tables[0] != srgb_gamma_table_256) { Gif_DeleteArray(gamma_tables[0]); Gif_DeleteArray(gamma_tables[1]); } gamma_tables[0] = (uint16_t*) srgb_gamma_table_256; gamma_tables[1] = (uint16_t*) srgb_revgamma_table_256; } else { if (gamma_tables[0] == srgb_gamma_table_256) { gamma_tables[0] = Gif_NewArray(uint16_t, 256); gamma_tables[1] = Gif_NewArray(uint16_t, 256); } for (j = 0; j != 256; ++j) { gamma_tables[0][j] = (int) (pow(i/255.0, gamma) * 32767); gamma_tables[1][j] = (int) (pow(i/256.0, 1/gamma) * 32767); for (i = 0; i != 2; ++i) while (j && gamma_tables[i][j] <= gamma_tables[i][j-1] && gamma_tables[i][j] < 3267) ++gamma_tables[i][j]; } } cur_type = type; cur_gamma = gamma; #else (void) type, (void) gamma; #endif } #if 0 static void kc_test_gamma() { int x, y, z; for (x = 0; x != 256; ++x) for (y = 0; y != 256; ++y) for (z = 0; z != 256; ++z) { kcolor k; kc_set8g(&k, x, y, z); kc_revgamma_transform(&k); if ((k.a[0] >> 7) != x || (k.a[1] >> 7) != y || (k.a[2] >> 7) != z) { kcolor kg; kc_set8g(&kg, x, y, z); fprintf(stderr, "#%02X%02X%02X ->g #%04X%04X%04X ->revg #%02X%02X%02X!\n", x, y, z, kg.a[0], kg.a[1], kg.a[2], k.a[0] >> 7, k.a[1] >> 7, k.a[2] >> 7); assert(0); } } } #endif static inline uint32_t kc_distance(const kcolor* x, const kcolor* y) { return (x->a[0] - y->a[0]) * (x->a[0] - y->a[0]) + (x->a[1] - y->a[1]) * (x->a[1] - y->a[1]) + (x->a[2] - y->a[2]) * (x->a[2] - y->a[2]); } static inline int kc_luminance(const kcolor* x) { return (306 * x->a[0] + 601 * x->a[1] + 117 * x->a[2]) >> 10; } static inline void kc_luminance_transform(kcolor* x) { /* For grayscale colormaps, use distance in luminance space instead of distance in RGB space. The weights for the R,G,B components in luminance space are 0.299,0.587,0.114. Using the proportional factors 306, 601, and 117 we get a scaled gray value between 0 and 255 * 1024. Thanks to Christian Kumpf, , for providing a patch. */ x->a[0] = x->a[1] = x->a[2] = kc_luminance(x); } typedef struct Gif_Histogram { Gif_Color *c; int n; int cap; } Gif_Histogram; static void add_histogram_color(Gif_Color *, Gif_Histogram *, unsigned long); static void init_histogram(Gif_Histogram *new_hist, Gif_Histogram *old_hist) { int new_cap = (old_hist ? old_hist->cap * 2 : 1024); Gif_Color *nc = Gif_NewArray(Gif_Color, new_cap); int i; new_hist->c = nc; new_hist->n = 0; new_hist->cap = new_cap; for (i = 0; i < new_cap; i++) new_hist->c[i].haspixel = 0; if (old_hist) for (i = 0; i < old_hist->cap; i++) if (old_hist->c[i].haspixel) add_histogram_color(&old_hist->c[i], new_hist, old_hist->c[i].pixel); } static void delete_histogram(Gif_Histogram *hist) { Gif_DeleteArray(hist->c); } static void add_histogram_color(Gif_Color *color, Gif_Histogram *hist, unsigned long count) { Gif_Color *hc = hist->c; int hcap = hist->cap - 1; int i = (((color->gfc_red & 0xF0) << 4) | (color->gfc_green & 0xF0) | (color->gfc_blue >> 4)) & hcap; int hash2 = ((((color->gfc_red & 0x0F) << 8) | ((color->gfc_green & 0x0F) << 4) | (color->gfc_blue & 0x0F)) & hcap) | 1; for (; hc[i].haspixel; i = (i + hash2) & hcap) if (GIF_COLOREQ(&hc[i], color)) { hc[i].pixel += count; color->haspixel = 1; color->pixel = i; return; } if (hist->n > ((hist->cap * 7) >> 3)) { Gif_Histogram new_hist; init_histogram(&new_hist, hist); delete_histogram(hist); *hist = new_hist; hc = hist->c; /* 31.Aug.1999 - bug fix from Steven Marthouse */ } hist->n++; hc[i] = *color; hc[i].haspixel = 1; hc[i].pixel = count; color->haspixel = 1; color->pixel = i; } static int popularity_sort_compare(const void *va, const void *vb) { const Gif_Color *a = (const Gif_Color *)va; const Gif_Color *b = (const Gif_Color *)vb; return b->pixel - a->pixel; } static int pixel_sort_compare(const void *va, const void *vb) { const Gif_Color *a = (const Gif_Color *)va; const Gif_Color *b = (const Gif_Color *)vb; return a->pixel - b->pixel; } Gif_Color * histogram(Gif_Stream *gfs, int *nhist_store) { Gif_Histogram hist; Gif_Color *linear; Gif_Color transparent_color; unsigned long ntransparent = 0; unsigned long nbackground = 0; int x, y, i; unmark_colors(gfs->global); for (i = 0; i < gfs->nimages; i++) unmark_colors(gfs->images[i]->local); init_histogram(&hist, 0); /* Count pixels. Be careful about values which are outside the range of the colormap. */ for (i = 0; i < gfs->nimages; i++) { Gif_Image *gfi = gfs->images[i]; Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global; uint32_t count[256]; Gif_Color *col; int ncol; int transparent = gfi->transparent; int only_compressed = (gfi->img == 0); if (!gfcm) continue; /* unoptimize the image if necessary */ if (only_compressed) Gif_UncompressImage(gfi); /* sweep over the image data, counting pixels */ for (x = 0; x < 256; x++) count[x] = 0; for (y = 0; y < gfi->height; y++) { uint8_t *data = gfi->img[y]; for (x = 0; x < gfi->width; x++, data++) count[*data]++; } /* add counted colors to global histogram */ col = gfcm->col; ncol = gfcm->ncol; for (x = 0; x < ncol; x++) if (count[x] && x != transparent) { if (col[x].haspixel) hist.c[ col[x].pixel ].pixel += count[x]; else add_histogram_color(&col[x], &hist, count[x]); } if (transparent >= 0) { if (ntransparent == 0) transparent_color = col[transparent]; ntransparent += count[transparent]; } /* if this image has background disposal, count its size towards the background's pixel count */ if (gfi->disposal == GIF_DISPOSAL_BACKGROUND) nbackground += gfi->width * gfi->height; /* unoptimize the image if necessary */ if (only_compressed) Gif_ReleaseUncompressedImage(gfi); } /* account for background by adding it to 'ntransparent' or the histogram */ if (gfs->images[0]->transparent < 0 && gfs->global && gfs->background < gfs->global->ncol) add_histogram_color(&gfs->global->col[gfs->background], &hist, nbackground); else ntransparent += nbackground; /* now, make the linear histogram from the hashed histogram */ linear = Gif_NewArray(Gif_Color, hist.n + 1); i = 0; /* Put all transparent pixels in histogram slot 0. Transparent pixels are marked by haspixel == 255. */ if (ntransparent) { linear[0] = transparent_color; linear[0].haspixel = 255; linear[0].pixel = ntransparent; i++; } /* put hash histogram colors into linear histogram */ for (x = 0; x < hist.cap; x++) if (hist.c[x].haspixel) linear[i++] = hist.c[x]; delete_histogram(&hist); *nhist_store = i; return linear; } #undef min #undef max #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) static int red_sort_compare(const void *va, const void *vb) { const Gif_Color *a = (const Gif_Color *)va; const Gif_Color *b = (const Gif_Color *)vb; return a->gfc_red - b->gfc_red; } static int green_sort_compare(const void *va, const void *vb) { const Gif_Color *a = (const Gif_Color *)va; const Gif_Color *b = (const Gif_Color *)vb; return a->gfc_green - b->gfc_green; } static int blue_sort_compare(const void *va, const void *vb) { const Gif_Color *a = (const Gif_Color *)va; const Gif_Color *b = (const Gif_Color *)vb; return a->gfc_blue - b->gfc_blue; } static void assert_hist_transparency(Gif_Color *hist, int nhist) { int i; for (i = 1; i < nhist; i++) assert(hist[i].haspixel != 255); } /* COLORMAP FUNCTIONS return a palette (a vector of Gif_Colors). The pixel fields are undefined; the haspixel fields are all 0. */ typedef struct { int first; int count; uint32_t pixel; } adaptive_slot; Gif_Colormap * colormap_median_cut(Gif_Color* hist, int nhist, Gt_OutputData* od) { int adapt_size = od->colormap_size; adaptive_slot *slots = Gif_NewArray(adaptive_slot, adapt_size); Gif_Colormap *gfcm = Gif_NewFullColormap(adapt_size, 256); Gif_Color *adapt = gfcm->col; int nadapt; int i, j; /* This code was written with reference to ppmquant by Jef Poskanzer, part of the pbmplus package. */ if (adapt_size < 2 || adapt_size > 256) fatal_error("adaptive palette size must be between 2 and 256"); if (adapt_size >= nhist && !od->colormap_fixed) warning(1, "trivial adaptive palette (only %d colors in source)", nhist); if (adapt_size >= nhist) adapt_size = nhist; /* 0. remove any transparent color from consideration; reduce adaptive palette size to accommodate transparency if it looks like that'll be necessary */ assert_hist_transparency(hist, nhist); if (adapt_size > 2 && adapt_size < nhist && hist[0].haspixel == 255 && nhist <= 265) adapt_size--; if (hist[0].haspixel == 255) { hist[0] = hist[nhist - 1]; nhist--; } /* 1. set up the first slot, containing all pixels. */ { uint32_t total = 0; for (i = 0; i < nhist; i++) total += hist[i].pixel; slots[0].first = 0; slots[0].count = nhist; slots[0].pixel = total; qsort(hist, nhist, sizeof(Gif_Color), pixel_sort_compare); } /* 2. split slots until we have enough. */ for (nadapt = 1; nadapt < adapt_size; nadapt++) { adaptive_slot *split = 0; Gif_Color minc, maxc, *slice; /* 2.1. pick the slot to split. */ { uint32_t split_pixel = 0; for (i = 0; i < nadapt; i++) if (slots[i].count >= 2 && slots[i].pixel > split_pixel) { split = &slots[i]; split_pixel = slots[i].pixel; } if (!split) break; } slice = &hist[split->first]; /* 2.2. find its extent. */ { Gif_Color *trav = slice; minc = maxc = *trav; for (i = 1, trav++; i < split->count; i++, trav++) { minc.gfc_red = min(minc.gfc_red, trav->gfc_red); maxc.gfc_red = max(maxc.gfc_red, trav->gfc_red); minc.gfc_green = min(minc.gfc_green, trav->gfc_green); maxc.gfc_green = max(maxc.gfc_green, trav->gfc_green); minc.gfc_blue = min(minc.gfc_blue, trav->gfc_blue); maxc.gfc_blue = max(maxc.gfc_blue, trav->gfc_blue); } } /* 2.3. decide how to split it. use the luminance method. also sort the colors. */ { double red_diff = 0.299 * (maxc.gfc_red - minc.gfc_red); double green_diff = 0.587 * (maxc.gfc_green - minc.gfc_green); double blue_diff = 0.114 * (maxc.gfc_blue - minc.gfc_blue); if (red_diff >= green_diff && red_diff >= blue_diff) qsort(slice, split->count, sizeof(Gif_Color), red_sort_compare); else if (green_diff >= blue_diff) qsort(slice, split->count, sizeof(Gif_Color), green_sort_compare); else qsort(slice, split->count, sizeof(Gif_Color), blue_sort_compare); } /* 2.4. decide where to split the slot and split it there. */ { uint32_t half_pixels = split->pixel / 2; uint32_t pixel_accum = slice[0].pixel; uint32_t diff1, diff2; for (i = 1; i < split->count - 1 && pixel_accum < half_pixels; i++) pixel_accum += slice[i].pixel; /* We know the area before the split has more pixels than the area after, possibly by a large margin (bad news). If it would shrink the margin, change the split. */ diff1 = 2*pixel_accum - split->pixel; diff2 = split->pixel - 2*(pixel_accum - slice[i-1].pixel); if (diff2 < diff1 && i > 1) { i--; pixel_accum -= slice[i].pixel; } slots[nadapt].first = split->first + i; slots[nadapt].count = split->count - i; slots[nadapt].pixel = split->pixel - pixel_accum; split->count = i; split->pixel = pixel_accum; } } /* 3. make the new palette by choosing one color from each slot. */ for (i = 0; i < nadapt; i++) { double red_total = 0, green_total = 0, blue_total = 0; Gif_Color *slice = &hist[ slots[i].first ]; kcolor k; for (j = 0; j < slots[i].count; j++) { kc_set8g(&k, slice[j].gfc_red, slice[j].gfc_green, slice[j].gfc_blue); red_total += k.a[0] * (double) slice[j].pixel; green_total += k.a[1] * (double) slice[j].pixel; blue_total += k.a[2] * (double) slice[j].pixel; } k.a[0] = (int) (red_total / slots[i].pixel); k.a[1] = (int) (green_total / slots[i].pixel); k.a[2] = (int) (blue_total / slots[i].pixel); kc_revgamma_transform(&k); adapt[i].gfc_red = (uint8_t) (k.a[0] >> 7); adapt[i].gfc_green = (uint8_t) (k.a[1] >> 7); adapt[i].gfc_blue = (uint8_t) (k.a[2] >> 7); adapt[i].haspixel = 0; } Gif_DeleteArray(slots); gfcm->ncol = nadapt; return gfcm; } static Gif_Colormap * colormap_diversity(Gif_Color *hist, int nhist, Gt_OutputData* od, int blend) { int adapt_size = od->colormap_size; uint32_t* min_dist = Gif_NewArray(uint32_t, nhist); uint32_t* min_dither_dist = Gif_NewArray(uint32_t, nhist); int *closest = Gif_NewArray(int, nhist); kcolor* gchist = Gif_NewArray(kcolor, nhist); /* gamma-corrected */ Gif_Colormap *gfcm = Gif_NewFullColormap(adapt_size, 256); Gif_Color *adapt = gfcm->col; int nadapt = 0; int i, j, match = 0; /* This code was uses XV's modified diversity algorithm, and was written with reference to XV's implementation of that algorithm by John Bradley and Tom Lane . */ if (adapt_size < 2 || adapt_size > 256) fatal_error("adaptive palette size must be between 2 and 256"); if (adapt_size > nhist && !od->colormap_fixed) warning(1, "trivial adaptive palette (only %d colors in source)", nhist); if (adapt_size > nhist) adapt_size = nhist; /* 0. remove any transparent color from consideration; reduce adaptive palette size to accommodate transparency if it looks like that'll be necessary */ assert_hist_transparency(hist, nhist); /* It will be necessary to accommodate transparency if (1) there is transparency in the image; (2) the adaptive palette isn't trivial; and (3) there are a small number of colors in the image (arbitrary constant: <= 265), so it's likely that most images will use most of the slots, so it's likely there won't be unused slots. */ if (adapt_size > 2 && adapt_size < nhist && hist[0].haspixel == 255 && nhist <= 265) adapt_size--; if (hist[0].haspixel == 255) { hist[0] = hist[nhist - 1]; nhist--; } /* blending has bad effects when there are very few colors */ if (adapt_size < 4) blend = 0; /* 1. initialize min_dist and sort the colors in order of popularity. */ for (i = 0; i < nhist; i++) min_dist[i] = min_dither_dist[i] = 0xFFFFFFFF; qsort(hist, nhist, sizeof(Gif_Color), popularity_sort_compare); /* 1.5. gamma-correct hist colors */ for (i = 0; i < nhist; ++i) kc_set8g(&gchist[i], hist[i].gfc_red, hist[i].gfc_green, hist[i].gfc_blue); /* 2. choose colors one at a time */ for (nadapt = 0; nadapt < adapt_size; nadapt++) { int chosen; /* 2.0. find the first non-chosen color */ for (chosen = 0; min_dist[chosen] == 0; ++chosen) /* do nothing */; /* 2.1. choose the color to be added */ if (nadapt == 0 || (nadapt >= 10 && nadapt % 2 == 0)) { /* 2.1a. want most popular unchosen color; we've sorted them on popularity, so we're done! */ } else if (od->dither_type == dither_none) { /* 2.1b. choose based on diversity from unchosen colors */ for (i = chosen + 1; i != nhist; ++i) if (min_dist[i] > min_dist[chosen]) chosen = i; } else { /* 2.1c. choose based on diversity from unchosen colors, but allow dithered combinations to stand in for colors, particularly early on in the color finding process */ #if HAVE_POW /* Weight assigned to dithered combinations drops as we proceed. */ double dweight = 0.05 + pow(0.25, 1 + (nadapt - 1) / 3.); #else double dweight = nadapt < 4 ? 0.25 : 0.125; #endif double max_dist = min_dist[chosen] + min_dither_dist[chosen] * dweight; for (i = chosen + 1; i != nhist; ++i) if (min_dist[i] != 0) { double dist = min_dist[i] + min_dither_dist[i] * dweight; if (dist > max_dist) { chosen = i; max_dist = dist; } } } /* 2.2. add the color */ min_dist[chosen] = min_dither_dist[chosen] = 0; closest[chosen] = nadapt; adapt[nadapt] = hist[chosen]; adapt[nadapt].pixel = chosen; adapt[nadapt].haspixel = 0; /* 2.3. adjust the min_dist array */ for (i = 0; i < nhist; ++i) if (min_dist[i]) { uint32_t dist = kc_distance(&gchist[i], &gchist[chosen]); if (dist < min_dist[i]) { min_dist[i] = dist; closest[i] = nadapt; } } /* 2.4. also account for dither distances */ if (od->dither_type != dither_none && nadapt > 0 && nadapt < 64) for (j = 0; j < nadapt; ++j) { kcolor x = gchist[chosen], *y = &gchist[adapt[j].pixel]; /* penalize combinations with large luminance difference */ double dL = fabs(kc_luminance(&x) - kc_luminance(y)); dL = (dL > 8192 ? dL * 4 / 32767. : 1); /* create combination */ for (i = 0; i < 3; ++i) x.a[i] = (x.a[i] + y->a[i]) >> 1; /* track closeness of combination to other colors */ for (i = 0; i < nhist; ++i) if (min_dist[i]) { double dist = kc_distance(&gchist[i], &x) * dL; if (dist < min_dither_dist[i]) min_dither_dist[i] = (uint32_t) dist; } } } /* 3. make the new palette by choosing one color from each slot. */ if (blend) { for (i = 0; i < nadapt; i++) { double red_total = 0, green_total = 0, blue_total = 0; uint32_t pixel_total = 0, mismatch_pixel_total = 0; for (j = 0; j < nhist; j++) if (closest[j] == i) { double pixel = hist[j].pixel; red_total += gchist[j].a[0] * pixel; green_total += gchist[j].a[1] * pixel; blue_total += gchist[j].a[2] * pixel; pixel_total += pixel; if (min_dist[j]) mismatch_pixel_total += pixel; else match = j; } /* Only blend if total number of mismatched pixels exceeds total number of matched pixels by a large margin. */ if (3 * mismatch_pixel_total <= 2 * pixel_total) adapt[i] = hist[match]; else { /* Favor, by a smallish amount, the color the plain diversity algorithm would pick. */ double pixel = hist[match].pixel * 2; kcolor k; red_total += gchist[match].a[0] * pixel; green_total += gchist[match].a[1] * pixel; blue_total += gchist[match].a[2] * pixel; pixel_total += pixel; k.a[0] = (int) (red_total / pixel_total); k.a[1] = (int) (green_total / pixel_total); k.a[2] = (int) (blue_total / pixel_total); kc_revgamma_transform(&k); adapt[i].gfc_red = (uint8_t) (k.a[0] >> 7); adapt[i].gfc_green = (uint8_t) (k.a[1] >> 7); adapt[i].gfc_blue = (uint8_t) (k.a[2] >> 7); } adapt[i].haspixel = 0; } } Gif_DeleteArray(min_dist); Gif_DeleteArray(min_dither_dist); Gif_DeleteArray(closest); Gif_DeleteArray(gchist); gfcm->ncol = nadapt; return gfcm; } Gif_Colormap* colormap_blend_diversity(Gif_Color* hist, int nhist, Gt_OutputData* od) { return colormap_diversity(hist, nhist, od, 1); } Gif_Colormap* colormap_flat_diversity(Gif_Color* hist, int nhist, Gt_OutputData* od) { return colormap_diversity(hist, nhist, od, 0); } /***** * kd_tree allocation and deallocation **/ typedef struct kd3_item { kcolor k; int index; } kd3_item; typedef struct kd3_treepos { int pivot; int offset; } kd3_treepos; struct kd3_tree { kd3_treepos* tree; int ntree; int disabled; kd3_item* items; int nitems; int items_cap; int maxdepth; void (*transform)(kcolor*); unsigned* xradius; }; void kd3_init(kd3_tree* kd3, void (*transform)(kcolor*)) { kd3->tree = NULL; kd3->items = Gif_NewArray(kd3_item, 256); kd3->nitems = 0; kd3->items_cap = 256; kd3->transform = transform; kd3->xradius = NULL; kd3->disabled = -1; } void kd3_cleanup(kd3_tree* kd3) { Gif_DeleteArray(kd3->tree); Gif_DeleteArray(kd3->items); Gif_DeleteArray(kd3->xradius); } void kd3_add_transformed(kd3_tree* kd3, const kcolor* k) { if (kd3->nitems == kd3->items_cap) { kd3->items_cap *= 2; Gif_ReArray(kd3->items, kd3_item, kd3->items_cap); } kd3->items[kd3->nitems].k = *k; kd3->items[kd3->nitems].index = kd3->nitems; ++kd3->nitems; } void kd3_add8g(kd3_tree* kd3, int a0, int a1, int a2) { kcolor k; kc_set8g(&k, a0, a1, a2); if (kd3->transform) kd3->transform(&k); kd3_add_transformed(kd3, &k); } static int kd3_item_compar_0(const void* a, const void* b) { const kd3_item* aa = (const kd3_item*) a, *bb = (const kd3_item*) b; return aa->k.a[0] - bb->k.a[0]; } static int kd3_item_compar_1(const void* a, const void* b) { const kd3_item* aa = (const kd3_item*) a, *bb = (const kd3_item*) b; return aa->k.a[1] - bb->k.a[1]; } static int kd3_item_compar_2(const void* a, const void* b) { const kd3_item* aa = (const kd3_item*) a, *bb = (const kd3_item*) b; return aa->k.a[2] - bb->k.a[2]; } static int (*kd3_item_compars[])(const void*, const void*) = { &kd3_item_compar_0, &kd3_item_compar_1, &kd3_item_compar_2 }; static int kd3_build_range(kd3_tree* kd3, kd3_item* items, int l, int r, int n, int depth) { int m, nl, nr, aindex = depth % 3; if (depth > kd3->maxdepth) kd3->maxdepth = depth; while (n >= kd3->ntree) { kd3->ntree *= 2; Gif_ReArray(kd3->tree, kd3_treepos, kd3->ntree); } if (l + 1 >= r) { kd3->tree[n].pivot = (l == r ? -1 : items[l].index); kd3->tree[n].offset = -1; return 2; } qsort(&items[l], r - l, sizeof(kd3_item), kd3_item_compars[aindex]); /* pick pivot: a color component to split */ m = l + ((r - l) >> 1); while (m > l && items[m].k.a[aindex] == items[m-1].k.a[aindex]) --m; if (m == l) { /* don't split entirely to the right (infinite loop) */ m = l + ((r - l) >> 1); while (m < r && items[m].k.a[aindex] == items[m-1].k.a[aindex]) ++m; } if (m == l) kd3->tree[n].pivot = items[m].k.a[aindex]; else kd3->tree[n].pivot = items[m-1].k.a[aindex] + ((items[m].k.a[aindex] - items[m-1].k.a[aindex]) >> 1); /* recurse */ nl = kd3_build_range(kd3, items, l, m, n+1, depth+1); kd3->tree[n].offset = 1+nl; nr = kd3_build_range(kd3, items, m, r, n+1+nl, depth+1); return 1+nl+nr; } static int kd3_item_all_compar(const void* a, const void* b) { const kd3_item* aa = (const kd3_item*) a, *bb = (const kd3_item*) b; if (aa->k.a[0] - bb->k.a[0]) return aa->k.a[0] - bb->k.a[0]; else if (aa->k.a[1] - bb->k.a[1]) return aa->k.a[1] - bb->k.a[1]; else return aa->k.a[2] - bb->k.a[2]; } #if 0 static void kd3_print_depth(kd3_tree* kd3, int depth, kd3_treepos* p, int* a, int* b) { int i; char x[6][10]; for (i = 0; i != 3; ++i) { if (a[i] == INT_MIN) sprintf(x[2*i], "*"); else sprintf(x[2*i], "%d", a[i]); if (b[i] == INT_MAX) sprintf(x[2*i+1], "*"); else sprintf(x[2*i+1], "%d", b[i]); } printf("%*s<%s:%s,%s:%s,%s:%s>", depth*3, "", x[0], x[1], x[2], x[3], x[4], x[5]); if (p->offset < 0) { if (p->pivot >= 0) { assert(kd3->items[p->pivot].k.a[0] >= a[0]); assert(kd3->items[p->pivot].k.a[1] >= a[1]); assert(kd3->items[p->pivot].k.a[2] >= a[2]); assert(kd3->items[p->pivot].k.a[0] < b[0]); assert(kd3->items[p->pivot].k.a[1] < b[1]); assert(kd3->items[p->pivot].k.a[2] < b[2]); printf(" ** @%d: <%d,%d,%d>\n", p->pivot, kd3->items[p->pivot].k.a[0], kd3->items[p->pivot].k.a[1], kd3->items[p->pivot].k.a[2]); } } else { int aindex = depth % 3, x[3]; assert(p->pivot >= a[aindex]); assert(p->pivot < b[aindex]); printf((aindex == 0 ? " | <%d,_,_>\n" : aindex == 1 ? " | <_,%d,_>\n" : " | <_,_,%d>\n"), p->pivot); memcpy(x, b, sizeof(int) * 3); x[aindex] = p->pivot; kd3_print_depth(kd3, depth + 1, p + 1, a, x); memcpy(x, a, sizeof(int) * 3); x[aindex] = p->pivot; kd3_print_depth(kd3, depth + 1, p + p->offset, x, b); } } static void kd3_print(kd3_tree* kd3) { int a[3], b[3]; a[0] = a[1] = a[2] = INT_MIN; b[0] = b[1] = b[2] = INT_MAX; kd3_print_depth(kd3, 0, kd3->tree, a, b); } #endif void kd3_build_xradius(kd3_tree* kd3) { int i, j; /* create xradius */ if (kd3->xradius) return; kd3->xradius = Gif_NewArray(unsigned, kd3->nitems); for (i = 0; i != kd3->nitems; ++i) kd3->xradius[i] = (unsigned) -1; for (i = 0; i != kd3->nitems; ++i) for (j = i + 1; j != kd3->nitems; ++j) { unsigned dist = kc_distance(&kd3->items[i].k, &kd3->items[j].k); unsigned radius = dist / 4; if (radius < kd3->xradius[i]) kd3->xradius[i] = radius; if (radius < kd3->xradius[j]) kd3->xradius[j] = radius; } } void kd3_build(kd3_tree* kd3) { kd3_item* items; int i, delta; assert(!kd3->tree); /* create tree */ kd3->tree = Gif_NewArray(kd3_treepos, 256); kd3->ntree = 256; kd3->maxdepth = 0; /* create copy of items; remove duplicates */ items = Gif_NewArray(kd3_item, kd3->nitems); memcpy(items, kd3->items, sizeof(kd3_item) * kd3->nitems); qsort(items, kd3->nitems, sizeof(kd3_item), kd3_item_all_compar); for (i = 0, delta = 1; i != kd3->nitems - delta; ++i) if (items[i].k.a[0] == items[i+delta].k.a[0] && items[i].k.a[1] == items[i+delta].k.a[1] && items[i].k.a[2] == items[i+delta].k.a[2]) ++delta, --i; else if (delta > 1) items[i+1] = items[i+delta]; kd3_build_range(kd3, items, 0, kd3->nitems - (delta - 1), 0, 0); assert(kd3->maxdepth < 32); Gif_DeleteArray(items); } void kd3_disable(kd3_tree* kd3, int i) { assert((unsigned) i < (unsigned) kd3->nitems); if (kd3->items[i].index >= 0) { kd3->items[i].index = kd3->disabled; kd3->disabled = -i - 2; } } void kd3_enable(kd3_tree* kd3, int i) { int* pprev = &kd3->disabled; assert((unsigned) i < (unsigned) kd3->nitems); while (*pprev != -1 && *pprev != -i - 2) pprev = &kd3->items[-*pprev - 2].index; if (*pprev == -i - 2) { *pprev = kd3->items[i].index; kd3->items[i].index = i; } } void kd3_enable_all(kd3_tree* kd3) { while (kd3->disabled != -1) { int i = -kd3->disabled - 2; kd3->disabled = kd3->items[i].index; kd3->items[i].index = i; } } int kd3_closest_transformed(const kd3_tree* kd3, const kcolor* k) { const kd3_treepos* stack[32]; uint8_t state[32]; int stackpos = 0; int result = -1; unsigned mindist = (unsigned) -1; assert(kd3->tree); stack[0] = kd3->tree; state[0] = 0; while (stackpos >= 0) { const kd3_treepos* p; assert(stackpos < 32); p = stack[stackpos]; if (p->offset < 0) { if (p->pivot >= 0 && kd3->items[p->pivot].index >= 0) { unsigned dist = kc_distance(&kd3->items[p->pivot].k, k); if (dist < mindist) { mindist = dist; result = p->pivot; } } if (--stackpos >= 0) ++state[stackpos]; } else if (state[stackpos] == 0) { if (k->a[stackpos % 3] < p->pivot) stack[stackpos + 1] = p + 1; else stack[stackpos + 1] = p + p->offset; ++stackpos; state[stackpos] = 0; } else { int delta = k->a[stackpos % 3] - p->pivot; if (state[stackpos] == 1 && (unsigned) (delta * delta) < mindist) { if (delta < 0) stack[stackpos + 1] = p + p->offset; else stack[stackpos + 1] = p + 1; ++stackpos; state[stackpos] = 0; } else if (--stackpos >= 0) ++state[stackpos]; } } return result; } int kd3_closest(const kd3_tree* kd3, kcolor k) { if (kd3->transform) kd3->transform(&k); return kd3_closest_transformed(kd3, &k); } int kd3_closest8(const kd3_tree* kd3, int a0, int a1, int a2) { kcolor k; kc_set8g(&k, a0, a1, a2); if (kd3->transform) kd3->transform(&k); return kd3_closest_transformed(kd3, &k); } void colormap_image_posterize(Gif_Image *gfi, uint8_t *new_data, Gif_Colormap *old_cm, kd3_tree* kd3, uint32_t *histogram) { int ncol = old_cm->ncol; Gif_Color *col = old_cm->col; int map[256]; int i, j; int transparent = gfi->transparent; /* find closest colors in new colormap */ for (i = 0; i < ncol; i++) { map[i] = col[i].pixel = kd3_closest8(kd3, col[i].gfc_red, col[i].gfc_green, col[i].gfc_blue); col[i].haspixel = 1; } /* map image */ for (j = 0; j < gfi->height; j++) { uint8_t *data = gfi->img[j]; for (i = 0; i < gfi->width; i++, data++, new_data++) if (*data != transparent) { *new_data = map[*data]; histogram[*new_data]++; } } } #define DITHER_SCALE 1024 #define DITHER_SHIFT 10 #define DITHER_SCALE_M1 (DITHER_SCALE-1) #define DITHER_ITEM2ERR (1<<(DITHER_SHIFT-7)) #define N_RANDOM_VALUES 512 void colormap_image_floyd_steinberg(Gif_Image *gfi, uint8_t *all_new_data, Gif_Colormap *old_cm, kd3_tree* kd3, uint32_t *histogram) { static int32_t *random_values = 0; int width = gfi->width; int dither_direction = 0; int transparent = gfi->transparent; int i, j, k; kcolor *err, *err1; /* Initialize distances */ for (i = 0; i < old_cm->ncol; ++i) { Gif_Color* c = &old_cm->col[i]; c->pixel = kd3_closest8(kd3, c->gfc_red, c->gfc_green, c->gfc_blue); c->haspixel = 1; } /* This code was written with reference to ppmquant by Jef Poskanzer, part of the pbmplus package. */ /* Initialize Floyd-Steinberg error vectors to small random values, so we don't get artifacts on the top row */ err = Gif_NewArray(kcolor, width + 2); err1 = Gif_NewArray(kcolor, width + 2); /* Use the same random values on each call in an attempt to minimize "jumping dithering" effects on animations */ if (!random_values) { random_values = Gif_NewArray(int32_t, N_RANDOM_VALUES); for (i = 0; i < N_RANDOM_VALUES; i++) random_values[i] = RANDOM() % (DITHER_SCALE_M1 * 2) - DITHER_SCALE_M1; } for (i = 0; i < gfi->width + 2; i++) { j = (i + gfi->left) * 3; for (k = 0; k < 3; ++k) err[i].a[k] = random_values[ (j + k) % N_RANDOM_VALUES ]; } /* err1 initialized below */ kd3_build_xradius(kd3); /* Do the image! */ for (j = 0; j < gfi->height; j++) { int d0, d1, d2, d3; /* used for error diffusion */ uint8_t *data, *new_data; int x; if (dither_direction) { x = width - 1; d0 = 0, d1 = 2, d2 = 1, d3 = 0; } else { x = 0; d0 = 2, d1 = 0, d2 = 1, d3 = 2; } data = &gfi->img[j][x]; new_data = all_new_data + j * width + x; for (i = 0; i < width + 2; i++) err1[i].a[0] = err1[i].a[1] = err1[i].a[2] = 0; /* Do a single row */ while (x >= 0 && x < width) { int e; kcolor use; /* the transparent color never gets adjusted */ if (*data == transparent) goto next; /* find desired new color */ kc_set8g(&use, old_cm->col[*data].gfc_red, old_cm->col[*data].gfc_green, old_cm->col[*data].gfc_blue); if (kd3->transform) kd3->transform(&use); /* use Floyd-Steinberg errors to adjust */ for (k = 0; k < 3; ++k) use.a[k] += (err[x+1].a[k] & ~(DITHER_ITEM2ERR-1)) / DITHER_ITEM2ERR; kc_clamp(&use); e = old_cm->col[*data].pixel; if (kc_distance(&kd3->items[e].k, &use) < kd3->xradius[e]) *new_data = e; else *new_data = kd3_closest_transformed(kd3, &use); histogram[*new_data]++; /* calculate and propagate the error between desired and selected color. Assume that, with a large scale (1024), we don't need to worry about image artifacts caused by error accumulation (the fact that the error terms might not sum to the error). */ for (k = 0; k < 3; ++k) { e = (use.a[k] - kd3->items[*new_data].k.a[k]) * DITHER_ITEM2ERR; if (e) { err [x+d0].a[k] += ((e * 7) & ~15) / 16; err1[x+d1].a[k] += ((e * 3) & ~15) / 16; err1[x+d2].a[k] += ((e * 5) & ~15) / 16; err1[x+d3].a[k] += ( e & ~15) / 16; } } next: if (dither_direction) x--, data--, new_data--; else x++, data++, new_data++; } /* Did a single row */ /* change dithering directions */ { kcolor *temp = err1; err1 = err; err = temp; dither_direction = !dither_direction; } } /* delete temporary storage */ Gif_DeleteArray(err); Gif_DeleteArray(err1); } typedef struct odselect_planitem { uint8_t plan; uint16_t frac; } odselect_planitem; static int* ordered_dither_lum; static void plan_from_cplan(uint8_t* plan, int nplan, const odselect_planitem* cp, int ncp, int whole) { int i, cfrac_subt = 0, planpos = 0, end_planpos; for (i = 0; i != ncp; ++i) { cfrac_subt += cp[i].frac; end_planpos = cfrac_subt * nplan / whole; while (planpos != end_planpos) plan[planpos++] = cp[i].plan; } assert(planpos == nplan); } static int ordered_dither_plan_compare(const void* xa, const void* xb) { const uint8_t* a = (const uint8_t*) xa; const uint8_t* b = (const uint8_t*) xb; if (ordered_dither_lum[*a] != ordered_dither_lum[*b]) return ordered_dither_lum[*a] - ordered_dither_lum[*b]; else return *a - *b; } static int kc_line_closest(const kcolor* p0, const kcolor* p1, const kcolor* ref, double* t, unsigned* dist) { kcolor p01, p0ref; unsigned den; int d; for (d = 0; d != 3; ++d) { p01.a[d] = p1->a[d] - p0->a[d]; p0ref.a[d] = ref->a[d] - p0->a[d]; } den = (unsigned) (p01.a[0]*p01.a[0] + p01.a[1]*p01.a[1] + p01.a[2]*p01.a[2]); if (den == 0) return 0; /* NB: We've run out of bits of precision. We can calculate the denominator in unsigned arithmetic, but the numerator might be negative, or it might be so large that it is unsigned. Calculate the numerator as a double. */ *t = ((double) p01.a[0]*p0ref.a[0] + p01.a[1]*p0ref.a[1] + p01.a[2]*p0ref.a[2]) / den; if (*t < 0 || *t > 1) return 0; for (d = 0; d != 3; ++d) p01.a[d] = (int) (p01.a[d] * *t) + p0->a[d]; *dist = kc_distance(&p01, ref); return 1; } static int kc_plane_closest(const kcolor* p0, const kcolor* p1, const kcolor* p2, const kcolor* ref, double* t, unsigned* dist) { kcolor p0ref, p01, p02; double n[3], pvec[3], det, qvec[3], u, v; int d; /* Calculate the non-unit normal of the plane determined by the input colors (p0-p2) */ for (d = 0; d != 3; ++d) { p0ref.a[d] = ref->a[d] - p0->a[d]; p01.a[d] = p1->a[d] - p0->a[d]; p02.a[d] = p2->a[d] - p0->a[d]; } n[0] = p01.a[1]*p02.a[2] - p01.a[2]*p02.a[1]; n[1] = p01.a[2]*p02.a[0] - p01.a[0]*p02.a[2]; n[2] = p01.a[0]*p02.a[1] - p01.a[1]*p02.a[0]; /* Moeller-Trumbore ray tracing algorithm: trace a ray from `ref` along normal `n`; convert to barycentric coordinates to see if the ray intersects with the triangle. */ pvec[0] = n[1]*p02.a[2] - n[2]*p02.a[1]; pvec[1] = n[2]*p02.a[0] - n[0]*p02.a[2]; pvec[2] = n[0]*p02.a[1] - n[1]*p02.a[0]; det = pvec[0]*p01.a[0] + pvec[1]*p01.a[1] + pvec[2]*p01.a[2]; if (det > 0.0001 && det < 0.0001) return 0; det = 1 / det; u = (p0ref.a[0]*pvec[0] + p0ref.a[1]*pvec[1] + p0ref.a[2]*pvec[2]) * det; if (u < 0 || u > 1) return 0; qvec[0] = p0ref.a[1]*p01.a[2] - p0ref.a[2]*p01.a[1]; qvec[1] = p0ref.a[2]*p01.a[0] - p0ref.a[0]*p01.a[2]; qvec[2] = p0ref.a[0]*p01.a[1] - p0ref.a[1]*p01.a[0]; v = (n[0]*qvec[0] + n[1]*qvec[1] + n[2]*qvec[2]) * det; if (v < 0 || v > 1 || u + v > 1) return 0; /* Now we know at there is a point in the triangle that is closer to `ref` than any point along its edges. Return the barycentric coordinates for that point and the distance to that point. */ t[0] = u; t[1] = v; v = (p02.a[0]*qvec[0] + p02.a[1]*qvec[1] + p02.a[2]*qvec[2]) * det; *dist = (unsigned) (v * v * (n[0]*n[0] + n[1]*n[1] + n[2]*n[2]) + 0.5); return 1; } static void limit_ordered_dither_plan(uint8_t* plan, int nplan, int nc, const kcolor* want, kd3_tree* kd3) { unsigned mindist, dist; int ncp = 0, nbestcp = 0, i, j, k; double t[2]; odselect_planitem cp[256], bestcp[16]; nc = nc <= 16 ? nc : 16; /* sort colors */ cp[0].plan = plan[0]; cp[0].frac = 1; for (ncp = i = 1; i != nplan; ++i) if (plan[i - 1] == plan[i]) ++cp[ncp - 1].frac; else { cp[ncp].plan = plan[i]; cp[ncp].frac = 1; ++ncp; } /* calculate plan */ mindist = (unsigned) -1; for (i = 0; i != ncp; ++i) { /* check for closest single color */ dist = kc_distance(&kd3->items[cp[i].plan].k, want); if (dist < mindist) { bestcp[0].plan = cp[i].plan; bestcp[0].frac = KC_WHOLE; nbestcp = 1; mindist = dist; } for (j = i + 1; nc >= 2 && j < ncp; ++j) { /* check for closest blend of two colors */ if (kc_line_closest(&kd3->items[cp[i].plan].k, &kd3->items[cp[j].plan].k, want, &t[0], &dist) && dist < mindist) { bestcp[0].plan = cp[i].plan; bestcp[1].plan = cp[j].plan; bestcp[1].frac = (int) (KC_WHOLE * t[0]); bestcp[0].frac = KC_WHOLE - bestcp[1].frac; nbestcp = 2; mindist = dist; } for (k = j + 1; nc >= 3 && k < ncp; ++k) /* check for closest blend of three colors */ if (kc_plane_closest(&kd3->items[cp[i].plan].k, &kd3->items[cp[j].plan].k, &kd3->items[cp[k].plan].k, want, &t[0], &dist) && dist < mindist) { bestcp[0].plan = cp[i].plan; bestcp[1].plan = cp[j].plan; bestcp[1].frac = (int) (KC_WHOLE * t[0]); bestcp[2].plan = cp[k].plan; bestcp[2].frac = (int) (KC_WHOLE * t[1]); bestcp[0].frac = KC_WHOLE - bestcp[1].frac - bestcp[2].frac; nbestcp = 3; mindist = dist; } } } plan_from_cplan(plan, nplan, bestcp, nbestcp, KC_WHOLE); } static void set_ordered_dither_plan(uint8_t* plan, int nplan, int nc, Gif_Color* gfc, kd3_tree* kd3) { kcolor want, cur, err; int i, d; kc_set8g(&want, gfc->gfc_red, gfc->gfc_green, gfc->gfc_blue); if (kd3->transform) kd3->transform(&want); kc_clear(&err); for (i = 0; i != nplan; ++i) { for (d = 0; d != 3; ++d) cur.a[d] = want.a[d] + err.a[d]; kc_clamp(&cur); plan[i] = kd3_closest_transformed(kd3, &cur); for (d = 0; d != 3; ++d) err.a[d] += want.a[d] - kd3->items[plan[i]].k.a[d]; } qsort(plan, nplan, 1, ordered_dither_plan_compare); if (nc < nplan && plan[0] != plan[nplan-1]) { int ncp = 1; for (i = 1; i != nplan; ++i) ncp += plan[i-1] != plan[i]; if (ncp > nc) limit_ordered_dither_plan(plan, nplan, nc, &want, kd3); } gfc->haspixel = 1; } static void pow2_ordered_dither(Gif_Image* gfi, uint8_t* all_new_data, Gif_Colormap* old_cm, kd3_tree* kd3, uint32_t* histogram, const uint8_t* matrix, uint8_t* plan) { int mws, nplans, i, x, y; for (mws = 0; (1 << mws) != matrix[0]; ++mws) /* nada */; for (nplans = 0; (1 << nplans) != matrix[2]; ++nplans) /* nada */; for (y = 0; y != gfi->height; ++y) { uint8_t *data, *new_data, *thisplan; data = gfi->img[y]; new_data = all_new_data + y * gfi->width; for (x = 0; x != gfi->width; ++x) /* the transparent color never gets adjusted */ if (data[x] != gfi->transparent) { thisplan = &plan[data[x] << nplans]; if (!old_cm->col[data[x]].haspixel) set_ordered_dither_plan(thisplan, 1 << nplans, matrix[3], &old_cm->col[data[x]], kd3); i = matrix[4 + ((x + gfi->left) & (matrix[0] - 1)) + (((y + gfi->top) & (matrix[1] - 1)) << mws)]; new_data[x] = thisplan[i]; histogram[new_data[x]]++; } } } static void colormap_image_ordered(Gif_Image* gfi, uint8_t* all_new_data, Gif_Colormap* old_cm, kd3_tree* kd3, uint32_t* histogram, const uint8_t* matrix) { int mw = matrix[0], mh = matrix[1], nplan = matrix[2]; uint8_t* plan = Gif_NewArray(uint8_t, nplan * old_cm->ncol); int i, x, y; /* Written with reference to Joel Ylilouma's versions. */ /* Initialize colors */ for (i = 0; i != old_cm->ncol; ++i) old_cm->col[i].haspixel = 0; /* Initialize luminances, create luminance sorter */ ordered_dither_lum = Gif_NewArray(int, kd3->nitems); for (i = 0; i != kd3->nitems; ++i) ordered_dither_lum[i] = kc_luminance(&kd3->items[i].k); /* Do the image! */ if ((mw & (mw - 1)) == 0 && (mh & (mh - 1)) == 0 && (nplan & (nplan - 1)) == 0) pow2_ordered_dither(gfi, all_new_data, old_cm, kd3, histogram, matrix, plan); else for (y = 0; y != gfi->height; ++y) { uint8_t *data, *new_data, *thisplan; data = gfi->img[y]; new_data = all_new_data + y * gfi->width; for (x = 0; x != gfi->width; ++x) /* the transparent color never gets adjusted */ if (data[x] != gfi->transparent) { thisplan = &plan[nplan * data[x]]; if (!old_cm->col[data[x]].haspixel) set_ordered_dither_plan(thisplan, nplan, matrix[3], &old_cm->col[data[x]], kd3); i = matrix[4 + (x + gfi->left) % mw + ((y + gfi->top) % mh) * mw]; new_data[x] = thisplan[i]; histogram[new_data[x]]++; } } /* delete temporary storage */ Gif_DeleteArray(ordered_dither_lum); Gif_DeleteArray(plan); } static void dither(Gif_Image* gfi, uint8_t* new_data, Gif_Colormap* old_cm, kd3_tree* kd3, uint32_t* histogram, Gt_OutputData* od) { if (od->dither_type == dither_default || od->dither_type == dither_floyd_steinberg) colormap_image_floyd_steinberg(gfi, new_data, old_cm, kd3, histogram); else if (od->dither_type == dither_ordered || od->dither_type == dither_ordered_new) colormap_image_ordered(gfi, new_data, old_cm, kd3, histogram, od->dither_data); else colormap_image_posterize(gfi, new_data, old_cm, kd3, histogram); } /* return value 1 means run the dither again */ static int try_assign_transparency(Gif_Image *gfi, Gif_Colormap *old_cm, uint8_t *new_data, Gif_Colormap *new_cm, int *new_ncol, kd3_tree* kd3, uint32_t *histogram) { uint32_t min_used; int i, j; int transparent = gfi->transparent; int new_transparent = -1; Gif_Color transp_value; if (transparent < 0) return 0; if (old_cm) transp_value = old_cm->col[transparent]; /* look for an unused pixel in the existing colormap; prefer the same color we had */ for (i = 0; i < *new_ncol; i++) if (histogram[i] == 0 && GIF_COLOREQ(&transp_value, &new_cm->col[i])) { new_transparent = i; goto found; } for (i = 0; i < *new_ncol; i++) if (histogram[i] == 0) { new_transparent = i; goto found; } /* try to expand the colormap */ if (*new_ncol < 256) { assert(*new_ncol < new_cm->capacity); new_transparent = *new_ncol; new_cm->col[new_transparent] = transp_value; (*new_ncol)++; goto found; } /* not found: mark the least-frequently-used color as the new transparent color and return 1 (meaning 'dither again') */ assert(*new_ncol == 256); min_used = 0xFFFFFFFFU; for (i = 0; i < 256; i++) if (histogram[i] < min_used) { new_transparent = i; min_used = histogram[i]; } kd3_disable(kd3, new_transparent); /* mark it as unusable */ return 1; found: for (j = 0; j < gfi->height; j++) { uint8_t *data = gfi->img[j]; for (i = 0; i < gfi->width; i++, data++, new_data++) if (*data == transparent) *new_data = new_transparent; } gfi->transparent = new_transparent; return 0; } void colormap_stream(Gif_Stream* gfs, Gif_Colormap* new_cm, Gt_OutputData* od) { kd3_tree kd3; int background_transparent = gfs->images[0]->transparent >= 0; Gif_Color *new_col = new_cm->col; int new_ncol = new_cm->ncol, new_gray; int imagei, j; int compress_new_cm = 1; /* make sure colormap has enough space */ if (new_cm->capacity < 256) { Gif_Color *x = Gif_NewArray(Gif_Color, 256); memcpy(x, new_col, sizeof(Gif_Color) * new_ncol); Gif_DeleteArray(new_col); new_cm->col = new_col = x; new_cm->capacity = 256; } assert(new_cm->capacity >= 256); /* new_col[j].pixel == number of pixels with color j in the new image. */ for (j = 0; j < 256; j++) new_col[j].pixel = 0; /* initialize kd3 tree */ new_gray = 1; for (j = 0; new_gray && j < new_cm->ncol; ++j) if (new_col[j].gfc_red != new_col[j].gfc_green || new_col[j].gfc_red != new_col[j].gfc_blue) new_gray = 0; if (new_gray) kd3_init(&kd3, kc_luminance_transform); else kd3_init(&kd3, NULL); for (j = 0; j < new_cm->ncol; ++j) kd3_add8g(&kd3, new_col[j].gfc_red, new_col[j].gfc_green, new_col[j].gfc_blue); kd3_build(&kd3); for (imagei = 0; imagei < gfs->nimages; imagei++) { Gif_Image *gfi = gfs->images[imagei]; Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global; int only_compressed = (gfi->img == 0); if (gfcm) { /* If there was an old colormap, change the image data */ uint8_t *new_data = Gif_NewArray(uint8_t, gfi->width * gfi->height); uint32_t histogram[256]; unmark_colors(new_cm); unmark_colors(gfcm); if (only_compressed) Gif_UncompressImage(gfi); kd3_enable_all(&kd3); do { for (j = 0; j < 256; j++) histogram[j] = 0; dither(gfi, new_data, gfcm, &kd3, histogram, od); } while (try_assign_transparency(gfi, gfcm, new_data, new_cm, &new_ncol, &kd3, histogram)); Gif_ReleaseUncompressedImage(gfi); /* version 1.28 bug fix: release any compressed version or it'll cause bad images */ Gif_ReleaseCompressedImage(gfi); Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0); if (only_compressed) { Gif_FullCompressImage(gfs, gfi, &gif_write_info); Gif_ReleaseUncompressedImage(gfi); } /* update count of used colors */ for (j = 0; j < 256; j++) new_col[j].pixel += histogram[j]; if (gfi->transparent >= 0) /* we don't have data on the number of used colors for transparency so fudge it. */ new_col[gfi->transparent].pixel += gfi->width * gfi->height / 8; } else { /* Can't compress new_cm afterwards if we didn't actively change colors over */ compress_new_cm = 0; } if (gfi->local) { Gif_DeleteColormap(gfi->local); gfi->local = 0; } } /* Set new_cm->ncol from new_ncol. We didn't update new_cm->ncol before so the closest-color algorithms wouldn't see any new transparent colors. That way added transparent colors were only used for transparency. */ new_cm->ncol = new_ncol; /* change the background. I hate the background by now */ if (background_transparent) gfs->background = gfs->images[0]->transparent; else if (gfs->global && gfs->background < gfs->global->ncol) { Gif_Color *c = &gfs->global->col[gfs->background]; gfs->background = kd3_closest8(&kd3, c->gfc_red, c->gfc_green, c->gfc_blue); new_col[gfs->background].pixel++; } Gif_DeleteColormap(gfs->global); kd3_cleanup(&kd3); /* We may have used only a subset of the colors in new_cm. We try to store only that subset, just as if we'd piped the output of 'gifsicle --use-colormap=X' through 'gifsicle' another time. */ gfs->global = Gif_CopyColormap(new_cm); for (j = 0; j < new_cm->ncol; ++j) gfs->global->col[j].haspixel = 0; if (compress_new_cm) { /* only bother to recompress if we'll get anything out of it */ compress_new_cm = 0; for (j = 0; j < new_cm->ncol - 1; j++) if (new_col[j].pixel == 0 || new_col[j].pixel < new_col[j+1].pixel) { compress_new_cm = 1; break; } } if (compress_new_cm) { int map[256]; /* Gif_CopyColormap copies the 'pixel' values as well */ new_col = gfs->global->col; for (j = 0; j < new_cm->ncol; j++) new_col[j].haspixel = j; /* sort based on popularity */ qsort(new_col, new_cm->ncol, sizeof(Gif_Color), popularity_sort_compare); /* set up the map and reduce the number of colors */ for (j = 0; j < new_cm->ncol; j++) map[ new_col[j].haspixel ] = j; for (j = 0; j < new_cm->ncol; j++) if (!new_col[j].pixel) { gfs->global->ncol = j; break; } /* map the image data, transparencies, and background */ gfs->background = map[gfs->background]; for (imagei = 0; imagei < gfs->nimages; imagei++) { Gif_Image *gfi = gfs->images[imagei]; int only_compressed = (gfi->img == 0); uint32_t size; uint8_t *data; if (only_compressed) Gif_UncompressImage(gfi); data = gfi->image_data; for (size = gfi->width * gfi->height; size > 0; size--, data++) *data = map[*data]; if (gfi->transparent >= 0) gfi->transparent = map[gfi->transparent]; if (only_compressed) { Gif_FullCompressImage(gfs, gfi, &gif_write_info); Gif_ReleaseUncompressedImage(gfi); } } } } /* Halftone algorithms */ static const uint8_t dither_matrix_o3x3[4 + 3*3] = { 3, 3, 9, 9, 2, 6, 3, 5, 0, 8, 1, 7, 4 }; static const uint8_t dither_matrix_o4x4[4 + 4*4] = { 4, 4, 16, 16, 0, 8, 3, 10, 12, 4, 14, 6, 2, 11, 1, 9, 15, 7, 13, 5 }; static const uint8_t dither_matrix_o8x8[4 + 8*8] = { 8, 8, 64, 64, 0, 48, 12, 60, 3, 51, 15, 63, 32, 16, 44, 28, 35, 19, 47, 31, 8, 56, 4, 52, 11, 59, 7, 55, 40, 24, 36, 20, 43, 27, 39, 23, 2, 50, 14, 62, 1, 49, 13, 61, 34, 18, 46, 30, 33, 17, 45, 29, 10, 58, 6, 54, 9, 57, 5, 53, 42, 26, 38, 22, 41, 25, 37, 21 }; static const uint8_t dither_matrix_ro64x64[4 + 64*64] = { 64, 64, 16, 16, 6, 15, 2, 15, 2, 14, 1, 13, 2, 14, 5, 13, 0, 14, 0, 9, 6, 10, 7, 13, 6, 13, 3, 10, 5, 15, 4, 11, 0, 11, 6, 10, 7, 12, 7, 13, 0, 9, 6, 15, 6, 10, 0, 15, 1, 15, 0, 8, 0, 15, 6, 15, 7, 15, 7, 9, 1, 15, 3, 8, 1, 8, 0, 14, 9, 3, 10, 5, 10, 6, 10, 5, 9, 6, 9, 2, 9, 4, 13, 4, 13, 3, 8, 3, 10, 1, 13, 6, 11, 1, 12, 3, 14, 5, 15, 3, 8, 3, 8, 3, 12, 4, 11, 3, 13, 3, 8, 4, 9, 6, 12, 4, 11, 6, 11, 3, 10, 0, 12, 1, 11, 7, 12, 4, 12, 4, 11, 5, 1, 14, 0, 10, 2, 9, 2, 11, 1, 8, 1, 8, 3, 9, 4, 15, 7, 13, 7, 14, 7, 14, 0, 10, 0, 14, 7, 9, 0, 11, 1, 15, 0, 11, 0, 11, 3, 15, 7, 14, 6, 10, 5, 8, 0, 11, 0, 8, 7, 11, 0, 15, 0, 12, 1, 13, 6, 9, 0, 15, 4, 9, 1, 8, 10, 5, 15, 6, 13, 6, 14, 7, 14, 4, 12, 5, 15, 6, 10, 2, 11, 3, 10, 3, 11, 3, 13, 6, 11, 5, 14, 3, 14, 6, 8, 5, 14, 5, 14, 7, 10, 7, 11, 3, 13, 3, 13, 2, 14, 4, 15, 5, 15, 3, 8, 4, 11, 4, 9, 5, 12, 3, 8, 5, 15, 2, 13, 5, 3, 10, 2, 9, 5, 15, 4, 9, 0, 11, 7, 11, 0, 14, 5, 11, 5, 14, 7, 15, 6, 9, 0, 9, 0, 8, 4, 14, 6, 12, 0, 11, 4, 15, 5, 8, 6, 10, 6, 11, 6, 10, 3, 12, 5, 9, 6, 9, 5, 12, 6, 12, 7, 14, 0, 14, 2, 15, 5, 8, 2, 10, 3, 9, 14, 7, 14, 7, 8, 1, 12, 2, 14, 4, 15, 3, 11, 5, 12, 2, 8, 0, 10, 3, 12, 1, 13, 5, 14, 5, 11, 0, 11, 3, 13, 7, 8, 1, 12, 3, 15, 3, 14, 2, 15, 3, 11, 6, 15, 1, 12, 1, 9, 3, 9, 3, 11, 3, 11, 7, 11, 5, 12, 0, 14, 6, 13, 6, 5, 10, 6, 12, 3, 15, 3, 8, 7, 10, 0, 15, 7, 10, 5, 8, 1, 14, 5, 10, 7, 14, 2, 14, 0, 14, 1, 8, 3, 8, 5, 10, 5, 15, 0, 8, 6, 14, 0, 8, 2, 15, 4, 11, 6, 10, 0, 8, 5, 9, 4, 14, 1, 15, 3, 10, 1, 15, 0, 15, 5, 8, 7, 13, 15, 3, 8, 0, 9, 6, 12, 6, 15, 0, 11, 4, 14, 3, 15, 3, 10, 5, 12, 3, 10, 3, 9, 6, 9, 5, 13, 5, 15, 6, 14, 0, 9, 0, 12, 4, 11, 3, 15, 4, 11, 6, 15, 2, 15, 3, 14, 4, 13, 2, 11, 1, 8, 5, 12, 7, 9, 4, 8, 5, 12, 2, 11, 0, 0, 13, 5, 11, 5, 14, 5, 15, 7, 9, 5, 8, 2, 10, 3, 15, 6, 9, 3, 12, 5, 11, 6, 14, 3, 13, 6, 13, 0, 9, 1, 11, 3, 8, 3, 9, 4, 9, 6, 14, 7, 8, 6, 12, 7, 13, 6, 9, 5, 13, 3, 15, 5, 14, 3, 15, 4, 12, 4, 12, 2, 13, 0, 15, 10, 7, 14, 1, 8, 2, 10, 2, 12, 0, 13, 1, 13, 5, 11, 6, 12, 3, 9, 6, 15, 1, 9, 1, 10, 6, 10, 3, 15, 6, 15, 5, 15, 7, 12, 6, 12, 0, 9, 3, 12, 3, 11, 3, 8, 3, 13, 2, 9, 3, 9, 6, 10, 2, 11, 6, 9, 0, 9, 1, 9, 6, 10, 4, 3, 10, 4, 9, 4, 9, 6, 13, 3, 15, 0, 8, 4, 10, 0, 14, 5, 15, 7, 15, 2, 12, 7, 10, 5, 15, 7, 8, 0, 9, 0, 8, 6, 14, 4, 15, 2, 15, 1, 15, 0, 9, 5, 14, 0, 12, 7, 10, 6, 8, 6, 11, 0, 13, 7, 14, 1, 13, 2, 10, 5, 9, 0, 14, 14, 6, 13, 1, 12, 3, 8, 3, 9, 6, 12, 4, 15, 2, 8, 5, 9, 1, 10, 1, 8, 5, 15, 0, 8, 2, 12, 3, 12, 5, 12, 5, 11, 2, 10, 2, 8, 5, 10, 5, 12, 4, 9, 3, 8, 4, 13, 1, 15, 0, 12, 3, 8, 4, 10, 3, 9, 5, 13, 5, 13, 3, 11, 4, 4, 12, 3, 10, 6, 9, 0, 14, 0, 8, 1, 9, 1, 9, 6, 15, 0, 10, 2, 9, 6, 10, 7, 10, 2, 14, 4, 8, 0, 13, 4, 8, 1, 11, 6, 14, 7, 14, 0, 8, 4, 14, 7, 14, 4, 9, 2, 12, 0, 12, 3, 8, 5, 9, 6, 14, 0, 9, 2, 14, 5, 10, 1, 15, 10, 2, 15, 6, 14, 3, 11, 6, 15, 4, 15, 4, 13, 5, 11, 3, 12, 4, 14, 5, 12, 0, 13, 3, 8, 6, 15, 2, 10, 6, 13, 2, 12, 6, 8, 3, 10, 3, 14, 5, 8, 0, 10, 3, 13, 2, 9, 6, 10, 6, 15, 4, 13, 2, 8, 3, 14, 6, 11, 7, 13, 0, 10, 5, 2, 13, 1, 9, 5, 10, 3, 15, 6, 10, 0, 15, 4, 15, 4, 15, 6, 9, 0, 14, 1, 9, 6, 12, 0, 11, 5, 9, 0, 14, 5, 14, 6, 9, 3, 11, 7, 11, 1, 15, 1, 9, 3, 13, 5, 12, 0, 9, 2, 9, 6, 13, 2, 9, 6, 13, 7, 11, 7, 8, 0, 13, 3, 9, 9, 6, 13, 6, 13, 0, 8, 5, 14, 2, 11, 7, 11, 2, 11, 2, 12, 3, 11, 4, 13, 4, 10, 3, 15, 5, 13, 0, 11, 6, 10, 0, 13, 3, 15, 7, 14, 3, 8, 4, 12, 6, 9, 6, 10, 3, 14, 5, 13, 5, 11, 3, 13, 6, 8, 2, 14, 3, 15, 3, 11, 4, 12, 6, 4, 10, 7, 11, 1, 10, 2, 14, 7, 14, 0, 14, 4, 15, 0, 8, 0, 15, 5, 15, 7, 11, 7, 14, 6, 12, 0, 8, 1, 15, 1, 14, 2, 8, 0, 11, 4, 8, 5, 11, 1, 15, 0, 12, 7, 14, 0, 11, 4, 8, 2, 8, 0, 14, 2, 14, 4, 9, 4, 10, 7, 15, 5, 14, 14, 0, 13, 2, 14, 5, 11, 5, 10, 2, 10, 6, 11, 3, 12, 5, 11, 7, 11, 1, 12, 3, 11, 3, 9, 3, 12, 4, 11, 6, 9, 5, 14, 5, 12, 7, 14, 2, 12, 1, 8, 4, 11, 7, 10, 3, 14, 4, 14, 0, 14, 5, 11, 7, 11, 5, 15, 1, 14, 0, 10, 3, 10, 0, 5, 12, 7, 10, 7, 11, 0, 14, 5, 14, 1, 14, 3, 8, 0, 15, 0, 9, 5, 9, 1, 8, 6, 15, 6, 15, 7, 13, 7, 9, 4, 11, 0, 10, 6, 10, 7, 12, 7, 15, 0, 9, 7, 14, 2, 11, 0, 12, 7, 11, 7, 13, 0, 9, 6, 14, 2, 11, 1, 15, 0, 8, 0, 10, 10, 3, 15, 3, 15, 3, 8, 4, 11, 3, 11, 6, 15, 6, 11, 5, 12, 5, 13, 0, 15, 4, 8, 1, 11, 3, 10, 3, 15, 3, 14, 1, 14, 6, 13, 3, 11, 3, 11, 3, 13, 6, 8, 3, 12, 5, 8, 4, 13, 3, 8, 2, 13, 4, 8, 3, 14, 7, 8, 5, 14, 4, 15, 5, 3, 9, 0, 10, 0, 12, 3, 11, 7, 10, 6, 8, 7, 12, 0, 11, 1, 8, 5, 12, 5, 12, 7, 11, 2, 14, 0, 10, 0, 12, 0, 15, 2, 9, 5, 9, 0, 15, 4, 14, 6, 9, 7, 11, 6, 10, 0, 9, 1, 9, 0, 14, 4, 12, 5, 9, 6, 10, 4, 11, 6, 12, 5, 12, 12, 6, 15, 4, 8, 4, 15, 7, 15, 3, 14, 0, 9, 3, 13, 5, 14, 5, 11, 1, 9, 0, 15, 3, 8, 7, 12, 7, 8, 5, 9, 4, 12, 6, 12, 1, 10, 6, 9, 0, 15, 3, 14, 0, 15, 3, 13, 5, 15, 5, 9, 6, 10, 0, 14, 0, 13, 1, 15, 1, 8, 3, 8, 1, 2, 8, 7, 15, 0, 11, 1, 12, 1, 12, 0, 15, 0, 11, 2, 13, 1, 10, 5, 8, 7, 13, 6, 10, 0, 11, 4, 12, 7, 10, 1, 9, 1, 9, 0, 12, 2, 11, 7, 15, 1, 11, 0, 9, 2, 8, 4, 12, 2, 12, 6, 14, 4, 14, 3, 13, 3, 15, 1, 14, 4, 15, 6, 12, 13, 6, 11, 3, 12, 4, 8, 4, 9, 4, 9, 5, 12, 6, 10, 5, 14, 7, 14, 3, 10, 2, 13, 3, 14, 5, 8, 2, 13, 1, 15, 6, 15, 4, 8, 4, 15, 5, 10, 1, 14, 5, 12, 4, 13, 5, 11, 1, 9, 5, 9, 3, 9, 0, 10, 7, 10, 7, 11, 6, 10, 3, 9, 0, 3, 15, 5, 8, 1, 9, 5, 8, 4, 13, 6, 8, 4, 15, 6, 10, 6, 14, 7, 11, 0, 9, 1, 12, 0, 8, 6, 12, 6, 10, 3, 12, 7, 13, 7, 11, 3, 8, 0, 13, 7, 12, 0, 15, 4, 12, 5, 8, 4, 15, 5, 10, 0, 15, 3, 15, 1, 8, 1, 15, 4, 14, 6, 15, 10, 6, 14, 0, 13, 4, 13, 1, 9, 1, 13, 3, 11, 2, 12, 1, 8, 3, 12, 3, 14, 6, 8, 4, 15, 4, 8, 3, 15, 1, 9, 6, 11, 2, 14, 3, 13, 7, 10, 4, 10, 3, 8, 7, 11, 2, 12, 1, 11, 1, 14, 3, 9, 6, 9, 7, 13, 5, 11, 7, 10, 2, 9, 3, 1, 9, 0, 14, 7, 12, 7, 14, 5, 9, 6, 10, 6, 14, 6, 15, 1, 14, 7, 10, 3, 12, 0, 14, 5, 9, 6, 8, 1, 12, 0, 13, 2, 8, 4, 9, 6, 15, 0, 14, 4, 10, 7, 11, 5, 14, 2, 8, 4, 15, 3, 8, 7, 13, 1, 9, 0, 15, 0, 14, 5, 14, 0, 14, 15, 4, 10, 6, 11, 1, 10, 2, 14, 3, 15, 1, 10, 3, 10, 3, 8, 4, 12, 3, 10, 6, 9, 6, 14, 2, 12, 3, 11, 4, 9, 6, 12, 5, 15, 0, 10, 3, 8, 4, 14, 1, 14, 3, 11, 2, 12, 7, 11, 2, 12, 6, 10, 1, 13, 4, 11, 4, 10, 5, 11, 2, 11, 7, 0, 8, 1, 11, 4, 8, 4, 10, 6, 11, 3, 10, 6, 10, 6, 8, 1, 11, 1, 15, 7, 15, 6, 9, 1, 9, 7, 8, 0, 14, 5, 12, 3, 13, 4, 12, 0, 15, 5, 12, 1, 12, 7, 9, 6, 8, 3, 15, 0, 13, 6, 15, 7, 15, 7, 13, 2, 15, 1, 14, 2, 15, 0, 8, 12, 5, 13, 5, 15, 1, 12, 1, 15, 1, 14, 6, 14, 2, 14, 2, 14, 6, 11, 6, 11, 3, 12, 2, 13, 6, 15, 3, 9, 5, 8, 2, 8, 5, 9, 1, 9, 4, 9, 2, 8, 4, 13, 1, 13, 0, 11, 6, 11, 6, 9, 2, 11, 3, 10, 1, 10, 6, 9, 6, 11, 7, 15, 5, 5, 12, 0, 9, 5, 8, 5, 9, 0, 10, 2, 13, 4, 8, 5, 14, 2, 9, 2, 15, 4, 8, 2, 8, 0, 12, 6, 12, 0, 10, 5, 15, 4, 9, 3, 13, 0, 9, 4, 15, 1, 14, 1, 9, 0, 9, 2, 14, 6, 12, 0, 15, 7, 9, 2, 9, 0, 15, 6, 10, 3, 15, 3, 13, 9, 1, 15, 5, 12, 3, 14, 0, 15, 7, 8, 5, 14, 1, 11, 1, 13, 6, 10, 7, 13, 0, 14, 5, 10, 7, 11, 3, 15, 6, 11, 1, 12, 2, 8, 4, 13, 5, 10, 2, 10, 6, 13, 5, 13, 4, 10, 5, 9, 3, 8, 4, 12, 1, 12, 5, 11, 6, 14, 3, 11, 7, 11, 7, 2, 11, 4, 12, 7, 8, 3, 15, 3, 11, 4, 11, 7, 10, 1, 10, 2, 10, 0, 11, 4, 12, 0, 10, 1, 8, 7, 11, 1, 10, 1, 15, 7, 10, 2, 11, 1, 9, 6, 14, 2, 11, 1, 14, 4, 12, 2, 13, 1, 9, 5, 8, 7, 11, 7, 10, 7, 15, 4, 13, 3, 10, 1, 11, 13, 5, 8, 0, 15, 3, 11, 6, 12, 7, 15, 3, 15, 1, 15, 4, 14, 5, 13, 6, 8, 1, 15, 6, 13, 5, 12, 2, 15, 4, 9, 4, 15, 3, 14, 6, 14, 5, 9, 3, 12, 6, 11, 5, 8, 2, 9, 5, 12, 5, 15, 1, 13, 3, 14, 2, 8, 0, 8, 0, 12, 7, 15, 5, 0, 14, 1, 8, 2, 8, 2, 15, 2, 9, 6, 12, 0, 12, 7, 12, 7, 13, 0, 15, 6, 14, 5, 11, 1, 12, 5, 8, 5, 8, 1, 14, 0, 10, 4, 12, 6, 9, 6, 8, 0, 9, 0, 15, 4, 15, 5, 13, 1, 15, 5, 12, 7, 10, 6, 14, 4, 9, 6, 15, 0, 15, 7, 13, 10, 4, 13, 5, 13, 5, 11, 5, 12, 5, 9, 3, 9, 4, 8, 3, 9, 3, 10, 6, 11, 1, 15, 2, 8, 5, 15, 1, 13, 2, 11, 6, 14, 6, 8, 2, 15, 3, 14, 3, 13, 6, 9, 6, 9, 0, 10, 2, 10, 7, 11, 1, 15, 3, 9, 3, 13, 3, 10, 3, 9, 4, 10, 1, 4, 11, 7, 10, 2, 14, 4, 15, 3, 15, 2, 15, 7, 10, 2, 14, 1, 8, 0, 15, 2, 8, 1, 12, 2, 13, 1, 8, 7, 12, 6, 11, 1, 10, 4, 11, 2, 15, 0, 13, 0, 12, 7, 11, 5, 12, 7, 8, 6, 15, 4, 12, 7, 10, 6, 10, 0, 10, 0, 11, 4, 12, 7, 10, 13, 2, 14, 2, 10, 7, 11, 1, 11, 7, 11, 7, 12, 3, 11, 7, 13, 4, 11, 6, 12, 5, 11, 6, 10, 7, 13, 4, 11, 3, 15, 3, 14, 4, 15, 3, 8, 5, 10, 7, 10, 6, 15, 3, 9, 3, 15, 1, 11, 3, 9, 0, 15, 1, 15, 3, 15, 4, 13, 5, 8, 3, 15, 3, 3, 9, 1, 12, 4, 14, 0, 11, 7, 15, 1, 11, 3, 14, 0, 11, 5, 10, 2, 10, 2, 8, 6, 14, 7, 11, 0, 10, 7, 14, 7, 15, 6, 9, 6, 9, 1, 12, 7, 9, 4, 8, 7, 13, 0, 13, 6, 12, 6, 8, 1, 9, 1, 15, 4, 12, 0, 12, 4, 10, 0, 13, 0, 12, 13, 5, 10, 6, 9, 1, 13, 6, 11, 0, 14, 7, 11, 7, 14, 5, 15, 2, 13, 5, 15, 4, 9, 2, 13, 3, 14, 7, 10, 3, 10, 3, 12, 3, 12, 2, 8, 5, 15, 3, 13, 3, 11, 3, 10, 4, 9, 3, 15, 1, 14, 4, 11, 6, 10, 3, 8, 4, 13, 0, 10, 4, 8, 5, 5, 8, 3, 13, 4, 14, 1, 13, 7, 9, 2, 14, 4, 14, 4, 12, 7, 10, 6, 10, 5, 12, 2, 11, 6, 12, 7, 13, 4, 11, 2, 11, 3, 8, 5, 15, 2, 10, 1, 9, 2, 12, 0, 12, 0, 10, 1, 12, 0, 9, 7, 10, 0, 15, 4, 9, 0, 8, 1, 14, 4, 14, 4, 13, 12, 2, 8, 6, 10, 0, 8, 5, 13, 3, 8, 5, 10, 3, 11, 2, 15, 0, 13, 3, 8, 2, 15, 6, 9, 1, 8, 3, 14, 1, 15, 5, 14, 7, 8, 0, 12, 6, 15, 5, 8, 5, 9, 4, 15, 5, 8, 5, 15, 4, 12, 3, 9, 6, 12, 3, 13, 5, 11, 7, 10, 1, 8, 3, 4, 15, 2, 11, 2, 10, 6, 11, 3, 14, 7, 15, 0, 10, 0, 14, 3, 12, 4, 8, 7, 9, 3, 11, 0, 13, 2, 12, 2, 13, 5, 8, 5, 8, 2, 11, 4, 12, 2, 10, 7, 8, 6, 10, 7, 12, 7, 11, 0, 15, 7, 8, 7, 15, 0, 9, 2, 12, 6, 13, 0, 9, 4, 9, 8, 3, 12, 5, 15, 5, 13, 1, 8, 7, 8, 3, 12, 5, 9, 5, 9, 6, 14, 1, 12, 3, 15, 7, 10, 7, 8, 5, 8, 5, 15, 0, 13, 1, 14, 7, 9, 1, 14, 7, 13, 2, 12, 3, 8, 1, 13, 3, 8, 4, 12, 0, 11, 3, 12, 5, 11, 5, 9, 3, 12, 6, 14, 2, 5, 13, 2, 8, 6, 12, 7, 10, 5, 14, 4, 11, 2, 11, 2, 13, 2, 13, 5, 10, 5, 9, 0, 10, 7, 13, 4, 15, 2, 9, 1, 9, 5, 9, 6, 10, 4, 12, 5, 12, 4, 10, 3, 14, 3, 15, 1, 8, 4, 12, 5, 8, 5, 14, 7, 11, 7, 15, 5, 11, 2, 13, 1, 9, 10, 0, 13, 6, 10, 2, 15, 3, 8, 1, 12, 2, 14, 6, 8, 5, 10, 7, 13, 1, 13, 1, 12, 7, 9, 1, 9, 2, 12, 5, 12, 4, 12, 3, 12, 2, 9, 0, 8, 1, 15, 1, 10, 7, 10, 6, 12, 4, 11, 1, 14, 2, 11, 0, 14, 1, 9, 2, 12, 2, 8, 5, 13, 5, 6, 10, 7, 11, 0, 9, 3, 9, 5, 11, 0, 8, 0, 13, 2, 13, 4, 13, 5, 9, 4, 8, 2, 8, 0, 10, 0, 14, 6, 9, 6, 9, 4, 14, 7, 9, 0, 11, 7, 10, 7, 11, 7, 14, 4, 14, 5, 15, 4, 8, 4, 11, 5, 14, 0, 8, 1, 14, 7, 14, 2, 11, 7, 13, 12, 3, 13, 3, 14, 5, 15, 6, 12, 0, 15, 4, 11, 5, 9, 5, 9, 2, 14, 1, 12, 1, 13, 5, 15, 4, 11, 7, 12, 1, 13, 2, 8, 1, 12, 0, 15, 6, 14, 2, 14, 3, 10, 1, 11, 3, 11, 0, 12, 1, 15, 2, 11, 1, 12, 4, 9, 4, 10, 2, 13, 6, 10, 2, 2, 8, 4, 8, 4, 9, 0, 9, 2, 15, 5, 9, 6, 11, 7, 14, 0, 9, 2, 12, 2, 8, 0, 10, 1, 9, 7, 8, 2, 9, 1, 11, 2, 11, 2, 8, 1, 9, 1, 11, 7, 13, 6, 11, 1, 11, 0, 9, 2, 13, 4, 14, 1, 15, 2, 8, 7, 15, 0, 13, 6, 9, 4, 13, 13, 5, 13, 1, 14, 0, 12, 6, 9, 6, 12, 0, 13, 0, 11, 3, 13, 6, 11, 7, 12, 5, 14, 6, 14, 5, 15, 3, 13, 6, 14, 7, 15, 6, 15, 5, 13, 4, 14, 5, 8, 2, 14, 3, 14, 6, 14, 5, 10, 6, 10, 2, 9, 5, 15, 5, 11, 1, 8, 5, 13, 3, 11, 2, 2, 8, 6, 8, 0, 9, 1, 15, 0, 11, 4, 15, 7, 8, 4, 8, 1, 13, 7, 11, 1, 13, 5, 15, 1, 15, 2, 9, 0, 13, 5, 12, 3, 12, 2, 8, 1, 10, 1, 13, 5, 15, 3, 9, 3, 9, 2, 12, 5, 14, 6, 13, 1, 9, 6, 9, 1, 8, 4, 15, 7, 10, 7, 15, 14, 5, 14, 3, 12, 4, 10, 7, 12, 7, 8, 2, 12, 1, 13, 2, 11, 4, 13, 3, 8, 5, 8, 1, 10, 7, 12, 6, 9, 5, 8, 0, 8, 7, 14, 5, 13, 6, 8, 4, 8, 2, 12, 6, 13, 5, 8, 7, 8, 3, 10, 3, 13, 4, 12, 1, 13, 4, 11, 1, 14, 3, 8, 1, 2, 13, 6, 10, 0, 9, 1, 15, 0, 12, 4, 11, 2, 9, 0, 9, 0, 13, 1, 8, 0, 11, 5, 9, 6, 13, 2, 15, 2, 12, 7, 12, 6, 15, 2, 14, 1, 13, 1, 14, 4, 11, 2, 14, 1, 9, 0, 15, 1, 12, 5, 14, 6, 13, 2, 15, 3, 9, 1, 15, 7, 8, 1, 14, 11, 7, 13, 3, 15, 6, 8, 4, 8, 4, 14, 2, 14, 6, 13, 6, 11, 4, 14, 4, 15, 4, 14, 3, 10, 2, 10, 5, 9, 6, 9, 3, 9, 1, 11, 6, 9, 4, 8, 4, 15, 0, 8, 4, 13, 4, 9, 4, 9, 5, 9, 3, 10, 2, 9, 5, 12, 6, 8, 4, 12, 0, 11, 4, 4, 10, 4, 13, 1, 12, 7, 8, 0, 13, 4, 12, 2, 13, 1, 14, 7, 15, 3, 8, 7, 12, 3, 10, 4, 9, 4, 11, 7, 8, 2, 11, 2, 10, 0, 12, 1, 14, 6, 14, 7, 13, 7, 11, 3, 10, 0, 10, 4, 9, 3, 13, 0, 13, 7, 8, 7, 9, 7, 11, 2, 8, 1, 14, 15, 0, 11, 1, 9, 6, 15, 3, 10, 7, 9, 1, 9, 7, 10, 7, 10, 1, 12, 5, 8, 1, 15, 7, 13, 3, 12, 2, 13, 2, 14, 7, 14, 5, 10, 4, 8, 4, 11, 1, 10, 3, 14, 0, 14, 6, 14, 5, 13, 2, 8, 7, 10, 7, 13, 2, 14, 2, 13, 2, 14, 5, 11, 6, 7, 11, 5, 13, 1, 11, 7, 8, 5, 14, 4, 13, 1, 14, 5, 10, 2, 15, 4, 13, 7, 11, 7, 10, 1, 8, 5, 9, 4, 12, 7, 10, 1, 13, 7, 13, 7, 11, 0, 14, 5, 14, 2, 14, 4, 12, 4, 13, 7, 13, 7, 8, 2, 14, 2, 13, 5, 9, 5, 9, 2, 8, 1, 10, 12, 0, 8, 2, 13, 4, 12, 1, 11, 1, 10, 1, 10, 4, 12, 2, 11, 5, 8, 1, 15, 3, 14, 1, 13, 4, 14, 2, 9, 2, 12, 2, 8, 4, 8, 2, 12, 3, 10, 6, 11, 0, 11, 7, 10, 1, 9, 2, 10, 0, 13, 1, 11, 7, 10, 6, 13, 1, 12, 1, 12, 6, 14, 7, 2, 14, 4, 15, 7, 14, 5, 8, 4, 13, 2, 10, 4, 13, 0, 13, 1, 11, 1, 12, 7, 12, 6, 13, 4, 13, 4, 13, 2, 12, 2, 13, 1, 13, 7, 10, 2, 11, 2, 10, 7, 15, 7, 11, 5, 13, 2, 8, 2, 14, 4, 9, 2, 14, 0, 8, 1, 8, 7, 10, 5, 15, 6, 14, 11, 7, 10, 2, 11, 1, 13, 0, 11, 1, 15, 7, 8, 1, 9, 4, 13, 4, 8, 4, 8, 3, 10, 0, 9, 0, 9, 2, 9, 7, 9, 6, 10, 7, 13, 1, 13, 7, 14, 6, 11, 3, 12, 2, 8, 2, 12, 5, 11, 5, 12, 2, 10, 5, 14, 4, 12, 4, 13, 2, 9, 1, 10, 0, 2, 12, 0, 13, 7, 13, 2, 12, 4, 8, 1, 12, 4, 13, 6, 11, 7, 13, 7, 13, 1, 9, 7, 10, 2, 10, 1, 9, 2, 10, 1, 11, 6, 9, 4, 13, 2, 10, 0, 10, 2, 14, 0, 13, 7, 10, 7, 10, 0, 12, 0, 9, 0, 13, 2, 13, 1, 9, 0, 15, 2, 14, 2, 13, 11, 7, 8, 4, 10, 2, 10, 7, 12, 1, 11, 7, 8, 2, 13, 1, 10, 0, 10, 2, 13, 6, 14, 0, 14, 7, 13, 6, 14, 5, 13, 4, 15, 1, 10, 2, 13, 7, 13, 7, 9, 4, 9, 6, 13, 3, 13, 3, 8, 4, 13, 4, 10, 6, 10, 5, 12, 4, 10, 7, 11, 6, 9, 6, 4, 14, 6, 11, 7, 13, 6, 10, 4, 8, 4, 11, 6, 8, 5, 13, 7, 14, 7, 14, 1, 9, 0, 12, 1, 9, 1, 12, 4, 14, 7, 10, 4, 13, 7, 13, 7, 11, 4, 10, 1, 11, 7, 13, 4, 12, 1, 10, 4, 12, 2, 8, 2, 12, 2, 10, 2, 12, 1, 12, 4, 12, 2, 12, 8, 2, 13, 2, 8, 1, 13, 1, 12, 1, 12, 2, 12, 2, 11, 1, 9, 2, 11, 3, 12, 4, 8, 4, 12, 4, 10, 6, 10, 1, 13, 2, 11, 2, 10, 1, 12, 0, 14, 2, 14, 4, 9, 2, 8, 1, 13, 4, 8, 0, 12, 4, 11, 6, 12, 6, 11, 7, 10, 7, 11, 2, 10, 7 }; /*static const uint8_t dither_matrix_halftone8[4 + 8*8] = { 8, 8, 64, 3, 60, 53, 42, 26, 27, 43, 54, 61, 52, 41, 25, 13, 14, 28, 44, 55, 40, 24, 12, 5, 6, 15, 29, 45, 39, 23, 4, 0, 1, 7, 16, 30, 38, 22, 11, 3, 2, 8, 17, 31, 51, 37, 21, 10, 9, 18, 32, 46, 59, 50, 36, 20, 19, 33, 47, 56, 63, 58, 49, 35, 34, 48, 57, 62 }; */ static const uint8_t dither_matrix_diagonal45_8[4 + 8*8] = { 8, 8, 64, 2, 16, 32, 48, 56, 40, 24, 8, 0, 36, 52, 60, 44, 28, 12, 4, 20, 49, 57, 41, 25, 9, 1, 17, 33, 61, 45, 29, 13, 5, 21, 37, 53, 42, 26, 10, 2, 18, 34, 50, 58, 30, 14, 6, 22, 38, 54, 62, 46, 11, 3, 19, 35, 51, 59, 43, 27, 7, 23, 39, 55, 63, 47, 31, 15 }; typedef struct halftone_pixelinfo { int x; int y; double distance; double angle; } halftone_pixelinfo; static inline halftone_pixelinfo* halftone_pixel_make(int w, int h) { int x, y, k; halftone_pixelinfo* hp = Gif_NewArray(halftone_pixelinfo, w * h); for (y = k = 0; y != h; ++y) for (x = 0; x != w; ++x, ++k) { hp[k].x = x; hp[k].y = y; hp[k].distance = -1; } return hp; } static inline void halftone_pixel_combine(halftone_pixelinfo* hp, double cx, double cy) { double d = (hp->x - cx) * (hp->x - cx) + (hp->y - cy) * (hp->y - cy); if (hp->distance < 0 || d < hp->distance) { hp->distance = d; hp->angle = atan2(hp->y - cy, hp->x - cx); } } static inline int halftone_pixel_compare(const void* va, const void* vb) { const halftone_pixelinfo* a = (const halftone_pixelinfo*) va; const halftone_pixelinfo* b = (const halftone_pixelinfo*) vb; if (fabs(a->distance - b->distance) > 0.01) return a->distance < b->distance ? -1 : 1; else return a->angle < b->angle ? -1 : 1; } static uint8_t* halftone_pixel_matrix(halftone_pixelinfo* hp, int w, int h, int nc) { int i; uint8_t* m = Gif_NewArray(uint8_t, 4 + w * h); m[0] = w; m[1] = h; m[3] = nc; if (w * h > 255) { double s = 255. / (w * h); m[2] = 255; for (i = 0; i != w * h; ++i) m[4 + hp[i].x + hp[i].y*w] = (int) (i * s); } else { m[2] = w * h; for (i = 0; i != w * h; ++i) m[4 + hp[i].x + hp[i].y*w] = i; } Gif_DeleteArray(hp); return m; } static uint8_t* make_halftone_matrix_square(int w, int h, int nc) { halftone_pixelinfo* hp = halftone_pixel_make(w, h); int i; for (i = 0; i != w * h; ++i) halftone_pixel_combine(&hp[i], (w-1)/2.0, (h-1)/2.0); qsort(hp, w * h, sizeof(*hp), halftone_pixel_compare); return halftone_pixel_matrix(hp, w, h, nc); } static uint8_t* make_halftone_matrix_triangular(int w, int h, int nc) { halftone_pixelinfo* hp = halftone_pixel_make(w, h); int i; for (i = 0; i != w * h; ++i) { halftone_pixel_combine(&hp[i], (w-1)/2.0, (h-1)/2.0); halftone_pixel_combine(&hp[i], -0.5, -0.5); halftone_pixel_combine(&hp[i], w-0.5, -0.5); halftone_pixel_combine(&hp[i], -0.5, h-0.5); halftone_pixel_combine(&hp[i], w-0.5, h-0.5); } qsort(hp, w * h, sizeof(*hp), halftone_pixel_compare); return halftone_pixel_matrix(hp, w, h, nc); } int set_dither_type(Gt_OutputData* od, const char* name) { int parm[4], nparm = 0; const char* comma = strchr(name, ','); char buf[256]; /* separate arguments from dither name */ if (comma && (size_t) (comma - name) < sizeof(buf)) { memcpy(buf, name, comma - name); buf[comma - name] = 0; name = buf; } for (nparm = 0; comma && *comma && isdigit((unsigned char) comma[1]); ++nparm) parm[nparm] = strtol(&comma[1], (char**) &comma, 10); /* parse dither name */ if (od->dither_type == dither_ordered_new) Gif_DeleteArray(od->dither_data); od->dither_type = dither_none; if (strcmp(name, "none") == 0 || strcmp(name, "posterize") == 0) /* ok */; else if (strcmp(name, "default") == 0) od->dither_type = dither_default; else if (strcmp(name, "floyd-steinberg") == 0 || strcmp(name, "fs") == 0) od->dither_type = dither_floyd_steinberg; else if (strcmp(name, "o3") == 0 || strcmp(name, "o3x3") == 0 || (strcmp(name, "o") == 0 && nparm >= 1 && parm[0] == 3)) { od->dither_type = dither_ordered; od->dither_data = dither_matrix_o3x3; } else if (strcmp(name, "o4") == 0 || strcmp(name, "o4x4") == 0 || (strcmp(name, "o") == 0 && nparm >= 1 && parm[0] == 4)) { od->dither_type = dither_ordered; od->dither_data = dither_matrix_o4x4; } else if (strcmp(name, "o8") == 0 || strcmp(name, "o8x8") == 0 || (strcmp(name, "o") == 0 && nparm >= 1 && parm[0] == 8)) { od->dither_type = dither_ordered; od->dither_data = dither_matrix_o8x8; } else if (strcmp(name, "ro64") == 0 || strcmp(name, "ro64x64") == 0 || strcmp(name, "o") == 0 || strcmp(name, "ordered") == 0) { od->dither_type = dither_ordered; od->dither_data = dither_matrix_ro64x64; } else if (strcmp(name, "diag45") == 0 || strcmp(name, "diagonal") == 0) { od->dither_type = dither_ordered; od->dither_data = dither_matrix_diagonal45_8; } else if (strcmp(name, "halftone") == 0 || strcmp(name, "half") == 0 || strcmp(name, "trihalftone") == 0 || strcmp(name, "trihalf") == 0) { int size = nparm >= 1 && parm[0] > 0 ? parm[0] : 6; int ncol = nparm >= 2 && parm[1] > 1 ? parm[1] : 2; od->dither_type = dither_ordered_new; od->dither_data = make_halftone_matrix_triangular(size, (int) (size * sqrt(3) + 0.5), ncol); } else if (strcmp(name, "sqhalftone") == 0 || strcmp(name, "sqhalf") == 0 || strcmp(name, "squarehalftone") == 0) { int size = nparm >= 1 && parm[0] > 0 ? parm[0] : 6; int ncol = nparm >= 2 && parm[1] > 1 ? parm[1] : 2; od->dither_type = dither_ordered_new; od->dither_data = make_halftone_matrix_square(size, size, ncol); } else return -1; if (od->dither_type == dither_ordered && nparm >= 2 && parm[1] > 1 && parm[1] != od->dither_data[3]) { int size = od->dither_data[0] * od->dither_data[1]; uint8_t* dd = Gif_NewArray(uint8_t, 4 + size); memcpy(dd, od->dither_data, 4 + size); dd[3] = parm[1]; od->dither_data = dd; od->dither_type = dither_ordered_new; } return 0; } gifsicle-1.78/src/optimize.c0000644000175000017500000012162712251251172012761 00000000000000/* optimize.c - Functions to optimize animated GIFs. Copyright (C) 1997-2013 Eddie Kohler, ekohler@gmail.com This file is part of gifsicle. Gifsicle is free software. It is distributed under the GNU Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #include #include "gifsicle.h" #include #include typedef struct { int left; int top; int width; int height; } Gif_OptBounds; typedef struct { uint16_t left; uint16_t top; uint16_t width; uint16_t height; uint32_t size; uint8_t disposal; int transparent; uint8_t *needed_colors; uint16_t required_color_count; int32_t active_penalty; int32_t global_penalty; int32_t colormap_penalty; Gif_Image *new_gfi; } Gif_OptData; /* Screen width and height */ static int screen_width; static int screen_height; /* Colormap containing all colors in the image. May have >256 colors */ static Gif_Colormap *all_colormap; /* The old global colormap, or a fake one we created if necessary */ static Gif_Colormap *in_global_map; /* The new global colormap */ static Gif_Colormap *out_global_map; #define TRANSP (0) static uint16_t background; #define NOT_IN_OUT_GLOBAL (256) static uint16_t *last_data; static uint16_t *this_data; static uint16_t *next_data; static int image_index; static int gif_color_count; /***** * SIMPLE HELPERS * new and delete optimize data; and colormap_combine; and sorting permutations **/ Gif_OptData * new_opt_data(void) { Gif_OptData *od = Gif_New(Gif_OptData); od->needed_colors = 0; od->global_penalty = 1; return od; } void delete_opt_data(Gif_OptData *od) { if (!od) return; Gif_DeleteArray(od->needed_colors); Gif_Delete(od); } /* colormap_combine: Ensure that each color in 'src' is represented in 'dst'. For each color 'i' in 'src', src->col[i].pixel == some j so that GIF_COLOREQ(&src->col[i], &dst->col[j]). dst->col[0] is reserved for transparency; no source color will be mapped to it. */ void colormap_combine(Gif_Colormap *dst, Gif_Colormap *src) { Gif_Color *src_col, *dst_col; int i, j; /* expand dst->col if necessary. This might change dst->col */ if (dst->ncol + src->ncol >= dst->capacity) { dst->capacity *= 2; Gif_ReArray(dst->col, Gif_Color, dst->capacity); } src_col = src->col; dst_col = dst->col; for (i = 0; i < src->ncol; i++, src_col++) { for (j = 1; j < dst->ncol; j++) { if (GIF_COLOREQ(src_col, &dst_col[j])) goto found; } dst_col[j] = *src_col; dst_col[j].pixel = 0; dst->ncol++; found: src_col->pixel = j; } } /* sort_permutation: sorts a given permutation 'perm' according to the corresponding values in 'values'. Thus, in the output, the sequence '[ values[perm[i]] | i <- 0..size-1 ]' will be monotonic, either up or (if is_down != 0) down. */ /* 9.Dec.1998 - Dumb idiot, it's time you stopped using C. The optimizer was broken because I switched to uint32_t's for the sorting values without considering the consequences; and the consequences were bad. */ static int32_t *permuting_sort_values; static int permuting_sorter_up(const void *v1, const void *v2) { const uint16_t *n1 = (const uint16_t *)v1; const uint16_t *n2 = (const uint16_t *)v2; return (permuting_sort_values[*n1] - permuting_sort_values[*n2]); } static int permuting_sorter_down(const void *v1, const void *v2) { const uint16_t *n1 = (const uint16_t *)v1; const uint16_t *n2 = (const uint16_t *)v2; return (permuting_sort_values[*n2] - permuting_sort_values[*n1]); } static uint16_t * sort_permutation(uint16_t *perm, int size, int32_t *values, int is_down) { permuting_sort_values = values; if (is_down) qsort(perm, size, sizeof(uint16_t), permuting_sorter_down); else qsort(perm, size, sizeof(uint16_t), permuting_sorter_up); permuting_sort_values = 0; return perm; } /***** * MANIPULATING IMAGE AREAS **/ static Gif_OptBounds safe_bounds(Gif_Image *area) { /* Returns bounds constrained to lie within the screen. */ Gif_OptBounds b; b.left = constrain(0, area->left, screen_width); b.top = constrain(0, area->top, screen_height); b.width = constrain(0, area->left + area->width, screen_width) - b.left; b.height = constrain(0, area->top + area->height, screen_height) - b.top; return b; } static void copy_data_area(uint16_t *dst, uint16_t *src, Gif_Image *area) { Gif_OptBounds ob; int y; if (!area) return; ob = safe_bounds(area); dst += ob.top * screen_width + ob.left; src += ob.top * screen_width + ob.left; for (y = 0; y < ob.height; y++) { memcpy(dst, src, sizeof(uint16_t) * ob.width); dst += screen_width; src += screen_width; } } static void copy_data_area_subimage(uint16_t *dst, uint16_t *src, Gif_OptData *area) { Gif_Image img; img.left = area->left; img.top = area->top; img.width = area->width; img.height = area->height; copy_data_area(dst, src, &img); } static void fill_data_area(uint16_t *dst, uint16_t value, Gif_Image *area) { int x, y; Gif_OptBounds ob = safe_bounds(area); dst += ob.top * screen_width + ob.left; for (y = 0; y < ob.height; y++) { for (x = 0; x < ob.width; x++) dst[x] = value; dst += screen_width; } } static void fill_data_area_subimage(uint16_t *dst, uint16_t value, Gif_OptData *area) { Gif_Image img; img.left = area->left; img.top = area->top; img.width = area->width; img.height = area->height; fill_data_area(dst, value, &img); } static void erase_screen(uint16_t *dst) { uint32_t i; uint32_t screen_size = screen_width * screen_height; for (i = 0; i < screen_size; i++) *dst++ = background; } /***** * APPLY A GIF FRAME OR DISPOSAL TO AN IMAGE DESTINATION **/ static void apply_frame(uint16_t *dst, Gif_Image *gfi, int replace, int save_uncompressed) { int i, y, was_compressed = 0; uint16_t map[256]; Gif_Colormap *colormap = gfi->local ? gfi->local : in_global_map; Gif_OptBounds ob = safe_bounds(gfi); if (!gfi->img) { was_compressed = 1; Gif_UncompressImage(gfi); } /* make sure transparency maps to TRANSP */ for (i = 0; i < colormap->ncol; i++) map[i] = colormap->col[i].pixel; /* out-of-bounds colors map to 0, for the sake of argument */ for (i = colormap->ncol; i < 256; i++) map[i] = colormap->col[0].pixel; if (gfi->transparent >= 0 && gfi->transparent < 256) map[gfi->transparent] = TRANSP; else replace = 1; /* map the image */ dst += ob.left + ob.top * screen_width; for (y = 0; y < ob.height; y++) { uint8_t *gfi_pointer = gfi->img[y]; int x; if (replace) for (x = 0; x < ob.width; x++) dst[x] = map[gfi_pointer[x]]; else for (x = 0; x < ob.width; x++) { uint16_t new_pixel = map[gfi_pointer[x]]; if (new_pixel != TRANSP) dst[x] = new_pixel; } dst += screen_width; } if (was_compressed && !save_uncompressed) Gif_ReleaseUncompressedImage(gfi); } static void apply_frame_disposal(uint16_t *into_data, uint16_t *from_data, uint16_t *previous_data, Gif_Image *gfi) { int screen_size = screen_width * screen_height; if (gfi->disposal == GIF_DISPOSAL_PREVIOUS) memcpy(into_data, previous_data, sizeof(uint16_t) * screen_size); else { memcpy(into_data, from_data, sizeof(uint16_t) * screen_size); if (gfi->disposal == GIF_DISPOSAL_BACKGROUND) fill_data_area(into_data, background, gfi); } } /***** * FIND THE SMALLEST BOUNDING RECTANGLE ENCLOSING ALL CHANGES **/ /* find_difference_bounds: Find the smallest rectangular area containing all the changes and store it in 'bounds'. */ static void find_difference_bounds(Gif_OptData *bounds, Gif_Image *gfi, Gif_Image *last) { int lf, rt, lf_min, rt_max, tp, bt, x, y; Gif_OptBounds ob; /* 1.Aug.99 - use current bounds if possible, since this function is a speed bottleneck */ if (!last || last->disposal == GIF_DISPOSAL_NONE || last->disposal == GIF_DISPOSAL_ASIS) { ob = safe_bounds(gfi); lf_min = ob.left; rt_max = ob.left + ob.width - 1; tp = ob.top; bt = ob.top + ob.height - 1; } else { lf_min = 0; rt_max = screen_width - 1; tp = 0; bt = screen_height - 1; } for (; tp < screen_height; tp++) if (memcmp(last_data + screen_width * tp, this_data + screen_width * tp, screen_width * sizeof(uint16_t)) != 0) break; for (; bt >= tp; bt--) if (memcmp(last_data + screen_width * bt, this_data + screen_width * bt, screen_width * sizeof(uint16_t)) != 0) break; lf = screen_width; rt = 0; for (y = tp; y <= bt; y++) { uint16_t *ld = last_data + screen_width * y; uint16_t *td = this_data + screen_width * y; for (x = lf_min; x < lf; x++) if (ld[x] != td[x]) break; lf = x; for (x = rt_max; x > rt; x--) if (ld[x] != td[x]) break; rt = x; } /* 19.Aug.1999 - handle case when there's no difference between frames */ if (tp > bt) { tp = bt = gfi->top; lf = rt = gfi->left; } bounds->left = lf; bounds->top = tp; bounds->width = rt + 1 - lf; bounds->height = bt + 1 - tp; } /* expand_difference_bounds: If the current image has background disposal and the background is transparent, we must expand the difference bounds to include any blanked (newly transparent) pixels that are still transparent in the next image. This function does that by comparing this_data and next_data. The new bounds are passed and stored in 'bounds'; the image's old bounds, which are also the maximum bounds, are passed in 'this_bounds'. */ static int expand_difference_bounds(Gif_OptData *bounds, Gif_Image *this_bounds) { int x, y, expanded = 0; Gif_OptBounds ob = safe_bounds(this_bounds); if (bounds->width <= 0 || bounds->height <= 0) { bounds->left = bounds->top = 0; bounds->width = screen_width; bounds->height = screen_height; } /* 20.Nov.2013 - The image `bounds` might be larger than `this_bounds` because of a previous frame's background disposal. Don't accidentally shrink `this_bounds`. */ if (ob.left > bounds->left) { ob.width = (ob.left + ob.width) - bounds->left; ob.left = bounds->left; } if (ob.top > bounds->top) { ob.height = (ob.top + ob.height) - bounds->top; ob.top = bounds->top; } if (ob.left + ob.width < bounds->left + bounds->width) ob.width = bounds->left + bounds->width - ob.left; if (ob.top + ob.height < bounds->top + bounds->height) ob.height = bounds->top + bounds->height - ob.top; for (; ob.top < bounds->top; ++ob.top, --ob.height) { uint16_t *now = this_data + screen_width * ob.top; uint16_t *next = next_data + screen_width * ob.top; for (x = ob.left; x < ob.left + ob.width; ++x) if (now[x] != TRANSP && next[x] == TRANSP) { expanded = 1; goto found_top; } } found_top: for (; ob.top + ob.height > bounds->top + bounds->height; --ob.height) { uint16_t *now = this_data + screen_width * (ob.top + ob.height - 1); uint16_t *next = next_data + screen_width * (ob.top + ob.height - 1); for (x = ob.left; x < ob.left + ob.width; ++x) if (now[x] != TRANSP && next[x] == TRANSP) { expanded = 1; goto found_bottom; } } found_bottom: for (; ob.left < bounds->left; ++ob.left, --ob.width) { uint16_t *now = this_data + ob.left; uint16_t *next = next_data + ob.left; for (y = ob.top; y < ob.top + ob.height; ++y) if (now[y*screen_width] != TRANSP && next[y*screen_width] == TRANSP) { expanded = 1; goto found_left; } } found_left: for (; ob.left + ob.width > bounds->left + bounds->width; --ob.width) { uint16_t *now = this_data + ob.left + ob.width - 1; uint16_t *next = next_data + ob.left + ob.width - 1; for (y = ob.top; y < ob.top + ob.height; ++y) if (now[y*screen_width] != TRANSP && next[y*screen_width] == TRANSP) { expanded = 1; goto found_right; } } found_right: if (!expanded) for (y = ob.top; y < ob.top + ob.height; ++y) { uint16_t *now = this_data + y*screen_width; uint16_t *next = next_data + y*screen_width; for (x = ob.left; x < ob.left + ob.width; ++x) if (now[x] != TRANSP && next[x] == TRANSP) { expanded = 1; break; } } bounds->left = ob.left; bounds->top = ob.top; bounds->width = ob.width; bounds->height = ob.height; return expanded; } /* fix_difference_bounds: make sure the image isn't 0x0. */ static void fix_difference_bounds(Gif_OptData *bounds) { if (bounds->width == 0 || bounds->height == 0) { bounds->top = 0; bounds->left = 0; bounds->width = 1; bounds->height = 1; } /* assert that image lies completely within screen */ assert(bounds->top < screen_height && bounds->left < screen_width && bounds->top + bounds->height <= screen_height && bounds->left + bounds->width <= screen_width); } /***** * DETERMINE WHICH COLORS ARE USED **/ #define REQUIRED 2 #define REPLACE_TRANSP 1 /* get_used_colors: mark which colors are needed by a given image. Returns a need array so that need[j] == REQUIRED if the output colormap must include all_color j; REPLACE_TRANSP if it should be replaced by transparency; and 0 if it's not in the image at all. If use_transparency > 0, then a pixel which was the same in the last frame may be replaced with transparency. If use_transparency == 2, transparency MUST be set. (This happens on the first image if the background should be transparent.) */ static void get_used_colors(Gif_OptData *bounds, int use_transparency) { int top = bounds->top, width = bounds->width, height = bounds->height; int i, x, y; int all_ncol = all_colormap->ncol; uint8_t *need = Gif_NewArray(uint8_t, all_ncol); for (i = 0; i < all_ncol; i++) need[i] = 0; /* set elements that are in the image. need == 2 means the color must be in the map; need == 1 means the color may be replaced by transparency. */ for (y = top; y < top + height; y++) { uint16_t *data = this_data + screen_width * y + bounds->left; uint16_t *last = last_data + screen_width * y + bounds->left; for (x = 0; x < width; x++) { if (data[x] != last[x]) need[data[x]] = REQUIRED; else if (need[data[x]] == 0) need[data[x]] = REPLACE_TRANSP; } } if (need[TRANSP]) need[TRANSP] = REQUIRED; /* check for too many colors; also force transparency if needed */ { int count[3]; /* Count distinct pixels in each category */ count[0] = count[1] = count[2] = 0; for (i = 0; i < all_ncol; i++) count[need[i]]++; /* If use_transparency is large and there's room, add transparency */ if (use_transparency > 1 && !need[TRANSP] && count[REQUIRED] < 256) { need[TRANSP] = REQUIRED; count[REQUIRED]++; } /* If too many "potentially transparent" pixels, force transparency */ if (count[REPLACE_TRANSP] + count[REQUIRED] > 256) use_transparency = 1; /* Make sure transparency is marked necessary if we use it */ if (count[REPLACE_TRANSP] > 0 && use_transparency && !need[TRANSP]) { need[TRANSP] = REQUIRED; count[REQUIRED]++; } /* If not using transparency, change "potentially transparent" pixels to "actually used" pixels */ if (!use_transparency) { for (i = 0; i < all_ncol; i++) if (need[i] == REPLACE_TRANSP) need[i] = REQUIRED; count[REQUIRED] += count[REPLACE_TRANSP]; } /* If we can afford to have transparency, and we want to use it, then include it */ if (count[REQUIRED] < 256 && use_transparency && !need[TRANSP]) { need[TRANSP] = REQUIRED; count[REQUIRED]++; } bounds->required_color_count = count[REQUIRED]; } bounds->needed_colors = need; } /***** * FIND SUBIMAGES AND COLORS USED **/ static void create_subimages(Gif_Stream *gfs, int optimize_flags, int save_uncompressed) { int screen_size; Gif_Image *last_gfi; int next_data_valid; uint16_t *previous_data = 0; int local_color_tables = 0; screen_size = screen_width * screen_height; next_data = Gif_NewArray(uint16_t, screen_size); next_data_valid = 0; /* do first image. Remember to uncompress it if necessary */ erase_screen(last_data); erase_screen(this_data); last_gfi = 0; /* PRECONDITION: previous_data -- garbage last_data -- optimized image after disposal of previous optimized frame this_data -- input image after disposal of previous input frame next_data -- input image after application of current input frame, if next_image_valid */ for (image_index = 0; image_index < gfs->nimages; image_index++) { Gif_Image *gfi = gfs->images[image_index]; Gif_OptData *subimage = new_opt_data(); if (gfi->local) local_color_tables = 1; /* save previous data if necessary */ if (gfi->disposal == GIF_DISPOSAL_PREVIOUS || (local_color_tables && image_index > 0 && last_gfi->disposal > GIF_DISPOSAL_ASIS)) { if (!previous_data) previous_data = Gif_NewArray(uint16_t, screen_size); memcpy(previous_data, this_data, sizeof(uint16_t) * screen_size); } /* set this_data equal to the current image */ if (next_data_valid) { uint16_t *temp = this_data; this_data = next_data; next_data = temp; next_data_valid = 0; } else apply_frame(this_data, gfi, 0, save_uncompressed); retry_frame: /* find minimum area of difference between this image and last image */ subimage->disposal = GIF_DISPOSAL_ASIS; if (image_index > 0) find_difference_bounds(subimage, gfi, last_gfi); else { Gif_OptBounds ob = safe_bounds(gfi); subimage->left = ob.left; subimage->top = ob.top; subimage->width = ob.width; subimage->height = ob.height; } /* might need to expand difference border if transparent background & background disposal */ if ((gfi->disposal == GIF_DISPOSAL_BACKGROUND || gfi->disposal == GIF_DISPOSAL_PREVIOUS) && background == TRANSP && image_index < gfs->nimages - 1) { /* set up next_data */ Gif_Image *next_gfi = gfs->images[image_index + 1]; apply_frame_disposal(next_data, this_data, previous_data, gfi); apply_frame(next_data, next_gfi, 0, save_uncompressed); next_data_valid = 1; /* expand border as necessary */ if (expand_difference_bounds(subimage, gfi)) subimage->disposal = GIF_DISPOSAL_BACKGROUND; } fix_difference_bounds(subimage); /* set map of used colors */ { int use_transparency = (optimize_flags & GT_OPT_MASK) > 1 && image_index > 0; if (image_index == 0 && background == TRANSP) use_transparency = 2; get_used_colors(subimage, use_transparency); /* Gifsicle's optimization strategy normally creates frames with ASIS or BACKGROUND disposal (not PREVIOUS disposal). However, there are cases when PREVIOUS disposal is strictly required, or a frame would require more than 256 colors. Detect this case and try to recover. */ if (subimage->required_color_count > 256) { if (image_index > 0 && local_color_tables) { Gif_OptData *subimage = (Gif_OptData*) last_gfi->user_data; if ((last_gfi->disposal == GIF_DISPOSAL_PREVIOUS || last_gfi->disposal == GIF_DISPOSAL_BACKGROUND) && subimage->disposal != last_gfi->disposal) { subimage->disposal = last_gfi->disposal; memcpy(last_data, previous_data, sizeof(uint16_t) * screen_size); goto retry_frame; } } fatal_error("%d colors required in a frame (256 is max)", subimage->required_color_count); } } gfi->user_data = subimage; last_gfi = gfi; /* Apply optimized disposal to last_data and unoptimized disposal to this_data. Before 9.Dec.1998 I applied unoptimized disposal uniformly to both. This led to subtle bugs. After all, to determine bounds, we want to compare the current image (only obtainable through unoptimized disposal) with what WILL be left after the previous OPTIMIZED image's disposal. This fix is repeated in create_new_image_data */ if (subimage->disposal == GIF_DISPOSAL_BACKGROUND) fill_data_area_subimage(last_data, background, subimage); else copy_data_area_subimage(last_data, this_data, subimage); if (last_gfi->disposal == GIF_DISPOSAL_BACKGROUND) fill_data_area(this_data, background, last_gfi); else if (last_gfi->disposal == GIF_DISPOSAL_PREVIOUS) { uint16_t *temp = previous_data; previous_data = this_data; this_data = temp; } } Gif_DeleteArray(next_data); if (previous_data) Gif_DeleteArray(previous_data); } /***** * CALCULATE OUTPUT GLOBAL COLORMAP **/ /* create_out_global_map: The interface function to this pass. It creates out_global_map and sets pixel values on all_colormap appropriately. Specifically: all_colormap->col[P].pixel >= 256 ==> P is not in the global colormap. Otherwise, all_colormap->col[P].pixel == the J so that GIF_COLOREQ(&all_colormap->col[P], &out_global_map->col[J]). On return, the 'colormap_penalty' component of an image's Gif_OptData structure is <0 iff that image will need a local colormap. 20.Aug.1999 - updated to new version that arranges the entire colormap, not just the stuff above 256 colors. */ static void increment_penalties(Gif_OptData *opt, int32_t *penalty, int32_t delta) { int i; int all_ncol = all_colormap->ncol; uint8_t *need = opt->needed_colors; for (i = 1; i < all_ncol; i++) if (need[i] == REQUIRED) penalty[i] += delta; } static void create_out_global_map(Gif_Stream *gfs) { int all_ncol = all_colormap->ncol; int32_t *penalty = Gif_NewArray(int32_t, all_ncol); uint16_t *permute = Gif_NewArray(uint16_t, all_ncol); uint16_t *ordering = Gif_NewArray(uint16_t, all_ncol); int cur_ncol, i, imagei; int nglobal_all = (all_ncol <= 257 ? all_ncol - 1 : 256); int permutation_changed; /* initial permutation is null */ for (i = 0; i < all_ncol - 1; i++) permute[i] = i + 1; /* choose appropriate penalties for each image */ for (imagei = 0; imagei < gfs->nimages; imagei++) { Gif_OptData *opt = (Gif_OptData *)gfs->images[imagei]->user_data; opt->global_penalty = opt->colormap_penalty = 1; for (i = 2; i < opt->required_color_count; i *= 2) opt->colormap_penalty *= 3; opt->active_penalty = (all_ncol > 257 ? opt->colormap_penalty : opt->global_penalty); } /* set initial penalties for each color */ for (i = 1; i < all_ncol; i++) penalty[i] = 0; for (imagei = 0; imagei < gfs->nimages; imagei++) { Gif_OptData *opt = (Gif_OptData *)gfs->images[imagei]->user_data; increment_penalties(opt, penalty, opt->active_penalty); } permutation_changed = 1; /* Loop, removing one color at a time. */ for (cur_ncol = all_ncol - 1; cur_ncol; cur_ncol--) { uint16_t removed; /* sort permutation based on penalty */ if (permutation_changed) sort_permutation(permute, cur_ncol, penalty, 1); permutation_changed = 0; /* update reverse permutation */ removed = permute[cur_ncol - 1]; ordering[removed] = cur_ncol - 1; /* decrement penalties for colors that are out of the running */ for (imagei = 0; imagei < gfs->nimages; imagei++) { Gif_OptData *opt = (Gif_OptData *)gfs->images[imagei]->user_data; uint8_t *need = opt->needed_colors; if (opt->global_penalty > 0 && need[removed] == REQUIRED) { increment_penalties(opt, penalty, -opt->active_penalty); opt->global_penalty = 0; opt->colormap_penalty = (cur_ncol > 256 ? -1 : 0); permutation_changed = 1; } } /* change colormap penalties if we're no longer working w/globalmap */ if (cur_ncol == 257) { for (i = 0; i < all_ncol; i++) penalty[i] = 0; for (imagei = 0; imagei < gfs->nimages; imagei++) { Gif_OptData *opt = (Gif_OptData *)gfs->images[imagei]->user_data; opt->active_penalty = opt->global_penalty; increment_penalties(opt, penalty, opt->global_penalty); } permutation_changed = 1; } } /* make sure background is in the global colormap */ if (background != TRANSP && ordering[background] >= 256) { uint16_t other = permute[255]; ordering[other] = ordering[background]; ordering[background] = 255; } /* assign out_global_map based on permutation */ out_global_map = Gif_NewFullColormap(nglobal_all, 256); for (i = 1; i < all_ncol; i++) if (ordering[i] < 256) { out_global_map->col[ordering[i]] = all_colormap->col[i]; all_colormap->col[i].pixel = ordering[i]; } else all_colormap->col[i].pixel = NOT_IN_OUT_GLOBAL; /* set the stream's background color */ if (background != TRANSP) gfs->background = ordering[background]; /* cleanup */ Gif_DeleteArray(penalty); Gif_DeleteArray(permute); Gif_DeleteArray(ordering); } /***** * CREATE COLOR MAPPING FOR A PARTICULAR IMAGE **/ /* sort_colormap_permutation_rgb: for canonicalizing local colormaps by arranging them in RGB order */ static int colormap_rgb_permutation_sorter(const void *v1, const void *v2) { const Gif_Color *col1 = (const Gif_Color *)v1; const Gif_Color *col2 = (const Gif_Color *)v2; int value1 = (col1->gfc_red << 16) | (col1->gfc_green << 8) | col1->gfc_blue; int value2 = (col2->gfc_red << 16) | (col2->gfc_green << 8) | col2->gfc_blue; return value1 - value2; } /* prepare_colormap_map: Create and return an array of bytes mapping from global pixel values to pixel values for this image. It may add colormap cells to 'into'; if there isn't enough room in 'into', it will return 0. It sets the 'transparent' field of 'gfi->optdata', but otherwise doesn't change or read it at all. */ static uint8_t * prepare_colormap_map(Gif_Image *gfi, Gif_Colormap *into, uint8_t *need) { int i; int is_global = (into == out_global_map); int all_ncol = all_colormap->ncol; Gif_Color *all_col = all_colormap->col; int ncol = into->ncol; Gif_Color *col = into->col; uint8_t *map = Gif_NewArray(uint8_t, all_ncol); uint8_t into_used[256]; /* keep track of which pixel indices in 'into' have been used; initially, all unused */ for (i = 0; i < 256; i++) into_used[i] = 0; /* go over all non-transparent global pixels which MUST appear (need[P]==REQUIRED) and place them in 'into' */ for (i = 1; i < all_ncol; i++) { int val; if (need[i] != REQUIRED) continue; /* fail if a needed pixel isn't in the global map */ if (is_global) { val = all_col[i].pixel; if (val >= ncol) goto error; } else { /* always place colors in a local colormap */ if (ncol == 256) goto error; val = ncol; col[val] = all_col[i]; col[val].pixel = i; ncol++; } map[i] = val; into_used[val] = 1; } if (!is_global) { qsort(col, ncol, sizeof(Gif_Color), colormap_rgb_permutation_sorter); for (i = 0; i < ncol; ++i) map[col[i].pixel] = i; } /* now check for transparency */ gfi->transparent = -1; if (need[TRANSP]) { int transparent = -1; /* first, look for an unused index in 'into'. Pick the lowest one: the lower transparent index we get, the more likely we can shave a bit off min_code_bits later, thus saving space */ for (i = 0; i < ncol; i++) if (!into_used[i]) { transparent = i; break; } /* otherwise, [1.Aug.1999] use a fake slot for the purely transparent color. Don't actually enter the transparent color into the colormap -- we might be able to output a smaller colormap! If there's no room for it, give up */ if (transparent < 0) { if (ncol < 256) { transparent = ncol; /* 1.Aug.1999 - don't increase ncol */ col[ncol] = all_col[TRANSP]; } else goto error; } /* change mapping */ map[TRANSP] = transparent; for (i = 1; i < all_ncol; i++) if (need[i] == REPLACE_TRANSP) map[i] = transparent; gfi->transparent = transparent; } /* If we get here, it worked! Commit state changes (the number of color cells in 'into') and return the map. */ into->ncol = ncol; return map; error: /* If we get here, it failed! Return 0 and don't change global state. */ Gif_DeleteArray(map); return 0; } /* prepare_colormap: make a colormap up from the image data by fitting any used colors into a colormap. Returns a map from global color index to index in this image's colormap. May set a local colormap on 'gfi'. */ static uint8_t * prepare_colormap(Gif_Image *gfi, uint8_t *need) { uint8_t *map; /* try to map pixel values into the global colormap */ Gif_DeleteColormap(gfi->local); gfi->local = 0; map = prepare_colormap_map(gfi, out_global_map, need); if (!map) { /* that didn't work; add a local colormap. */ gfi->local = Gif_NewFullColormap(0, 256); map = prepare_colormap_map(gfi, gfi->local, need); } return map; } /***** * CREATE OUTPUT FRAME DATA **/ /* simple_frame_data: just copy the data from the image into the frame data. No funkiness, no transparency, nothing */ static void simple_frame_data(Gif_Image *gfi, uint8_t *map) { Gif_OptBounds ob = safe_bounds(gfi); int x, y, scan_width = gfi->width; for (y = 0; y < ob.height; y++) { uint16_t *from = this_data + screen_width * (y + ob.top) + ob.left; uint8_t *into = gfi->image_data + y * scan_width; for (x = 0; x < ob.width; x++) *into++ = map[*from++]; } } /* transp_frame_data: copy the frame data into the actual image, using transparency occasionally according to a heuristic described below */ static void transp_frame_data(Gif_Stream *gfs, Gif_Image *gfi, uint8_t *map, int optimize_flags, Gif_CompressInfo *gcinfo) { Gif_OptBounds ob = safe_bounds(gfi); int x, y, transparent = gfi->transparent; uint16_t *last = 0; uint16_t *cur = 0; uint8_t *data, *begin_same; uint8_t *t2_data = 0, *last_for_t2; int nsame; /* First, try w/o transparency. Compare this to the result using transparency and pick the better of the two. */ simple_frame_data(gfi, map); Gif_FullCompressImage(gfs, gfi, gcinfo); gcinfo->flags |= GIF_WRITE_SHRINK; /* Actually copy data to frame. Use transparency if possible to shrink the size of the written GIF. The written GIF will be small if patterns (sequences of pixel values) recur in the image. We could conceivably use transparency to produce THE OPTIMAL image, with the most recurring patterns of the best kinds; but this would be very hard (wouldn't it?). Instead, we settle for a heuristic: we try and create RUNS. (Since we *try* to create them, they will presumably recur!) A RUN is a series of adjacent pixels all with the same value. By & large, we just use the regular image's values. However, we might create a transparent run *not in* the regular image, if TWO OR MORE adjacent runs OF DIFFERENT COLORS *could* be made transparent. (An area can be made transparent if the corresponding area in the previous frame had the same colors as the area does now.) Why? If only one run (say of color C) could be transparent, we get no large immediate advantage from making it transparent (it'll be a run of the same length regardless). Also, we might LOSE: what if the run was adjacent to some more of color C, which couldn't be made transparent? If we use color C (instead of the transparent color), then we get a longer run. This simple heuristic does a little better than Gifwizard's (6/97) on some images, but does *worse than nothing at all* on others. However, it DOES do better than the complicated, greedy algorithm that preceded it; and now we pick either the transparency-optimized version or the normal version, whichever compresses smaller, for the best of both worlds. (9/98) On several images, making SINGLE color runs transparent wins over the previous heuristic, so try both at optimize level 3 or above (the cost is ~30%). (2/11) */ data = begin_same = last_for_t2 = gfi->image_data; nsame = 0; for (y = 0; y < ob.height; ++y) { last = last_data + screen_width * (y + ob.top) + ob.left; cur = this_data + screen_width * (y + ob.top) + ob.left; for (x = 0; x < ob.width; ++x) { if (*cur != *last && map[*cur] != transparent) { if (nsame == 1 && data[-1] != transparent && (optimize_flags & GT_OPT_MASK) > 2) { if (!t2_data) t2_data = Gif_NewArray(uint8_t, ob.width * ob.height); memcpy(t2_data + (last_for_t2 - gfi->image_data), last_for_t2, begin_same - last_for_t2); memset(t2_data + (begin_same - gfi->image_data), transparent, data - begin_same); last_for_t2 = data; } nsame = 0; } else if (nsame == 0) { begin_same = data; ++nsame; } else if (nsame == 1 && map[*cur] != data[-1]) { memset(begin_same, transparent, data - begin_same); ++nsame; } if (nsame > 1) *data = transparent; else *data = map[*cur]; ++data, ++cur, ++last; } } if (t2_data) memcpy(t2_data + (last_for_t2 - gfi->image_data), last_for_t2, data - last_for_t2); /* Now, try compressed transparent version(s) and pick the better of the two (or three). */ Gif_FullCompressImage(gfs, gfi, gcinfo); if (t2_data) { Gif_SetUncompressedImage(gfi, t2_data, Gif_DeleteArrayFunc, 0); Gif_FullCompressImage(gfs, gfi, gcinfo); } Gif_ReleaseUncompressedImage(gfi); gcinfo->flags &= ~GIF_WRITE_SHRINK; } /***** * CREATE NEW IMAGE DATA **/ /* last == what last image ended up looking like this == what new image should look like last = apply O1 + dispose O1 + ... + apply On-1 + dispose On-1 this = apply U1 + dispose U1 + ... + apply Un-1 + dispose Un-1 + apply Un invariant: apply O1 + dispose O1 + ... + apply Ok === apply U1 + dispose U1 + ... + apply Uk */ static void create_new_image_data(Gif_Stream *gfs, int optimize_flags) { Gif_Image cur_unopt_gfi; /* placehoder; maintains pre-optimization image size so we can apply background disposal */ int screen_size = screen_width * screen_height; uint16_t *previous_data = 0; Gif_CompressInfo gcinfo = gif_write_info; if ((optimize_flags & GT_OPT_MASK) >= 3) gcinfo.flags |= GIF_WRITE_OPTIMIZE; gfs->global = out_global_map; /* do first image. Remember to uncompress it if necessary */ erase_screen(last_data); erase_screen(this_data); for (image_index = 0; image_index < gfs->nimages; image_index++) { Gif_Image *cur_gfi = gfs->images[image_index]; Gif_OptData *opt = (Gif_OptData *)cur_gfi->user_data; int was_compressed = (cur_gfi->img == 0); /* save previous data if necessary */ if (cur_gfi->disposal == GIF_DISPOSAL_PREVIOUS) { if (!previous_data) previous_data = Gif_NewArray(uint16_t, screen_size); copy_data_area(previous_data, this_data, cur_gfi); } /* set up this_data to be equal to the current image */ apply_frame(this_data, cur_gfi, 0, 0); /* save actual bounds and disposal from unoptimized version so we can apply the disposal correctly next time through */ cur_unopt_gfi = *cur_gfi; /* set bounds and disposal from optdata */ Gif_ReleaseUncompressedImage(cur_gfi); cur_gfi->left = opt->left; cur_gfi->top = opt->top; cur_gfi->width = opt->width; cur_gfi->height = opt->height; cur_gfi->disposal = opt->disposal; if (image_index > 0) cur_gfi->interlace = 0; /* find the new image's colormap and then make new data */ { uint8_t *map = prepare_colormap(cur_gfi, opt->needed_colors); uint8_t *data = Gif_NewArray(uint8_t, cur_gfi->width * cur_gfi->height); Gif_SetUncompressedImage(cur_gfi, data, Gif_DeleteArrayFunc, 0); /* don't use transparency on first frame */ if ((optimize_flags & GT_OPT_MASK) > 1 && image_index > 0 && cur_gfi->transparent >= 0) transp_frame_data(gfs, cur_gfi, map, optimize_flags, &gcinfo); else simple_frame_data(cur_gfi, map); if (cur_gfi->img) { if (was_compressed || (optimize_flags & GT_OPT_MASK) > 1) { Gif_FullCompressImage(gfs, cur_gfi, &gcinfo); Gif_ReleaseUncompressedImage(cur_gfi); } else /* bug fix 22.May.2001 */ Gif_ReleaseCompressedImage(cur_gfi); } Gif_DeleteArray(map); } delete_opt_data(opt); cur_gfi->user_data = 0; /* Set up last_data and this_data. last_data must contain this_data + new disposal. this_data must contain this_data + old disposal. */ if (cur_gfi->disposal == GIF_DISPOSAL_NONE || cur_gfi->disposal == GIF_DISPOSAL_ASIS) copy_data_area(last_data, this_data, cur_gfi); else if (cur_gfi->disposal == GIF_DISPOSAL_BACKGROUND) fill_data_area(last_data, background, cur_gfi); else if (cur_gfi->disposal != GIF_DISPOSAL_PREVIOUS) assert(0 && "optimized frame has strange disposal"); if (cur_unopt_gfi.disposal == GIF_DISPOSAL_BACKGROUND) fill_data_area(this_data, background, &cur_unopt_gfi); else if (cur_unopt_gfi.disposal == GIF_DISPOSAL_PREVIOUS) copy_data_area(this_data, previous_data, &cur_unopt_gfi); } if (previous_data) Gif_DeleteArray(previous_data); } /***** * INITIALIZATION AND FINALIZATION **/ static int initialize_optimizer(Gif_Stream *gfs) { int i, screen_size; if (gfs->nimages < 1) return 0; /* combine colormaps */ all_colormap = Gif_NewFullColormap(1, 384); all_colormap->col[0].gfc_red = 255; all_colormap->col[0].gfc_green = 255; all_colormap->col[0].gfc_blue = 255; in_global_map = gfs->global; if (!in_global_map) { Gif_Color *col; in_global_map = Gif_NewFullColormap(256, 256); col = in_global_map->col; for (i = 0; i < 256; i++, col++) col->gfc_red = col->gfc_green = col->gfc_blue = i; } { int any_globals = 0; int first_transparent = -1; for (i = 0; i < gfs->nimages; i++) { Gif_Image *gfi = gfs->images[i]; if (gfi->local) colormap_combine(all_colormap, gfi->local); else any_globals = 1; if (gfi->transparent >= 0 && first_transparent < 0) first_transparent = i; } if (any_globals) colormap_combine(all_colormap, in_global_map); /* try and maintain transparency's pixel value */ if (first_transparent >= 0) { Gif_Image *gfi = gfs->images[first_transparent]; Gif_Colormap *gfcm = gfi->local ? gfi->local : gfs->global; all_colormap->col[TRANSP] = gfcm->col[gfi->transparent]; } } /* find screen_width and screen_height, and clip all images to screen */ Gif_CalculateScreenSize(gfs, 0); screen_width = gfs->screen_width; screen_height = gfs->screen_height; for (i = 0; i < gfs->nimages; i++) Gif_ClipImage(gfs->images[i], 0, 0, screen_width, screen_height); /* create data arrays */ screen_size = screen_width * screen_height; last_data = Gif_NewArray(uint16_t, screen_size); this_data = Gif_NewArray(uint16_t, screen_size); /* set up colormaps */ gif_color_count = 2; while (gif_color_count < gfs->global->ncol && gif_color_count < 256) gif_color_count *= 2; /* choose background */ if (gfs->images[0]->transparent < 0 && gfs->background < in_global_map->ncol) background = in_global_map->col[gfs->background].pixel; else background = TRANSP; return 1; } static void finalize_optimizer(Gif_Stream *gfs, int optimize_flags) { int i; if (background == TRANSP) gfs->background = (uint8_t)gfs->images[0]->transparent; /* 11.Mar.2010 - remove entirely transparent frames. */ for (i = 1; i < gfs->nimages && !(optimize_flags & GT_OPT_KEEPEMPTY); ++i) { Gif_Image *gfi = gfs->images[i]; if (gfi->width == 1 && gfi->height == 1 && gfi->transparent >= 0 && !gfi->identifier && !gfi->comment && (gfi->disposal == GIF_DISPOSAL_ASIS || gfi->disposal == GIF_DISPOSAL_NONE || gfi->disposal == GIF_DISPOSAL_PREVIOUS) && gfi->delay && gfs->images[i-1]->delay) { Gif_UncompressImage(gfi); if (gfi->img[0][0] == gfi->transparent && (gfs->images[i-1]->disposal == GIF_DISPOSAL_ASIS || gfs->images[i-1]->disposal == GIF_DISPOSAL_NONE)) { gfs->images[i-1]->delay += gfi->delay; Gif_DeleteImage(gfi); memmove(&gfs->images[i], &gfs->images[i+1], sizeof(Gif_Image *) * (gfs->nimages - i - 1)); --gfs->nimages; --i; } } } /* 10.Dec.1998 - prefer GIF_DISPOSAL_NONE to GIF_DISPOSAL_ASIS. This is semantically "wrong" -- it's better to set the disposal explicitly than rely on default behavior -- but will result in smaller GIF files, since the graphic control extension can be left off in many cases. */ for (i = 0; i < gfs->nimages; i++) if (gfs->images[i]->disposal == GIF_DISPOSAL_ASIS && gfs->images[i]->delay == 0 && gfs->images[i]->transparent < 0) gfs->images[i]->disposal = GIF_DISPOSAL_NONE; Gif_DeleteColormap(in_global_map); Gif_DeleteColormap(all_colormap); Gif_DeleteArray(last_data); Gif_DeleteArray(this_data); } /* the interface function! */ void optimize_fragments(Gif_Stream *gfs, int optimize_flags, int huge_stream) { if (!initialize_optimizer(gfs)) return; create_subimages(gfs, optimize_flags, !huge_stream); create_out_global_map(gfs); create_new_image_data(gfs, optimize_flags); finalize_optimizer(gfs, optimize_flags); } gifsicle-1.78/src/Makefile.w320000644000175000017500000000513412237442106013024 00000000000000# Win32 Makefile originally by Emil Mikulic # Updates by Eddie Kohler and # Steven Marthouse # This makefile will work under Win32 (95/98/NT/whatever) or Win64. # It should work out-of-the-box with Visual C++ 5. # # C:\GIFSICLE> nmake -f Makefile.w32 # *** MAKING UNGIFSICLE *** # If `GIFWRITE_OBJ' is defined to `gifwrite.obj', Gifsicle will use # Unisys-patented LZW compression. If it is defined to `ungifwrt.obj', it # will use unpatented run-length compression, which creates larger GIFs but # is completely free software. If you downloaded the ungifsicle package, # which doesn't have `gifwrite.c', you MUST define `GIFWRITE_OBJ' to # `ungifwrt.obj' by commenting the first line below and uncommenting the # second. GIFWRITE_OBJ = gifwrite.obj #GIFWRITE_OBJ = ungifwrt.obj # *** SUPPORTING WILDCARD EXPANSION *** # Define `SETARGV_OBJ' to the filename for the `setargv.obj' object file. # The definition included here works for Microsoft compilers; you will # probably need to change it if you're using a different compiler. You can # define it to the empty string, in which case Gifsicle will compile fine, # but you won't be able to use wildcards in file name arguments. SETARGV_OBJ = $(MSDEVDIR)\lib\setargv.obj CC = cl CFLAGS = -I.. -I..\include -DHAVE_CONFIG_H -D_CONSOLE /W3 /ML -O2 GIFSICLE_OBJS = clp.obj fmalloc.obj giffunc.obj gifread.obj gifunopt.obj \ $(GIFWRITE_OBJ) merge.obj optimize.obj quantize.obj support.obj \ xform.obj gifsicle.obj $(SETARGV_OBJ) GIFDIFF_OBJS = clp.obj fmalloc.obj giffunc.obj gifread.obj gifdiff.obj \ $(SETARGV_OBJ) .c.obj: $(CC) $(CFLAGS) /c $< gifsicle.exe: $(GIFSICLE_OBJS) $(CC) $(CFLAGS) /ogifsicle.exe $(GIFSICLE_OBJS) gifdiff.exe: $(GIFDIFF_OBJS) $(CC) $(CFLAGS) /ogifdiff.exe $(GIFDIFF_OBJS) clp.obj: ..\config.h ..\include\lcdf\clp.h clp.c fmalloc.obj: ..\config.h fmalloc.c giffunc.obj: ..\config.h giffunc.c ..\include\lcdfgif\gif.h gifread.obj: ..\config.h gifread.c ..\include\lcdfgif\gif.h gifwrite.obj: ..\config.h gifwrite.c ..\include\lcdfgif\gif.h ungifwrt.obj: ..\config.h ungifwrt.c ..\include\lcdfgif\gif.h gifunopt.obj: ..\config.h gifunopt.c ..\include\lcdfgif\gif.h merge.obj: ..\config.h gifsicle.h merge.c optimize.obj: ..\config.h gifsicle.h optimize.c quantize.obj: ..\config.h gifsicle.h quantize.c support.obj: ..\config.h gifsicle.h support.c xform.obj: ..\config.h gifsicle.h xform.c gifsicle.obj: ..\config.h gifsicle.h gifsicle.c ..\config.h: win32cfg.h copy win32cfg.h ..\config.h clean: del *.obj del *.exe gifsicle-1.78/src/support.c0000644000175000017500000013756212244271315012645 00000000000000/* support.c - Support functions for gifsicle. Copyright (C) 1997-2013 Eddie Kohler, ekohler@gmail.com This file is part of gifsicle. Gifsicle is free software. It is distributed under the GNU Public License, version 2; you can copy, distribute, or alter it at will, as long as this notice is kept intact and this source code is made available. There is no warranty, express or implied. */ #include #include "gifsicle.h" #include #include #include #include #include #include const char *program_name = "gifsicle"; static int verbose_pos = 0; int error_count = 0; int no_warnings = 0; static void verror(int need_file, int seriousness, const char *fmt, va_list val) { char pattern[BUFSIZ]; char buffer[BUFSIZ]; static char *printed_file = 0; static int just_printed_context = 0; const char *initial_prefix = program_name; const char *prefix = ""; const char *iname = input_name; if (!iname) iname = ""; if (mode == EXPLODING && active_output_data.active_output_name) iname = active_output_data.active_output_name; if (printed_file && strcmp(printed_file, iname) != 0) { free(printed_file); printed_file = 0; } if (need_file == 2 && !printed_file) initial_prefix = iname; else if (need_file && !printed_file) { if (mode != BLANK_MODE && mode != MERGING && nested_mode != MERGING) { fprintf(stderr, "%s: While processing '%s':\n", program_name, iname); just_printed_context = 1; prefix = " "; initial_prefix = ""; } printed_file = malloc(strlen(iname) + 1); strcpy(printed_file, iname); } else if (just_printed_context && seriousness == 0) { prefix = " "; initial_prefix = ""; } else just_printed_context = 0; if (seriousness > 2) sprintf(pattern, "%s%s%s fatal error: %%s\n", initial_prefix, *initial_prefix ? ":" : "", prefix); else if (seriousness == 1) sprintf(pattern, "%s%s%s warning: %%s\n", initial_prefix, *initial_prefix ? ":" : "", prefix); else sprintf(pattern, "%s%s%s %%s\n", initial_prefix, *initial_prefix ? ":" : "", prefix); if (seriousness > 1) error_count++; else if (no_warnings) return; /* try and keep error messages together (no interleaving of error messages from two gifsicle processes in the same command line) by calling fprintf only once */ verbose_endline(); if (strlen(fmt) + strlen(pattern) < BUFSIZ) { sprintf(buffer, pattern, fmt); vfprintf(stderr, buffer, val); } else { pattern[strlen(pattern) - 3] = 0; fprintf(stderr, "%s", pattern); vfprintf(stderr, fmt, val); putc('\n', stderr); } } void fatal_error(const char *message, ...) { va_list val; va_start(val, message); verror(0, 3, message, val); va_end(val); exit(EXIT_USER_ERR); } void error(int need_file, const char *message, ...) { va_list val; va_start(val, message); verror(need_file, 2, message, val); va_end(val); } void warning(int need_file, const char *message, ...) { va_list val; va_start(val, message); verror(need_file, 1, message, val); va_end(val); } void warncontext(int need_file, const char *message, ...) { va_list val; va_start(val, message); verror(need_file, 0, message, val); va_end(val); } void clp_error_handler(Clp_Parser *clp, const char *message) { (void) clp; verbose_endline(); fputs(message, stderr); } void short_usage(void) { fprintf(stderr, "Usage: %s [OPTION | FILE | FRAME]...\n\ Try '%s --help' for more information.\n", program_name, program_name); } void usage(void) { printf("\ 'Gifsicle' manipulates GIF images. Its most common uses include combining\n\ single images into animations, adding transparency, optimizing animations for\n\ space, and printing information about GIFs.\n\ \n\ Usage: %s [OPTION | FILE | FRAME]...\n\n", program_name); printf("\ Mode options: at most one, before any filenames.\n\ -m, --merge Merge mode: combine inputs, write stdout.\n\ -b, --batch Batch mode: modify inputs, write back to\n\ same filenames.\n\ -e, --explode Explode mode: write N files for each input,\n\ one per frame, to 'input.frame-number'.\n\ -E, --explode-by-name Explode mode, but write 'input.name'.\n\n"); printf("\ General options: Also --no-OPTION for info and verbose.\n\ -I, --info Print info about input GIFs. Two -I's means\n\ normal output is not suppressed.\n\ --color-info, --cinfo --info plus colormap details.\n\ --extension-info, --xinfo --info plus extension details.\n\ --size-info, --sinfo --info plus compression information.\n\ -V, --verbose Prints progress information.\n"); printf("\ -h, --help Print this message and exit.\n\ --version Print version number and exit.\n\ -o, --output FILE Write output to FILE.\n\ -w, --no-warnings Don't report warnings.\n\ --conserve-memory Conserve memory at the expense of speed.\n\ --multifile Support concatenated GIF files.\n\ \n"); printf("\ Frame selections: #num, #num1-num2, #num1-, #name\n\ \n\ Frame change options:\n\ --delete FRAMES Delete FRAMES from input.\n\ --insert-before FRAME GIFS Insert GIFS before FRAMES in input.\n\ --append GIFS Append GIFS to input.\n\ --replace FRAMES GIFS Replace FRAMES with GIFS in input.\n\ --done Done with frame changes.\n\n"); printf("\ Image options: Also --no-OPTION and --same-OPTION.\n\ -B, --background COL Make COL the background color.\n\ --crop X,Y+WxH, --crop X,Y-X2,Y2\n\ Crop the image.\n\ --crop-transparency Crop transparent borders off the image.\n\ --flip-horizontal, --flip-vertical\n\ Flip the image.\n"); printf("\ -i, --interlace Turn on interlacing.\n\ -S, --logical-screen WxH Set logical screen to WxH.\n\ -p, --position X,Y Set frame position to (X,Y).\n\ --rotate-90, --rotate-180, --rotate-270, --no-rotate\n\ Rotate the image.\n\ -t, --transparent COL Make COL transparent.\n\n"); printf("\ Extension options: Also --no-OPTION and --same-OPTION.\n\ -x, --app-extension N D Add an app extension named N with data D.\n\ -c, --comment TEXT Add a comment before the next frame.\n\ --extension N D Add an extension number N with data D.\n\ -n, --name TEXT Set next frame's name.\n\n"); printf("\ Animation options: Also --no-OPTION and --same-OPTION.\n\ -d, --delay TIME Set frame delay to TIME (in 1/100sec).\n\ -D, --disposal METHOD Set frame disposal to METHOD.\n\ -l, --loopcount[=N] Set loop extension to N (default forever).\n\ -O, --optimize[=LEVEL] Optimize output GIFs.\n\ -U, --unoptimize Unoptimize input GIFs.\n\ \n"); printf("\ Whole-GIF options: Also --no-OPTION.\n\ --careful Write larger GIFs that avoid bugs in other\n\ programs.\n\ --change-color COL1 COL2 Change COL1 to COL2 throughout.\n\ -k, --colors N Reduce the number of colors to N.\n\ --color-method METHOD Set method for choosing reduced colors.\n\ -f, --dither Dither image after changing colormap.\n"); #if HAVE_POW printf("\ --gamma G Set gamma for color reduction [2.2].\n"); #endif printf("\ --resize WxH Resize the output GIF to WxH.\n\ --resize-width W Resize to width W and proportional height.\n\ --resize-height H Resize to height H and proportional width.\n"); printf("\ --scale XFACTOR[xYFACTOR] Scale the output GIF by XFACTORxYFACTOR.\n\ --transform-colormap CMD Transform each output colormap by shell CMD.\n\ --use-colormap CMAP Set output GIF's colormap to CMAP, which can\n\ be 'web', 'gray', 'bw', or a GIF file.\n\n"); printf("\ Report bugs to .\n\ Too much information? Try '%s --help | more'.\n", program_name); #ifdef GIF_UNGIF printf("\ This version of Gifsicle writes uncompressed GIFs, which can be far larger\n\ than compressed GIFs. See http://www.lcdf.org/gifsicle for more information.\n"); #endif } void verbose_open(char open, const char *name) { int l = strlen(name); if (verbose_pos && verbose_pos + 3 + l > 79) { fputc('\n', stderr); verbose_pos = 0; } if (verbose_pos) { fputc(' ', stderr); verbose_pos++; } fputc(open, stderr); fputs(name, stderr); verbose_pos += 1 + l; } void verbose_close(char close) { fputc(close, stderr); verbose_pos++; } void verbose_endline(void) { if (verbose_pos) { fputc('\n', stderr); fflush(stderr); verbose_pos = 0; } } /***** * Info functions **/ const char* debug_color_str(const Gif_Color* gfc) { static int whichbuf = 0; static char buf[4][8]; whichbuf = (whichbuf + 1) % 4; sprintf(buf[whichbuf], "#%02X%02X%02X", gfc->gfc_red, gfc->gfc_green, gfc->gfc_blue); return buf[whichbuf]; } static void safe_puts(const char *s, uint32_t len, FILE *f) { const char *last_safe = s; for (; len > 0; len--, s++) if (*s < ' ' || *s >= 0x7F || *s == '\\') { if (last_safe != s) { size_t n = s - last_safe; if (fwrite(last_safe, 1, n, f) != n) return; } last_safe = s + 1; switch (*s) { case '\a': fputs("\\a", f); break; case '\b': fputs("\\b", f); break; case '\f': fputs("\\f", f); break; case '\n': fputs("\\n", f); break; case '\r': fputs("\\r", f); break; case '\t': fputs("\\t", f); break; case '\v': fputs("\\v", f); break; case '\\': fputs("\\\\", f); break; case 0: if (len > 1) fputs("\\000", f); break; default: fprintf(f, "\\%03o", *s); break; } } if (last_safe != s) { size_t n = s - last_safe; if (fwrite(last_safe, 1, n, f) != n) return; } } static void comment_info(FILE *where, Gif_Comment *gfcom, char *prefix) { int i; for (i = 0; i < gfcom->count; i++) { fputs(prefix, where); safe_puts(gfcom->str[i], gfcom->len[i], where); fputc('\n', where); } } #define COLORMAP_COLS 4 static void colormap_info(FILE *where, Gif_Colormap *gfcm, char *prefix) { int i, j; int nrows = ((gfcm->ncol - 1) / COLORMAP_COLS) + 1; for (j = 0; j < nrows; j++) { int which = j; fputs(prefix, where); for (i = 0; i < COLORMAP_COLS && which < gfcm->ncol; i++, which += nrows) { if (i) fputs(" ", where); fprintf(where, " %3d: #%02X%02X%02X", which, gfcm->col[which].gfc_red, gfcm->col[which].gfc_green, gfcm->col[which].gfc_blue); } fputc('\n', where); } } static void extension_info(FILE *where, Gif_Stream *gfs, Gif_Extension *gfex, int count) { uint8_t *data = gfex->data; uint32_t pos = 0; uint32_t len = gfex->length; fprintf(where, " extension %d: ", count); if (gfex->kind == 255) { fprintf(where, "app '"); safe_puts(gfex->application, strlen(gfex->application), where); fprintf(where, "'"); } else { if (gfex->kind >= 32 && gfex->kind < 127) fprintf(where, "'%c' (0x%02X)", gfex->kind, gfex->kind); else fprintf(where, "0x%02X", gfex->kind); } if (gfex->position >= gfs->nimages) fprintf(where, " at end\n"); else fprintf(where, " before #%d\n", gfex->position); /* Now, hexl the data. */ while (len > 0) { uint32_t row = 16; uint32_t i; if (row > len) row = len; fprintf(where, " %08x: ", pos); for (i = 0; i < row; i += 2) { if (i + 1 >= row) fprintf(where, "%02x ", data[i]); else fprintf(where, "%02x%02x ", data[i], data[i+1]); } for (; i < 16; i += 2) fputs(" ", where); putc(' ', where); for (i = 0; i < row; i++, data++) putc((*data >= ' ' && *data < 127 ? *data : '.'), where); putc('\n', where); pos += row; len -= row; } } void stream_info(FILE *where, Gif_Stream *gfs, const char *filename, int flags) { Gif_Extension *gfex; int n; if (!gfs) return; verbose_endline(); fprintf(where, "* %s %d image%s\n", (filename ? filename : ""), gfs->nimages, gfs->nimages == 1 ? "" : "s"); fprintf(where, " logical screen %dx%d\n", gfs->screen_width, gfs->screen_height); if (gfs->global) { fprintf(where, " global color table [%d]\n", gfs->global->ncol); if (flags & INFO_COLORMAPS) colormap_info(where, gfs->global, " |"); fprintf(where, " background %d\n", gfs->background); } if (gfs->comment) comment_info(where, gfs->comment, " end comment "); if (gfs->loopcount == 0) fprintf(where, " loop forever\n"); else if (gfs->loopcount > 0) fprintf(where, " loop count %u\n", (unsigned)gfs->loopcount); for (n = 0, gfex = gfs->extensions; gfex; gfex = gfex->next, n++) if (flags & INFO_EXTENSIONS) extension_info(where, gfs, gfex, n); if (n && !(flags & INFO_EXTENSIONS)) fprintf(where, " extensions %d\n", n); } static char *disposal_names[] = { "none", "asis", "background", "previous", "4", "5", "6", "7" }; void image_info(FILE *where, Gif_Stream *gfs, Gif_Image *gfi, int flags) { int num; if (!gfs || !gfi) return; num = Gif_ImageNumber(gfs, gfi); verbose_endline(); fprintf(where, " + image #%d ", num); if (gfi->identifier) fprintf(where, "#%s ", gfi->identifier); fprintf(where, "%dx%d", gfi->width, gfi->height); if (gfi->left || gfi->top) fprintf(where, " at %d,%d", gfi->left, gfi->top); if (gfi->interlace) fprintf(where, " interlaced"); if (gfi->transparent >= 0) fprintf(where, " transparent %d", gfi->transparent); fprintf(where, "\n"); if ((flags & INFO_SIZES) && gfi->compressed) fprintf(where, " compressed size %u\n", gfi->compressed_len); if (gfi->comment) comment_info(where, gfi->comment, " comment "); if (gfi->local) { fprintf(where, " local color table [%d]\n", gfi->local->ncol); if (flags & INFO_COLORMAPS) colormap_info(where, gfi->local, " |"); } if (gfi->disposal || gfi->delay) { fprintf(where, " "); if (gfi->disposal) fprintf(where, " disposal %s", disposal_names[gfi->disposal]); if (gfi->delay) fprintf(where, " delay %d.%02ds", gfi->delay / 100, gfi->delay % 100); fprintf(where, "\n"); } } char * explode_filename(const char *filename, int number, const char *name, int max_nimages) { static char *s; int l = strlen(filename); l += name ? strlen(name) : 10; Gif_Delete(s); s = Gif_NewArray(char, l + 3); if (name) sprintf(s, "%s.%s", filename, name); else if (max_nimages <= 1000) sprintf(s, "%s.%03d", filename, number); else { int digits; unsigned j; unsigned max = (max_nimages < 0 ? 0 : max_nimages); for (digits = 4, j = 10000; max > j; digits++) j *= 10; sprintf(s, "%s.%0*d", filename, digits, number); } return s; } /***** * parsing functions **/ int frame_spec_1; int frame_spec_2; char *frame_spec_name; int dimensions_x; int dimensions_y; int position_x; int position_y; Gif_Color parsed_color; Gif_Color parsed_color2; double parsed_scale_factor_x; double parsed_scale_factor_y; int parse_frame_spec(Clp_Parser *clp, const char *arg, int complain, void *thunk) { char *c; (void)thunk; frame_spec_1 = 0; frame_spec_2 = -1; frame_spec_name = 0; if (!input && !input_name) input_stream(0); if (!input) return 0; if (arg[0] != '#') { if (complain) return Clp_OptionError(clp, "frame specifications must start with #"); else return 0; } arg++; c = (char *)arg; /* Get a number range (#x, #x-y, or #x-). First, read x. */ if (isdigit(c[0])) frame_spec_1 = frame_spec_2 = strtol(c, &c, 10); else if (c[0] == '-' && isdigit(c[1])) frame_spec_1 = frame_spec_2 = Gif_ImageCount(input) + strtol(c, &c, 10); /* Then, if the next character is a dash, read y. Be careful to prevent #- from being interpreted as a frame range. */ if (c[0] == '-' && (frame_spec_2 > 0 || c[1] != 0)) { c++; if (isdigit(c[0])) frame_spec_2 = strtol(c, &c, 10); else if (c[0] == '-' && isdigit(c[1])) frame_spec_2 = Gif_ImageCount(input) + strtol(c, &c, 10); else frame_spec_2 = Gif_ImageCount(input) - 1; } /* It really was a number range (and not a frame name) only if c is now at the end of the argument. */ if (c[0] != 0) { Gif_Image *gfi = Gif_GetNamedImage(input, arg); if (gfi) { frame_spec_name = (char *)arg; frame_spec_1 = frame_spec_2 = Gif_ImageNumber(input, gfi); return 1; } else if (complain < 0) /* -1 is special value meaning 'don't complain about frame NAMES, but do complain about frame numbers.' */ return -97; /* Return -97 on bad frame name. */ else if (complain) return Clp_OptionError(clp, "no frame named %<#%s%>", arg); else return 0; } else { if (frame_spec_1 >= 0 && frame_spec_1 < Gif_ImageCount(input) && frame_spec_2 >= 0 && frame_spec_2 < Gif_ImageCount(input)) return 1; else if (!complain) return 0; else return Clp_OptionError(clp, "frame %<#%s%> out of range, image has %d frames", arg, Gif_ImageCount(input)); } } int parse_dimensions(Clp_Parser *clp, const char *arg, int complain, void *thunk) { char *val; (void)thunk; if (*arg == '_' && arg[1] == 'x') { dimensions_x = 0; val = (char *)(arg + 1); } else dimensions_x = strtol(arg, &val, 10); if (*val == 'x') { if (val[1] == '_' && val[2] == 0) { dimensions_y = 0; val = val + 2; } else dimensions_y = strtol(val + 1, &val, 10); if (*val == 0) return 1; } if (complain) return Clp_OptionError(clp, "invalid dimensions '%s' (want WxH)", arg); else return 0; } int parse_position(Clp_Parser *clp, const char *arg, int complain, void *thunk) { char *val; (void)thunk; position_x = strtol(arg, &val, 10); if (*val == ',') { position_y = strtol(val + 1, &val, 10); if (*val == 0) return 1; } if (complain) return Clp_OptionError(clp, "invalid position '%s' (want 'X,Y')", arg); else return 0; } int parse_scale_factor(Clp_Parser *clp, const char *arg, int complain, void *thunk) { char *val; (void)thunk; parsed_scale_factor_x = strtod(arg, &val); if (*val == 'x') { parsed_scale_factor_y = strtod(val + 1, &val); if (*val == 0) return 1; } else if (*val == 0) { parsed_scale_factor_y = parsed_scale_factor_x; return 1; } if (complain) return Clp_OptionError(clp, "invalid scale factor '%s' (want XxY)", arg); else return 0; } int parse_rectangle(Clp_Parser *clp, const char *arg, int complain, void *thunk) { const char *input_arg = arg; char *val; int x = position_x = strtol(arg, &val, 10); (void)thunk; if (*val == ',') { int y = position_y = strtol(val + 1, &val, 10); if (*val == '-' && parse_position(clp, val + 1, 0, 0)) { if (x >= 0 && y >= 0 && (position_x <= 0 || x < position_x) && (position_y <= 0 || y < position_y)) { /* 18.May.2008: Found it unintuitive that X,Y-0,0 acted like X,Y+-Xx-Y. Therefore changed it so that X,Y-0,0 acts like X,Y+0,0, and similar for negative dimensions. Probably safe to change this behavior since only X,Y+0,0 was documented. */ dimensions_x = (position_x <= 0 ? -position_x : position_x - x); dimensions_y = (position_y <= 0 ? -position_y : position_y - y); position_x = x; position_y = y; return 1; } } else if (*val == '+' && parse_dimensions(clp, val + 1, 0, 0)) return 1; } else if (*val == 'x') { dimensions_x = position_x; dimensions_y = strtol(val + 1, &val, 10); if (*val == 0) { position_x = position_y = 0; return 1; } } if (complain) return Clp_OptionError(clp, "invalid rectangle '%s' (want 'X1,Y1-X2,Y2' or 'X1,Y1+WxH'", input_arg); else return 0; } static int xvalue(char c) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return c - '0'; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': return c - 'A' + 10; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': return c - 'a' + 10; default: return -1; } } static int parse_hex_color_channel(const char *s, int ndigits) { int val1 = xvalue(s[0]); if (val1 < 0) return -1; if (ndigits == 1) return val1 * 16 + val1; else { int val2 = xvalue(s[1]); if (val2 < 0) return -1; return val1 * 16 + val2; } } int parse_color(Clp_Parser *clp, const char *arg, int complain, void *thunk) { const char *input_arg = arg; char *str; int red, green, blue; (void)thunk; if (*arg == '#') { int len = strlen(++arg); if (len == 0 || len % 3 != 0 || (int)strspn(arg, "0123456789ABCDEFabcdef") != len) { if (complain) Clp_OptionError(clp, "invalid color '%s' (want '#RGB' or '#RRGGBB')", input_arg); return 0; } len /= 3; red = parse_hex_color_channel(&arg[ 0 * len ], len); green = parse_hex_color_channel(&arg[ 1 * len ], len); blue = parse_hex_color_channel(&arg[ 2 * len ], len); goto gotrgb; } else if (!isdigit(*arg)) goto error; red = strtol(arg, &str, 10); if (*str == 0) { if (red < 0 || red > 255) goto error; parsed_color.haspixel = 1; parsed_color.pixel = red; return 1; } else if (*str != ',' && *str != '/') goto error; if (*++str == 0) goto error; green = strtol(str, &str, 10); if (*str != ',' && *str != '/') goto error; if (*++str == 0) goto error; blue = strtol(str, &str, 10); if (*str != 0) goto error; gotrgb: if (red < 0 || green < 0 || blue < 0 || red > 255 || green > 255 || blue > 255) goto error; parsed_color.gfc_red = red; parsed_color.gfc_green = green; parsed_color.gfc_blue = blue; parsed_color.haspixel = 0; return 1; error: if (complain) return Clp_OptionError(clp, "invalid color '%s'", input_arg); else return 0; } int parse_two_colors(Clp_Parser *clp, const char *arg, int complain, void *thunk) { Gif_Color old_color; if (parse_color(clp, arg, complain, thunk) <= 0) return 0; old_color = parsed_color; arg = Clp_Shift(clp, 0); if (!arg && complain) return Clp_OptionError(clp, "'%O' takes two color arguments"); else if (!arg) return 0; if (parse_color(clp, arg, complain, thunk) <= 0) return 0; parsed_color2 = parsed_color; parsed_color = old_color; return 1; } /***** * reading a file as a colormap **/ static Gif_Colormap * read_text_colormap(FILE *f, const char *name) { char buf[BUFSIZ]; Gif_Colormap *cm = Gif_NewFullColormap(0, 256); Gif_Color *col = cm->col; int ncol = 0; unsigned red, green, blue; float fred, fgreen, fblue; while (fgets(buf, BUFSIZ, f)) { if (sscanf(buf, "%g %g %g", &fred, &fgreen, &fblue) == 3) { if (fred < 0) fred = 0; if (fgreen < 0) fgreen = 0; if (fblue < 0) fblue = 0; red = (unsigned)(fred + .5); green = (unsigned)(fgreen + .5); blue = (unsigned)(fblue + .5); goto found; } else if (buf[0] == '#' && strspn(buf + 1, "0123456789abcdefABCDEF") == 3 && (!buf[4] || isspace((unsigned char) buf[4]))) { sscanf(buf + 1, "%1x%1x%1x", &red, &green, &blue); red += red << 4; green += green << 4; blue += blue << 4; goto found; } else if (buf[0] == '#' && strspn(buf + 1, "0123456789abcdefABCDEF") == 6 && (!buf[7] || isspace((unsigned char) buf[7]))) { sscanf(buf + 1, "%2x%2x%2x", &red, &green, &blue); found: if (red > 255) red = 255; if (green > 255) green = 255; if (blue > 255) blue = 255; if (ncol >= 256) { error(0, "%s: maximum 256 colors allowed in colormap", name); break; } else { col[ncol].gfc_red = red; col[ncol].gfc_green = green; col[ncol].gfc_blue = blue; ncol++; } } /* handle too-long lines gracefully */ if (strchr(buf, '\n') == 0) { int c; for (c = getc(f); c != '\n' && c != EOF; c = getc(f)) ; } } if (ncol == 0) { error(0, "%s: file not in colormap format", name); Gif_DeleteColormap(cm); return 0; } else { cm->ncol = ncol; return cm; } } Gif_Colormap * read_colormap_file(const char *name, FILE *f) { Gif_Colormap *cm = 0; int c; int my_file = 0; if (name && strcmp(name, "-") == 0) name = 0; if (!f) { my_file = 1; if (!name) f = stdin; else f = fopen(name, "rb"); if (!f) { error(0, "%s: %s", name, strerror(errno)); return 0; } } name = name ? name : ""; if (verbosing) verbose_open('<', name); c = getc(f); ungetc(c, f); if (c == 'G') { Gif_Stream *gfs = Gif_ReadFile(f); if (!gfs) error(0, "%s: file not in GIF format", name); else if (!gfs->global) error(0, "%s: can't use as palette (no global color table)", name); else { if (gfs->errors) warning(0, "%s: there were errors reading this GIF", name); cm = Gif_CopyColormap(gfs->global); } Gif_DeleteStream(gfs); } else cm = read_text_colormap(f, name); if (my_file) fclose(f); if (verbosing) verbose_close('>'); return cm; } /***** * Frame stuff **/ Gt_Frameset * new_frameset(int initial_cap) { Gt_Frameset *fs = Gif_New(Gt_Frameset); if (initial_cap < 0) initial_cap = 0; fs->cap = initial_cap; fs->count = 0; fs->f = Gif_NewArray(Gt_Frame, initial_cap); return fs; } void clear_def_frame_once_options(void) { /* Get rid of next-frame-only options. This causes problems with frame selection. In the command 'gifsicle -nblah f.gif', the name should be applied to frame 0 of f.gif. This will happen automatically when f.gif is read, since all of its frames will be added when it is input. After frame 0, the name in def_frame will be cleared. Now, 'gifsicle -nblah f.gif #1' should apply the name to frame 1 of f.gif. But once f.gif is input, its frames are added, and the name component of def_frame is cleared!! So when #1 comes around it's gone! We handle this in gifsicle.c using the _change fields. */ def_frame.name = 0; def_frame.comment = 0; def_frame.extensions = 0; } Gt_Frame * add_frame(Gt_Frameset *fset, int number, Gif_Stream *gfs, Gif_Image *gfi) { if (number < 0) { while (fset->count >= fset->cap) { fset->cap *= 2; Gif_ReArray(fset->f, Gt_Frame, fset->cap); } number = fset->count++; } else { assert(number < fset->count); blank_frameset(fset, number, number, 0); } /* Mark the stream and the image both */ gfs->refcount++; gfi->refcount++; fset->f[number] = def_frame; fset->f[number].stream = gfs; fset->f[number].image = gfi; clear_def_frame_once_options(); return &fset->f[number]; } static Gif_Extension * copy_extension(Gif_Extension *src) { Gif_Extension *dest = Gif_NewExtension(src->kind, src->application); if (!dest) return 0; dest->data = Gif_NewArray(uint8_t, src->length); dest->length = src->length; dest->free_data = Gif_DeleteArrayFunc; if (!dest->data) { Gif_DeleteExtension(dest); return 0; } memcpy(dest->data, src->data, src->length); return dest; } static Gt_Frame **merger = 0; static int nmerger = 0; static int mergercap = 0; static void merger_add(Gt_Frame *fp) { while (nmerger >= mergercap) if (mergercap) { mergercap *= 2; Gif_ReArray(merger, Gt_Frame *, mergercap); } else { mergercap = 16; merger = Gif_NewArray(Gt_Frame *, mergercap); } merger[ nmerger++ ] = fp; } static void merger_flatten(Gt_Frameset *fset, int f1, int f2) { int i; assert(f1 >= 0 && f2 < fset->count); for (i = f1; i <= f2; i++) { Gt_Frameset *nest = FRAME(fset, i).nest; if (nest && nest->count > 0) { if (FRAME(fset, i).use < 0 && nest->count == 1) { /* use < 0 means use the frame's delay, disposal and name (if not explicitly overridden), but not the frame itself. */ if (FRAME(nest, 0).delay < 0) FRAME(nest, 0).delay = FRAME(fset, i).image->delay; if (FRAME(nest, 0).disposal < 0) FRAME(nest, 0).disposal = FRAME(fset, i).image->disposal; if (FRAME(nest, 0).name == 0 && FRAME(nest, 0).no_name == 0) FRAME(nest, 0).name = Gif_CopyString(FRAME(fset, i).image->identifier); } merger_flatten(nest, 0, nest->count - 1); } if (FRAME(fset, i).use > 0) merger_add(&FRAME(fset, i)); } } static int find_color_or_error(Gif_Color *color, Gif_Stream *gfs, Gif_Image *gfi, char *color_context) { Gif_Colormap *gfcm = gfs->global; int index; if (gfi && gfi->local) gfcm = gfi->local; if (color->haspixel == 2) { /* have pixel value, not color */ if (color->pixel < (uint32_t)gfcm->ncol) return color->pixel; else { if (color_context) error(0, "%s color out of range", color_context); return -1; } } index = Gif_FindColor(gfcm, color); if (index < 0 && color_context) error(2, "%s color not in colormap", color_context); return index; } static void set_background(Gif_Stream *gfs, Gt_OutputData *output_data) { Gif_Color background; int i, j, conflict, want_transparent; Gif_Image *gfi; /* Check for user-specified background. */ /* If they specified the number, silently cooperate. */ if (output_data->background.haspixel == 2) { gfs->background = output_data->background.pixel; return; } /* Otherwise, if they specified a color, search for it. */ if (output_data->background.haspixel) { if (gfs->images[0]->transparent >= 0) { static int context = 0; warning(1, "irrelevant background color"); if (!context) { warncontext(1, "(The background will appear transparent because"); warncontext(1, "the first image contains transparency.)"); context = 1; } } background = output_data->background; goto search; } /* If we get here, user doesn't care about background. */ /* Search for required background colors. */ conflict = want_transparent = background.haspixel = 0; for (i = j = 0; i < nmerger; i++) { if (merger[i]->total_crop) /* frame does not correspond to an image */ continue; gfi = gfs->images[j]; if (gfi->disposal == GIF_DISPOSAL_BACKGROUND || (j == 0 && (gfi->left != 0 || gfi->top != 0 || gfi->width != gfs->screen_width || gfi->height != gfs->screen_height))) { /* transparent.haspixel set below, at merge_frame_done */ int original_bg_transparent = (merger[i]->transparent.haspixel == 2); if ((original_bg_transparent && background.haspixel) || (!original_bg_transparent && want_transparent)) conflict = 2; else if (original_bg_transparent) want_transparent = 1; else if (merger[i]->transparent.haspixel) { if (background.haspixel && !GIF_COLOREQ(&background, &merger[i]->transparent)) conflict = 1; else { background = merger[i]->transparent; background.haspixel = 1; } } } j++; } /* Report conflicts. */ if (conflict || (want_transparent && gfs->images[0]->transparent < 0)) { static int context = 0; warning(1, "input images have conflicting background colors"); if (!context) { warncontext(1, "(This means some animation frames may appear incorrect.)"); context = 1; } } /* If no important background color, bag. */ if (!background.haspixel) { gfs->background = 0; return; } search: i = find_color_or_error(&background, gfs, 0, "background"); gfs->background = (i >= 0 ? i : 0); } static void fix_total_crop(Gif_Stream *dest, Gif_Image *srci, int merger_index) { /* Salvage any relevant information from a frame that's been completely cropped away. This ends up being comments and delay. */ Gt_Frame *fr = merger[merger_index]; Gt_Frame *next_fr = 0; Gif_Image *prev_image; assert(dest->nimages > 0); prev_image = dest->images[dest->nimages - 1]; if (merger_index < nmerger - 1) next_fr = merger[merger_index + 1]; /* Don't save identifiers since the frame that was to be identified, is gone. Save comments though. */ if (!fr->no_comments && srci->comment && next_fr) { if (!next_fr->comment) next_fr->comment = Gif_NewComment(); merge_comments(next_fr->comment, srci->comment); } if (fr->comment && next_fr) { if (!next_fr->comment) next_fr->comment = Gif_NewComment(); merge_comments(next_fr->comment, fr->comment); Gif_DeleteComment(fr->comment); fr->comment = 0; } /* Save delay by adding it to the previous frame's delay. */ if (fr->delay < 0) fr->delay = srci->delay; prev_image->delay += fr->delay; /* Mark this image as totally cropped. */ fr->total_crop = 1; } static void handle_screen(Gif_Stream *dest, uint16_t width, uint16_t height) { /* Set the screen width & height, if the current input width and height are larger */ if (dest->screen_width < width) dest->screen_width = width; if (dest->screen_height < height) dest->screen_height = height; } static void handle_flip_and_screen(Gif_Stream *dest, Gif_Image *desti, Gt_Frame *fr) { Gif_Stream *gfs = fr->stream; uint16_t screen_width = gfs->screen_width; uint16_t screen_height = gfs->screen_height; if (fr->flip_horizontal) flip_image(desti, screen_width, screen_height, 0); if (fr->flip_vertical) flip_image(desti, screen_width, screen_height, 1); if (fr->rotation == 1) rotate_image(desti, screen_width, screen_height, 1); else if (fr->rotation == 2) { flip_image(desti, screen_width, screen_height, 0); flip_image(desti, screen_width, screen_height, 1); } else if (fr->rotation == 3) rotate_image(desti, screen_width, screen_height, 3); /* handle screen size, which might have height & width exchanged */ if (fr->rotation == 1 || fr->rotation == 3) handle_screen(dest, screen_height, screen_width); else handle_screen(dest, screen_width, screen_height); } static void analyze_crop(int nmerger, Gt_Crop *crop, int compress_immediately) { int i, nframes = 0; int l = 0x7FFFFFFF, r = 0, t = 0x7FFFFFFF, b = 0; /* count frames to which this crop applies */ for (i = 0; i < nmerger; i++) if (merger[i]->crop == crop) nframes++; /* find border of frames */ for (i = 0; i < nmerger; i++) if (merger[i]->crop == crop) { Gt_Frame *fr = merger[i]; int ll, tt, rr, bb; if (nframes <= 1) { ll = fr->image->left; tt = fr->image->top; rr = fr->image->left + fr->image->width; bb = fr->image->top + fr->image->height; } else { ll = tt = 0; rr = fr->stream->screen_width; bb = fr->stream->screen_height; } if (ll < l) l = ll; if (tt < t) t = tt; if (rr > r) r = rr; if (bb > b) b = bb; } if (t > b) /* total crop */ l = r = t = b = 0; crop->x = crop->spec_x + l; crop->y = crop->spec_y + t; crop->w = crop->spec_w <= 0 ? (r - crop->x) + crop->spec_w : crop->spec_w; crop->h = crop->spec_h <= 0 ? (b - crop->y) + crop->spec_h : crop->spec_h; crop->left_offset = crop->x; crop->top_offset = crop->y; if (crop->x < 0 || crop->y < 0 || crop->w <= 0 || crop->h <= 0 || crop->x + crop->w > r || crop->y + crop->h > b) { error(1, "cropping dimensions don't fit image"); crop->ready = 2; } else crop->ready = 1; /* Remove transparent edges. */ if (crop->transparent_edges && crop->ready == 1) { int have_l = crop->x, have_t = crop->y, have_r = crop->x + crop->w, have_b = crop->y + crop->h; l = t = 0x7FFFFFFF, r = b = 0; for (i = 0; i < nmerger && (l > have_l || t > have_t || r < have_r || b < have_b); ++i) if (merger[i]->crop == crop) { Gt_Frame *fr = merger[i]; Gif_Image *srci = fr->image; int ll = constrain(have_l, srci->left, have_r), tt = constrain(have_t, srci->top, have_b), rr = constrain(have_l, srci->left + srci->width, have_r), bb = constrain(have_t, srci->top + srci->height, have_b); if (srci->transparent >= 0) { int x, y; uint8_t **img; Gif_UncompressImage(srci); img = srci->img; /* Move top edge down over transparency */ while (tt < bb && tt < t) { uint8_t *data = img[tt - srci->top]; for (x = 0; x < srci->width; ++x) if (data[x] != srci->transparent) goto found_top; ++tt; } found_top: /* Move bottom edge up over transparency */ while (bb > tt + 1 && bb > b) { uint8_t *data = img[bb - 1 - srci->top]; for (x = 0; x < srci->width; ++x) if (data[x] != srci->transparent) goto found_bottom; --bb; } found_bottom: if (tt < bb) { /* Move left edge right over transparency */ while (ll < rr && ll < l) { for (y = tt - srci->top; y < bb - srci->top; ++y) if (img[y][ll - srci->left] != srci->transparent) goto found_left; ++ll; } found_left: /* Move right edge left over transparency */ while (rr > ll + 1 && rr > r) { for (y = tt - srci->top; y < bb - srci->top; ++y) if (img[y][rr - 1 - srci->left] != srci->transparent) goto found_right; --rr; } } found_right: if (compress_immediately) Gif_ReleaseUncompressedImage(srci); } if (tt < bb) { if (ll < l) l = ll; if (tt < t) t = tt; if (rr > r) r = rr; if (bb > b) b = bb; } } if (t > b) crop->w = crop->h = 0; else { crop->x = l; crop->y = t; crop->w = r - l; crop->h = b - t; } } } static inline int apply_frame_transparent(Gif_Image *gfi, Gt_Frame *fr) { int old_transparent = gfi->transparent; if (fr->transparent.haspixel == 255) gfi->transparent = -1; else if (fr->transparent.haspixel) { gfi->transparent = find_color_or_error(&fr->transparent, fr->stream, gfi, "transparent"); if (gfi->transparent < 0) fr->transparent.haspixel = 0; } return old_transparent; } Gif_Stream * merge_frame_interval(Gt_Frameset *fset, int f1, int f2, Gt_OutputData *output_data, int compress_immediately, int *huge_stream) { Gif_Stream *dest = Gif_NewStream(); Gif_Colormap *global = Gif_NewFullColormap(256, 256); int i, same_compressed_ok, all_same_compressed_ok; global->ncol = 0; dest->global = global; /* 11/23/98 A new stream's screen size is 0x0; we'll use the max of the merged-together streams' screen sizes by default (in merge_stream()) */ if (f2 < 0) f2 = fset->count - 1; nmerger = 0; merger_flatten(fset, f1, f2); if (nmerger == 0) { error(1, "empty output GIF not written"); return 0; } /* decide whether stream is huge */ { int s; for (i = s = 0; i < nmerger; i++) s += ((merger[i]->image->width * merger[i]->image->height) / 1024) + 1; *huge_stream = (s > 200 * 1024); /* 200 MB */ if (*huge_stream && !compress_immediately) { warning(1, "huge GIF, conserving memory (processing may take a while)"); compress_immediately = 1; } } /* merge stream-specific info and clear colormaps */ for (i = 0; i < nmerger; i++) merger[i]->stream->userflags = 1; for (i = 0; i < nmerger; i++) { if (merger[i]->stream->userflags) { Gif_Stream *src = merger[i]->stream; Gif_CalculateScreenSize(src, 0); /* merge_stream() unmarks the global colormap */ merge_stream(dest, src, merger[i]->no_comments); src->userflags = 0; } if (merger[i]->image->local) unmark_colors_2(merger[i]->image->local); } /* is it ok to save the same compressed image? This is true only if we will recompress later from scratch. */ /* 13.Aug.2002 - Can't save the same compressed image if we crop, so turn off all_same_compressed_ok below ('analyze crops'). Reported by Tom Schumm . */ if (output_data->colormap_size > 0 || output_data->colormap_fixed || (output_data->optimizing & GT_OPT_MASK) || output_data->scaling > 0) all_same_compressed_ok = 1; else all_same_compressed_ok = 0; /* analyze crops */ for (i = 0; i < nmerger; i++) if (merger[i]->crop) merger[i]->crop->ready = all_same_compressed_ok = 0; for (i = 0; i < nmerger; i++) if (merger[i]->crop && !merger[i]->crop->ready) analyze_crop(nmerger, merger[i]->crop, compress_immediately); /* mark used colors */ for (i = 0; i < nmerger; ++i) { int old_transp = apply_frame_transparent(merger[i]->image, merger[i]); mark_used_colors(merger[i]->stream, merger[i]->image, merger[i]->crop, compress_immediately); merger[i]->image->transparent = old_transp; } /* copy stream-wide information from output_data */ if (output_data->loopcount > -2) dest->loopcount = output_data->loopcount; dest->screen_width = dest->screen_height = 0; /** ACTUALLY MERGE FRAMES INTO THE NEW STREAM **/ for (i = 0; i < nmerger; i++) { Gt_Frame *fr = merger[i]; Gif_Image *srci; Gif_Image *desti; int old_transp; /* First, check for extensions */ { int j; Gif_Extension *gfex = fr->stream->extensions; for (j = 0; fr->stream->images[j] != fr->image; j++) ; while (gfex && gfex->position < j) gfex = gfex->next; while (!fr->no_extensions && gfex && gfex->position == j) { Gif_AddExtension(dest, copy_extension(gfex), i); gfex = gfex->next; } gfex = fr->extensions; while (gfex) { Gif_Extension *next = gfex->next; Gif_AddExtension(dest, gfex, i); gfex = next; } fr->extensions = 0; } /* Make a copy of the image and crop it if we're cropping */ if (fr->crop) { int preserve_total_crop; srci = Gif_CopyImage(fr->image); Gif_UncompressImage(srci); /* Zero-delay frames are a special case. You might think it was OK to get rid of totally-cropped delay-0 frames, but many browsers treat zero-delay frames as 100ms. So don't completely crop a zero-delay frame: leave it around. Problem reported by Calle Kabo. */ preserve_total_crop = (dest->nimages == 0 || fr->delay == 0 || (fr->delay < 0 && srci->delay == 0)); if (!crop_image(srci, fr->crop, preserve_total_crop)) { /* We cropped the image out of existence! Be careful not to make 0x0 frames. */ fix_total_crop(dest, srci, i); goto merge_frame_done; } } else { srci = fr->image; Gif_UncompressImage(srci); } /* It was pretty stupid to remove this code, which I did between 1.2b6 and 1.2 */ old_transp = apply_frame_transparent(srci, fr); /* Is it ok to use the old image's compressed version? */ /* 11.Feb.2003 -- It is NOT ok to use the old image's compressed version if you are going to flip or rotate the image. Crash reported by Dan Lasley . */ same_compressed_ok = all_same_compressed_ok; if ((fr->interlacing >= 0 && fr->interlacing != srci->interlace) || fr->flip_horizontal || fr->flip_vertical || fr->rotation) same_compressed_ok = 0; desti = merge_image(dest, fr->stream, srci, same_compressed_ok); srci->transparent = old_transp; /* restore real transparent value */ /* Flipping and rotating, and also setting the screen size */ if (fr->flip_horizontal || fr->flip_vertical || fr->rotation) handle_flip_and_screen(dest, desti, fr); else handle_screen(dest, fr->stream->screen_width, fr->stream->screen_height); /* Names and comments */ if (fr->name || fr->no_name) { Gif_DeleteArray(desti->identifier); desti->identifier = Gif_CopyString(fr->name); } if (fr->no_comments && desti->comment) { Gif_DeleteComment(desti->comment); desti->comment = 0; } if (fr->comment) { if (!desti->comment) desti->comment = Gif_NewComment(); merge_comments(desti->comment, fr->comment); /* delete the comment early to help with memory; set field to 0 so we don't re-free it later */ Gif_DeleteComment(fr->comment); fr->comment = 0; } if (fr->interlacing >= 0) desti->interlace = fr->interlacing; if (fr->left >= 0) desti->left = fr->left + (fr->position_is_offset ? desti->left : 0); if (fr->top >= 0) desti->top = fr->top + (fr->position_is_offset ? desti->top : 0); if (fr->delay >= 0) desti->delay = fr->delay; if (fr->disposal >= 0) desti->disposal = fr->disposal; /* compress immediately if possible to save on memory */ if (desti->img) { if (compress_immediately > 0) { Gif_FullCompressImage(dest, desti, &gif_write_info); Gif_ReleaseUncompressedImage(desti); } else if (desti->compressed) Gif_ReleaseCompressedImage(desti); } else if (compress_immediately <= 0) { Gif_UncompressImage(desti); Gif_ReleaseCompressedImage(desti); } merge_frame_done: /* 6/17/02 store information about image's background */ if (fr->stream->images[0]->transparent >= 0) fr->transparent.haspixel = 2; else if (fr->stream->global && fr->stream->background < fr->stream->global->ncol) { fr->transparent = fr->stream->global->col[fr->stream->background]; fr->transparent.haspixel = 1; } else fr->transparent.haspixel = 0; /* Destroy the copied, cropped image if necessary */ if (fr->crop) Gif_DeleteImage(srci); /* if we can, delete the image's data right now to save memory */ srci = fr->image; assert(srci->refcount > 1); if (--srci->refcount == 1) { /* only 1 reference ==> the reference is from the input stream itself */ Gif_ReleaseUncompressedImage(srci); Gif_ReleaseCompressedImage(srci); } fr->image = 0; /* 5/26/98 Destroy the stream now to help with memory. Assumes that all frames are added with add_frame() which properly increments the stream's refcount. Set field to 0 so we don't redelete */ Gif_DeleteStream(fr->stream); fr->stream = 0; } /** END MERGE LOOP **/ /* Cropping the whole output? */ if (merger[0]->crop && merger[0]->crop == merger[nmerger - 1]->crop) { /* Adjust positions */ int l = 0x7FFFFFFF, t = 0x7FFFFFFF; for (i = 0; i < dest->nimages && (l || t); i++) { Gif_Image *gfi = dest->images[i]; if (gfi->left < l) l = gfi->left; if (gfi->top < t) t = gfi->top; } for (i = 0; i < dest->nimages; i++) { Gif_Image *gfi = dest->images[i]; gfi->left -= l; gfi->top -= t; } /* 13.May.2008: Set the logical screen to the cropped dimensions */ /* 18.May.2008: Unless --crop-transparency is on */ if (merger[0]->crop->transparent_edges) dest->screen_width = dest->screen_height = 0; else { dest->screen_width = (merger[0]->crop->w > 0 ? merger[0]->crop->w : 0); dest->screen_height = (merger[0]->crop->h > 0 ? merger[0]->crop->h : 0); } } /* Set the logical screen from the user's preferences */ if (output_data->screen_width >= 0) dest->screen_width = output_data->screen_width; if (output_data->screen_height >= 0) dest->screen_height = output_data->screen_height; Gif_CalculateScreenSize(dest, 0); /* Find the background color in the colormap, or add it if we can */ set_background(dest, output_data); return dest; } void blank_frameset(Gt_Frameset *fset, int f1, int f2, int delete_object) { int i; if (delete_object) f1 = 0, f2 = -1; if (f2 < 0) f2 = fset->count - 1; for (i = f1; i <= f2; i++) { /* We may have deleted stream and image earlier to save on memory; see above in merge_frame_interval(); but if we didn't, do it now. */ if (FRAME(fset, i).image && FRAME(fset, i).image->refcount > 1) FRAME(fset, i).image->refcount--; Gif_DeleteStream(FRAME(fset, i).stream); Gif_DeleteComment(FRAME(fset, i).comment); if (FRAME(fset, i).nest) blank_frameset(FRAME(fset, i).nest, 0, 0, 1); } if (delete_object) { Gif_DeleteArray(fset->f); Gif_Delete(fset); } } void clear_frameset(Gt_Frameset *fset, int f1) { blank_frameset(fset, f1, -1, 0); fset->count = f1; } gifsicle-1.78/src/dmalloc.h0000644000175000017500000000145512237442106012540 00000000000000#ifndef DMALLOC_H #define DMALLOC_H #include void *debug_malloc_id(size_t, const char *, int); void *debug_realloc_id(void *, size_t, const char *, int); void debug_free_id(void *, const char *, int); void *debug_malloc(size_t); void *debug_realloc(void *, size_t); void debug_free(void *); void dmalloc_info(void *); void dmalloc_report(void); void dmalloc_verbose(const char *); extern size_t dmalloc_live_memory; #define xmalloc(s) debug_malloc_id((s),__FILE__,__LINE__) #define xrealloc(p,s) debug_realloc_id((p),(s),__FILE__,__LINE__) #define xfree(p) debug_free_id((p),__FILE__,__LINE__) #define debug_malloc(s) debug_malloc_id((s),__FILE__,__LINE__) #define debug_realloc(p,s) debug_realloc_id((p),(s),__FILE__,__LINE__) #define debug_free(p) debug_free_id((p),__FILE__,__LINE__) #endif gifsicle-1.78/src/Makefile.bcc0000644000175000017500000000541212237442106013137 00000000000000# Win32 Makefile originally by Emil Mikulic # Updates by Eddie Kohler and # Steven Marthouse # ---------------------------------------------------------- # Makefile adapted for Borland C++ 5.5 Compiler # Stephen Schnipsel # # set this to your bcc directory! MYBCCDIR = D:\BCC55 # # ---------------------------------------------------------- # *** MAKING UNGIFSICLE *** # If `GIFWRITE_OBJ' is defined to `gifwrite.obj', Gifsicle will use # Unisys-patented LZW compression. If it is defined to `ungifwrt.obj', it # will use unpatented run-length compression, which creates larger GIFs but # is completely free software. If you downloaded the ungifsicle package, # which doesn't have `gifwrite.c', you MUST define `GIFWRITE_OBJ' to # `ungifwrt.obj' by commenting the first line below and uncommenting the # second. GIFWRITE_OBJ = gifwrite.obj #GIFWRITE_OBJ = ungifwrt.obj # *** SUPPORTING WILDCARD EXPANSION *** # Define `SETARGV_OBJ' to the filename for the `setargv.obj' object file. # The definition included here works for Microsoft compilers; you will # probably need to change it if you're using a different compiler. You can # define it to the empty string, in which case Gifsicle will compile fine, # but you won't be able to use wildcards in file name arguments. SETARGV_OBJ = $(MYBCCDIR)\LIB\WILDARGS.OBJ CC = bcc32 CFLAGS = -I.. -I..\INCLUDE -DHAVE_CONFIG_H -D_CONSOLE -O2 -D_setmode=setmode GIFSICLE_OBJS = clp.obj fmalloc.obj giffunc.obj gifread.obj gifunopt.obj \ $(GIFWRITE_OBJ) merge.obj optimize.obj quantize.obj support.obj \ xform.obj gifsicle.obj $(SETARGV_OBJ) GIFDIFF_OBJS = clp.obj fmalloc.obj giffunc.obj gifread.obj gifdiff.obj \ $(SETARGV_OBJ) .c.obj: $(CC) $(CFLAGS) -c $< all: gifsicle.exe gifdiff.exe gifsicle.exe: $(GIFSICLE_OBJS) $(CC) $(CFLAGS) -egifsicle $(GIFSICLE_OBJS) gifdiff.exe: $(GIFDIFF_OBJS) $(CC) $(CFLAGS) -egifdiff $(GIFDIFF_OBJS) clp.obj: ..\config.h ..\include\lcdf\clp.h clp.c fmalloc.obj: ..\config.h fmalloc.c giffunc.obj: ..\config.h giffunc.c ..\include\lcdfgif\gif.h gifread.obj: ..\config.h gifread.c ..\include\lcdfgif\gif.h gifwrite.obj: ..\config.h gifwrite.c ..\include\lcdfgif\gif.h ungifwrt.obj: ..\config.h ungifwrt.c ..\include\lcdfgif\gif.h gifunopt.obj: ..\config.h gifunopt.c ..\include\lcdfgif\gif.h merge.obj: ..\config.h gifsicle.h merge.c optimize.obj: ..\config.h gifsicle.h optimize.c quantize.obj: ..\config.h gifsicle.h quantize.c support.obj: ..\config.h gifsicle.h support.c xform.obj: ..\config.h gifsicle.h xform.c gifsicle.obj: ..\config.h gifsicle.h gifsicle.c ..\config.h: win32cfg.h copy win32cfg.h ..\config.h clean: del *.obj del *.exe del *.tds gifsicle-1.78/src/Makefile.in0000644000175000017500000004651012251251264013021 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : bin_PROGRAMS = gifsicle$(EXEEXT) @OTHERPROGRAMS@ EXTRA_PROGRAMS = gifview$(EXEEXT) gifdiff$(EXEEXT) subdir = src DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am strerror.c \ $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am_gifdiff_OBJECTS = clp.$(OBJEXT) giffunc.$(OBJEXT) gifread.$(OBJEXT) \ gifdiff.$(OBJEXT) gifdiff_OBJECTS = $(am_gifdiff_OBJECTS) gifdiff_LDADD = $(LDADD) am_gifsicle_OBJECTS = clp.$(OBJEXT) giffunc.$(OBJEXT) \ gifread.$(OBJEXT) gifunopt.$(OBJEXT) merge.$(OBJEXT) \ optimize.$(OBJEXT) quantize.$(OBJEXT) support.$(OBJEXT) \ xform.$(OBJEXT) gifsicle.$(OBJEXT) gifsicle_OBJECTS = $(am_gifsicle_OBJECTS) am__DEPENDENCIES_1 = @LIBOBJS@ am_gifview_OBJECTS = clp.$(OBJEXT) giffunc.$(OBJEXT) gifread.$(OBJEXT) \ gifx.$(OBJEXT) gifview.$(OBJEXT) gifview_OBJECTS = $(am_gifview_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(gifdiff_SOURCES) $(gifsicle_SOURCES) $(gifview_SOURCES) DIST_SOURCES = $(gifdiff_SOURCES) $(gifsicle_SOURCES) \ $(gifview_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GIFWRITE_O = @GIFWRITE_O@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MALLOC_O = @MALLOC_O@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ OTHERMANS = @OTHERMANS@ OTHERPROGRAMS = @OTHERPROGRAMS@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ WERROR = @WERROR@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign check-news LDADD = @MALLOC_O@ @LIBOBJS@ gifsicle_LDADD = $(LDADD) @GIFWRITE_O@ gifview_LDADD = $(LDADD) @X_LIBS@ @X_PRE_LIBS@ -lX11 @X_EXTRA_LIBS@ gifsicle_DEPENDENCIES = @GIFWRITE_O@ @MALLOC_O@ @LIBOBJS@ gifview_DEPENDENCIES = @MALLOC_O@ @LIBOBJS@ gifdiff_DEPENDENCIES = @MALLOC_O@ @LIBOBJS@ gifsicle_SOURCES = clp.c \ giffunc.c gifread.c gifunopt.c \ gifsicle.h merge.c optimize.c quantize.c support.c xform.c \ gifsicle.c gifview_SOURCES = clp.c \ giffunc.c gifread.c gifx.c \ gifview.c gifdiff_SOURCES = clp.c \ giffunc.c gifread.c \ gifdiff.c AM_CPPFLAGS = $(X_CFLAGS) $(WERROR) -I$(top_srcdir)/include EXTRA_DIST = dmalloc.h dmalloc.c fmalloc.c gifwrite.c ungifwrt.c \ Makefile.bcc Makefile.w32 win32cfg.h all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) gifdiff$(EXEEXT): $(gifdiff_OBJECTS) $(gifdiff_DEPENDENCIES) $(EXTRA_gifdiff_DEPENDENCIES) @rm -f gifdiff$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gifdiff_OBJECTS) $(gifdiff_LDADD) $(LIBS) gifsicle$(EXEEXT): $(gifsicle_OBJECTS) $(gifsicle_DEPENDENCIES) $(EXTRA_gifsicle_DEPENDENCIES) @rm -f gifsicle$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gifsicle_OBJECTS) $(gifsicle_LDADD) $(LIBS) gifview$(EXEEXT): $(gifview_OBJECTS) $(gifview_DEPENDENCIES) $(EXTRA_gifview_DEPENDENCIES) @rm -f gifview$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gifview_OBJECTS) $(gifview_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strerror.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gifdiff.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/giffunc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gifread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gifsicle.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gifunopt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gifview.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gifx.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/merge.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/optimize.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/quantize.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/support.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xform.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -rf $(DEPDIR) ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf $(DEPDIR) ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-binPROGRAMS install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gifsicle-1.78/config.h.in0000644000175000017500000000747212251251270012211 00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ #ifndef GIFSICLE_CONFIG_H #define GIFSICLE_CONFIG_H /* Define when using the debugging malloc library. */ #undef DMALLOC /* Define to the number of arguments to gettimeofday (gifview only). */ #undef GETTIMEOFDAY_PROTO /* Define if GIF LZW compression is off. */ #undef GIF_UNGIF /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `mkstemp' function. */ #undef HAVE_MKSTEMP /* Define to 1 if you have the `pow' function. */ #undef HAVE_POW /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strtoul' function. */ #undef HAVE_STRTOUL /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if the system has the type `uintptr_t'. */ #undef HAVE_UINTPTR_T /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define if you have u_intXX_t types but not uintXX_t types. */ #undef HAVE_U_INT_TYPES /* Define to write GIFs to stdout even when stdout is a terminal. */ #undef OUTPUT_GIF_TO_TERMINAL /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Pathname separator character ('/' on Unix). */ #undef PATHNAME_SEPARATOR /* Define to a function that returns a random number. */ #undef RANDOM /* The size of `unsigned int', as computed by sizeof. */ #undef SIZEOF_UNSIGNED_INT /* The size of `unsigned long', as computed by sizeof. */ #undef SIZEOF_UNSIGNED_LONG /* The size of `void *', as computed by sizeof. */ #undef SIZEOF_VOID_P /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION /* Define if X is not available. */ #undef X_DISPLAY_MISSING /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif #ifdef __cplusplus extern "C" { #endif /* Use either the clean-failing malloc library in fmalloc.c, or the debugging malloc library in dmalloc.c. */ #ifdef DMALLOC # include "dmalloc.h" # define Gif_DeleteFunc (&debug_free) # define Gif_DeleteArrayFunc (&debug_free) #else # include # define xmalloc(s) fail_die_malloc((s),__FILE__,__LINE__) # define xrealloc(p,s) fail_die_realloc((p),(s),__FILE__,__LINE__) # define xfree free void *fail_die_malloc(size_t, const char *, int); void *fail_die_realloc(void *, size_t, const char *, int); #endif /* Prototype strerror if we don't have it. */ #ifndef HAVE_STRERROR char *strerror(int errno); #endif #ifdef __cplusplus } /* Get rid of a possible inline macro under C++. */ # define inline inline #endif #endif /* GIFSICLE_CONFIG_H */ gifsicle-1.78/missing0000755000175000017500000001533112237442114011561 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2012-06-26.16; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # 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, 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, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'automa4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gifsicle-1.78/configure.ac0000644000175000017500000001454312251251262012452 00000000000000dnl Process this file with autoconf to produce a configure script. AC_INIT([gifsicle], [1.78]) AC_CONFIG_SRCDIR([src/gifsicle.h]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE AC_PROG_MAKE_SET AC_PROG_CC AC_PROG_CPP AC_C_CONST AC_C_INLINE build_gifview=maybe AC_ARG_ENABLE(gifview, [ --disable-gifview do not build gifview, a GIF viewer for X11], if test "x$enableval" != xyes ; then build_gifview=no fi) build_gifdiff=yes AC_ARG_ENABLE(gifdiff, [ --disable-gifdiff do not build gifdiff, a utility for comparing GIFs], if test "x$enableval" != xyes ; then build_gifdiff=no fi) use_dmalloc= AC_ARG_ENABLE(dmalloc, [ --enable-dmalloc build with debugging malloc library], if test "x$enableval" = xyes ; then use_dmalloc=yes fi) AC_ARG_ENABLE(warnings, [ --enable-warnings compile with -W -Wall], if test "x$enableval" = xyes ; then CC="$CC -W -Wall" fi) AC_ARG_ENABLE([werror], [ --enable-werror compile with -Werror], if test "x$enableval" = xyes ; then WERROR="-Werror" fi) AC_SUBST([WERROR]) AC_ARG_ENABLE(all, [ --enable-all --enable-gifview --enable-gifdiff --enable-warnings], if test "x$enableval" = xyes ; then build_gifview=yes build_gifdiff=yes CC="$CC -W -Wall" fi) ungif= AC_ARG_ENABLE(ungif, [ --enable-ungif build without compression], if test "x$enableval" = xyes ; then ungif=yes fi) dnl dnl Choose programs to build. Always build gifsicle dnl OTHERPROGRAMS="" OTHERMANS="" if test "x$build_gifview" = xyes -o "x$build_gifview" = xmaybe; then AC_PATH_XTRA if test "x$no_x" = xyes; then if test "x$build_gifview" = xyes; then AC_MSG_ERROR([ ****************************************************************************** Cannot find X, but you explicitly requested that gifview be built. You may need to install an X11 development package to get the X headers, supply a '--with-x' option, or simply '--disable-gifview'.]) else AC_MSG_WARN([Not compiling gifview since X is not available.]) build_gifview=no fi else build_gifview=yes fi fi if test "x$build_gifview" = xyes ; then OTHERPROGRAMS="$OTHERPROGRAMS gifview"'$(EXEEXT)' OTHERMANS="$OTHERMANS gifview.1" AC_CACHE_CHECK(for gettimeofday prototype, ac_cv_gettimeofday, [AC_TRY_COMPILE([#include #include ], [gettimeofday((void *)0, (void *)0);], [AC_TRY_COMPILE([#include #include ], [gettimeofday((void *)0);], ac_cv_gettimeofday=0, ac_cv_gettimeofday=2)], ac_cv_gettimeofday=1)]) AC_DEFINE_UNQUOTED(GETTIMEOFDAY_PROTO, $ac_cv_gettimeofday, [Define to the number of arguments to gettimeofday (gifview only).]) else AC_DEFINE_UNQUOTED(X_DISPLAY_MISSING, 1, [Define if X is not available.]) fi if test "x$build_gifdiff" = xyes ; then OTHERPROGRAMS="$OTHERPROGRAMS gifdiff"'$(EXEEXT)' OTHERMANS="$OTHERMANS gifdiff.1" fi AC_SUBST(OTHERPROGRAMS)dnl AC_SUBST(OTHERMANS)dnl dnl dnl Set up malloc library dnl if test "x$use_dmalloc" = xyes ; then AC_DEFINE(DMALLOC, 1, [Define when using the debugging malloc library.]) MALLOC_O=dmalloc.o else MALLOC_O=fmalloc.o fi AC_SUBST(MALLOC_O) dnl dnl Set up `ungif' support dnl if test "x$ungif" = xyes -o "x$GIFSICLE_UNGIF" = xyes ; then GIFWRITE_O=ungifwrt.o AC_DEFINE(GIF_UNGIF, 1, [Define if GIF LZW compression is off.]) elif test -r $srcdir/src/gifwrite.c ; then GIFWRITE_O=gifwrite.o else AC_MSG_ERROR(This version of gifsicle cannot create compressed GIFs. *** Either reconfigure with the \`--enable-ungif' option or download the *** version with compression from http://www.lcdf.org/gifsicle/) fi AC_SUBST(GIFWRITE_O) dnl dnl random or rand, strerror, strtoul, mkstemp, sys/select.h dnl AC_CHECK_FUNC([random], [random_func=random], [random_func=rand]) AC_DEFINE_UNQUOTED(RANDOM, ${random_func}, [Define to a function that returns a random number.]) AC_REPLACE_FUNCS([strerror]) AC_CHECK_FUNCS([strtoul mkstemp]) AC_SEARCH_LIBS([pow], [m], [AC_DEFINE([HAVE_POW], [1], [Define to 1 if you have the `pow' function.])]) AC_CHECK_HEADERS([sys/select.h inttypes.h unistd.h]) dnl dnl integer types dnl AC_CHECK_HEADERS(inttypes.h, have_inttypes_h=yes, have_inttypes_h=no) AC_CHECK_HEADERS(sys/types.h, have_sys_types_h=yes, have_sys_types_h=no) if test $have_inttypes_h = no -a $have_sys_types_h = yes; then AC_CACHE_CHECK([for uintXX_t typedefs], ac_cv_uint_t, [AC_EGREP_HEADER(dnl changequote(<<,>>)<<(^|[^a-zA-Z_0-9])uint32_t[^a-zA-Z_0-9]>>changequote([,]), sys/types.h, ac_cv_uint_t=yes, ac_cv_uint_t=no)]) fi if test $have_inttypes_h = no -a $have_sys_types_h = yes -a "$ac_cv_uint_t" = no; then AC_CACHE_CHECK([for u_intXX_t typedefs], ac_cv_u_int_t, [AC_EGREP_HEADER(dnl changequote(<<,>>)<<(^|[^a-zA-Z_0-9])u_int32_t[^a-zA-Z_0-9]>>changequote([,]), sys/types.h, ac_cv_u_int_t=yes, ac_cv_u_int_t=no)]) fi if test $have_inttypes_h = yes -o "$ac_cv_uint_t" = yes; then : elif test "$ac_cv_u_int_t" = yes; then AC_DEFINE([HAVE_U_INT_TYPES], [1], [Define if you have u_intXX_t types but not uintXX_t types.]) fi AC_CHECK_TYPES([uintptr_t], [], [], [#if HAVE_INTTYPES_H # include #endif #if HAVE_SYS_TYPES_H # include #endif ]) AC_CHECK_SIZEOF([unsigned int]) AC_CHECK_SIZEOF([unsigned long]) AC_CHECK_SIZEOF([void *]) dnl dnl verbatim portions of the header dnl AC_DEFINE_UNQUOTED(PATHNAME_SEPARATOR, ['/'], [Pathname separator character ('/' on Unix).]) if false; then AC_DEFINE(OUTPUT_GIF_TO_TERMINAL, 1, [Define to write GIFs to stdout even when stdout is a terminal.]) fi AH_TOP([#ifndef GIFSICLE_CONFIG_H #define GIFSICLE_CONFIG_H]) AH_BOTTOM([#ifdef __cplusplus extern "C" { #endif /* Use either the clean-failing malloc library in fmalloc.c, or the debugging malloc library in dmalloc.c. */ #ifdef DMALLOC # include "dmalloc.h" # define Gif_DeleteFunc (&debug_free) # define Gif_DeleteArrayFunc (&debug_free) #else # include # define xmalloc(s) fail_die_malloc((s),__FILE__,__LINE__) # define xrealloc(p,s) fail_die_realloc((p),(s),__FILE__,__LINE__) # define xfree free void *fail_die_malloc(size_t, const char *, int); void *fail_die_realloc(void *, size_t, const char *, int); #endif /* Prototype strerror if we don't have it. */ #ifndef HAVE_STRERROR char *strerror(int errno); #endif #ifdef __cplusplus } /* Get rid of a possible inline macro under C++. */ # define inline inline #endif #endif /* GIFSICLE_CONFIG_H */]) dnl dnl Output dnl AC_OUTPUT(Makefile src/Makefile) gifsicle-1.78/configure0000755000175000017500000062231212251251265012075 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for gifsicle 1.78. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='gifsicle' PACKAGE_TARNAME='gifsicle' PACKAGE_VERSION='1.78' PACKAGE_STRING='gifsicle 1.78' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_unique_file="src/gifsicle.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS EGREP GREP LIBOBJS GIFWRITE_O MALLOC_O OTHERMANS OTHERPROGRAMS X_EXTRA_LIBS X_LIBS X_PRE_LIBS X_CFLAGS XMKMF WERROR CPP am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking enable_gifview enable_gifdiff enable_dmalloc enable_warnings enable_werror enable_all enable_ungif with_x ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP XMKMF' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures gifsicle 1.78 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/gifsicle] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of gifsicle 1.78:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --disable-gifview do not build gifview, a GIF viewer for X11 --disable-gifdiff do not build gifdiff, a utility for comparing GIFs --enable-dmalloc build with debugging malloc library --enable-warnings compile with -W -Wall --enable-werror compile with -Werror --enable-all --enable-gifview --enable-gifdiff --enable-warnings --enable-ungif build without compression Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-x use the X Window System Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor XMKMF Path to xmkmf, Makefile generator for X Window System Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF gifsicle configure 1.78 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by gifsicle $as_me 1.78, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" am__api_version='1.13' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='gifsicle' VERSION='1.78' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac build_gifview=maybe # Check whether --enable-gifview was given. if test "${enable_gifview+set}" = set; then : enableval=$enable_gifview; if test "x$enableval" != xyes ; then build_gifview=no fi fi build_gifdiff=yes # Check whether --enable-gifdiff was given. if test "${enable_gifdiff+set}" = set; then : enableval=$enable_gifdiff; if test "x$enableval" != xyes ; then build_gifdiff=no fi fi use_dmalloc= # Check whether --enable-dmalloc was given. if test "${enable_dmalloc+set}" = set; then : enableval=$enable_dmalloc; if test "x$enableval" = xyes ; then use_dmalloc=yes fi fi # Check whether --enable-warnings was given. if test "${enable_warnings+set}" = set; then : enableval=$enable_warnings; if test "x$enableval" = xyes ; then CC="$CC -W -Wall" fi fi # Check whether --enable-werror was given. if test "${enable_werror+set}" = set; then : enableval=$enable_werror; if test "x$enableval" = xyes ; then WERROR="-Werror" fi fi # Check whether --enable-all was given. if test "${enable_all+set}" = set; then : enableval=$enable_all; if test "x$enableval" = xyes ; then build_gifview=yes build_gifdiff=yes CC="$CC -W -Wall" fi fi ungif= # Check whether --enable-ungif was given. if test "${enable_ungif+set}" = set; then : enableval=$enable_ungif; if test "x$enableval" = xyes ; then ungif=yes fi fi OTHERPROGRAMS="" OTHERMANS="" if test "x$build_gifview" = xyes -o "x$build_gifview" = xmaybe; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # We can compile using X headers with no special include directory. ac_x_includes= else for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.i conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi if test "$no_x" = yes; then # Not all programs may use this symbol, but it does not hurt to define it. $as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= else if test -n "$x_includes"; then X_CFLAGS="$X_CFLAGS -I$x_includes" fi # It would also be nice to do this for all -L options, not just this one. if test -n "$x_libraries"; then X_LIBS="$X_LIBS -L$x_libraries" # For Solaris; some versions of Sun CC require a space after -R and # others require no space. Words are not sufficient . . . . { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 $as_echo_n "checking whether -R must be followed by a space... " >&6; } ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" ac_xsave_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } X_LIBS="$X_LIBS -R$x_libraries" else LIBS="$ac_xsave_LIBS -R $x_libraries" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } X_LIBS="$X_LIBS -R $x_libraries" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 $as_echo "neither works" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_c_werror_flag=$ac_xsave_c_werror_flag LIBS=$ac_xsave_LIBS fi # Check for system-dependent libraries X programs must link with. # Do this before checking for the system-independent R6 libraries # (-lICE), since we may need -lsocket or whatever for X linking. if test "$ISC" = yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" else # Martyn Johnson says this is needed for Ultrix, if the X # libraries were built with DECnet support. And Karl Berry says # the Alpha needs dnet_stub (dnet does not exist). ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XOpenDisplay (); int main () { return XOpenDisplay (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_dnet_ntoa=yes else ac_cv_lib_dnet_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" fi if test $ac_cv_lib_dnet_dnet_ntoa = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet_stub $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_stub_dnet_ntoa=yes else ac_cv_lib_dnet_stub_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" fi fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_xsave_LIBS" # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, # to get the SysV transport functions. # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) # needs -lnsl. # The nsl library prevents programs from opening the X display # on Irix 5.2, according to T.E. Dickey. # The functions gethostbyname, getservbyname, and inet_addr are # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = xyes; then : fi if test $ac_cv_func_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if ${ac_cv_lib_nsl_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname=yes else ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" fi if test $ac_cv_lib_nsl_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 $as_echo_n "checking for gethostbyname in -lbsd... " >&6; } if ${ac_cv_lib_bsd_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bsd_gethostbyname=yes else ac_cv_lib_bsd_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 $as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" fi fi fi # lieder@skyler.mavd.honeywell.com says without -lsocket, # socket/setsockopt and other routines are undefined under SCO ODT # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary # on later versions), says Simon Leinen: it contains gethostby* # variants that don't use the name server (or something). -lsocket # must be given before -lnsl if both are needed. We assume that # if connect needs -lnsl, so does gethostbyname. ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = xyes; then : fi if test $ac_cv_func_connect = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 $as_echo_n "checking for connect in -lsocket... " >&6; } if ${ac_cv_lib_socket_connect+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char connect (); int main () { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_connect=yes else ac_cv_lib_socket_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 $as_echo "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = xyes; then : X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" fi fi # Guillermo Gomez says -lposix is necessary on A/UX. ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" if test "x$ac_cv_func_remove" = xyes; then : fi if test $ac_cv_func_remove = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 $as_echo_n "checking for remove in -lposix... " >&6; } if ${ac_cv_lib_posix_remove+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lposix $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char remove (); int main () { return remove (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_posix_remove=yes else ac_cv_lib_posix_remove=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 $as_echo "$ac_cv_lib_posix_remove" >&6; } if test "x$ac_cv_lib_posix_remove" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" fi fi # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" if test "x$ac_cv_func_shmat" = xyes; then : fi if test $ac_cv_func_shmat = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 $as_echo_n "checking for shmat in -lipc... " >&6; } if ${ac_cv_lib_ipc_shmat+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lipc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shmat (); int main () { return shmat (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ipc_shmat=yes else ac_cv_lib_ipc_shmat=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 $as_echo "$ac_cv_lib_ipc_shmat" >&6; } if test "x$ac_cv_lib_ipc_shmat" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" fi fi fi # Check for libraries that X11R6 Xt/Xaw programs need. ac_save_LDFLAGS=$LDFLAGS test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to # check for ICE first), but we must link in the order -lSM -lICE or # we get undefined symbols. So assume we have SM if we have ICE. # These have to be linked with before -lX11, unlike the other # libraries we check for below, so use a different variable. # John Interrante, Karl Berry { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 $as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lICE $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char IceConnectionNumber (); int main () { return IceConnectionNumber (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ICE_IceConnectionNumber=yes else ac_cv_lib_ICE_IceConnectionNumber=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 $as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then : X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" fi LDFLAGS=$ac_save_LDFLAGS fi if test "x$no_x" = xyes; then if test "x$build_gifview" = xyes; then as_fn_error $? " ****************************************************************************** Cannot find X, but you explicitly requested that gifview be built. You may need to install an X11 development package to get the X headers, supply a '--with-x' option, or simply '--disable-gifview'." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Not compiling gifview since X is not available." >&5 $as_echo "$as_me: WARNING: Not compiling gifview since X is not available." >&2;} build_gifview=no fi else build_gifview=yes fi fi if test "x$build_gifview" = xyes ; then OTHERPROGRAMS="$OTHERPROGRAMS gifview"'$(EXEEXT)' OTHERMANS="$OTHERMANS gifview.1" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gettimeofday prototype" >&5 $as_echo_n "checking for gettimeofday prototype... " >&6; } if ${ac_cv_gettimeofday+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { gettimeofday((void *)0, (void *)0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { gettimeofday((void *)0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_gettimeofday=0 else ac_cv_gettimeofday=2 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else ac_cv_gettimeofday=1 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gettimeofday" >&5 $as_echo "$ac_cv_gettimeofday" >&6; } cat >>confdefs.h <<_ACEOF #define GETTIMEOFDAY_PROTO $ac_cv_gettimeofday _ACEOF else cat >>confdefs.h <<_ACEOF #define X_DISPLAY_MISSING 1 _ACEOF fi if test "x$build_gifdiff" = xyes ; then OTHERPROGRAMS="$OTHERPROGRAMS gifdiff"'$(EXEEXT)' OTHERMANS="$OTHERMANS gifdiff.1" fi if test "x$use_dmalloc" = xyes ; then $as_echo "#define DMALLOC 1" >>confdefs.h MALLOC_O=dmalloc.o else MALLOC_O=fmalloc.o fi if test "x$ungif" = xyes -o "x$GIFSICLE_UNGIF" = xyes ; then GIFWRITE_O=ungifwrt.o $as_echo "#define GIF_UNGIF 1" >>confdefs.h elif test -r $srcdir/src/gifwrite.c ; then GIFWRITE_O=gifwrite.o else as_fn_error $? "This version of gifsicle cannot create compressed GIFs. *** Either reconfigure with the \`--enable-ungif' option or download the *** version with compression from http://www.lcdf.org/gifsicle/" "$LINENO" 5 fi ac_fn_c_check_func "$LINENO" "random" "ac_cv_func_random" if test "x$ac_cv_func_random" = xyes; then : random_func=random else random_func=rand fi cat >>confdefs.h <<_ACEOF #define RANDOM ${random_func} _ACEOF ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror" if test "x$ac_cv_func_strerror" = xyes; then : $as_echo "#define HAVE_STRERROR 1" >>confdefs.h else case " $LIBOBJS " in *" strerror.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strerror.$ac_objext" ;; esac fi for ac_func in strtoul mkstemp do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pow" >&5 $as_echo_n "checking for library containing pow... " >&6; } if ${ac_cv_search_pow+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pow (); int main () { return pow (); ; return 0; } _ACEOF for ac_lib in '' m; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_pow=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_pow+:} false; then : break fi done if ${ac_cv_search_pow+:} false; then : else ac_cv_search_pow=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pow" >&5 $as_echo "$ac_cv_search_pow" >&6; } ac_res=$ac_cv_search_pow if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_POW 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/select.h inttypes.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in inttypes.h do : ac_fn_c_check_header_mongrel "$LINENO" "inttypes.h" "ac_cv_header_inttypes_h" "$ac_includes_default" if test "x$ac_cv_header_inttypes_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_INTTYPES_H 1 _ACEOF have_inttypes_h=yes else have_inttypes_h=no fi done for ac_header in sys/types.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" if test "x$ac_cv_header_sys_types_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_TYPES_H 1 _ACEOF have_sys_types_h=yes else have_sys_types_h=no fi done if test $have_inttypes_h = no -a $have_sys_types_h = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uintXX_t typedefs" >&5 $as_echo_n "checking for uintXX_t typedefs... " >&6; } if ${ac_cv_uint_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])uint32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_uint_t=yes else ac_cv_uint_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_uint_t" >&5 $as_echo "$ac_cv_uint_t" >&6; } fi if test $have_inttypes_h = no -a $have_sys_types_h = yes -a "$ac_cv_uint_t" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for u_intXX_t typedefs" >&5 $as_echo_n "checking for u_intXX_t typedefs... " >&6; } if ${ac_cv_u_int_t+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "(^|[^a-zA-Z_0-9])u_int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then : ac_cv_u_int_t=yes else ac_cv_u_int_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_u_int_t" >&5 $as_echo "$ac_cv_u_int_t" >&6; } fi if test $have_inttypes_h = yes -o "$ac_cv_uint_t" = yes; then : elif test "$ac_cv_u_int_t" = yes; then $as_echo "#define HAVE_U_INT_TYPES 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "#if HAVE_INTTYPES_H # include #endif #if HAVE_SYS_TYPES_H # include #endif " if test "x$ac_cv_type_uintptr_t" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UINTPTR_T 1 _ACEOF fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned int" >&5 $as_echo_n "checking size of unsigned int... " >&6; } if ${ac_cv_sizeof_unsigned_int+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned int))" "ac_cv_sizeof_unsigned_int" "$ac_includes_default"; then : else if test "$ac_cv_type_unsigned_int" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (unsigned int) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_unsigned_int=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_int" >&5 $as_echo "$ac_cv_sizeof_unsigned_int" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UNSIGNED_INT $ac_cv_sizeof_unsigned_int _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long" >&5 $as_echo_n "checking size of unsigned long... " >&6; } if ${ac_cv_sizeof_unsigned_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long))" "ac_cv_sizeof_unsigned_long" "$ac_includes_default"; then : else if test "$ac_cv_type_unsigned_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (unsigned long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_unsigned_long=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long" >&5 $as_echo "$ac_cv_sizeof_unsigned_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 $as_echo_n "checking size of void *... " >&6; } if ${ac_cv_sizeof_void_p+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : else if test "$ac_cv_type_void_p" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (void *) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_void_p=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 $as_echo "$ac_cv_sizeof_void_p" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_VOID_P $ac_cv_sizeof_void_p _ACEOF cat >>confdefs.h <<_ACEOF #define PATHNAME_SEPARATOR '/' _ACEOF if false; then $as_echo "#define OUTPUT_GIF_TO_TERMINAL 1" >>confdefs.h fi ac_config_files="$ac_config_files Makefile src/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by gifsicle $as_me 1.78, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ gifsicle config.status 1.78 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi gifsicle-1.78/README.md0000644000175000017500000001232712244127005011440 00000000000000Gifsicle ======== Gifsicle manipulates GIF image files in many different ways. Depending on command line options, it can merge several GIFs into a GIF animation; explode an animation into its component frames; change individual frames in an animation; turn interlacing on and off; add transparency; add delays, disposals, and looping to animations; add or remove comments; flip and rotate; optimize animations for space; change images' colormaps; and other things. Gifview, a companion program, displays GIF images and animations on an X display. It can display multi-frame GIFs either as slideshows, displaying one frame at a time, or as real-time animations. Gifdiff, another companion program, checks two GIF files for identical visual appearance. This is probably most useful for testing GIF-manipulating software. Each of these programs has a manpage, `PROGRAMNAME.1`. The Gifsicle package comes with NO WARRANTY, express or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. See `NEWS` in this directory for a detailed listing of changes in recent versions. The Gifsicle home page is: http://www.lcdf.org/gifsicle/ Building Gifsicle on UNIX ------------------------- Type `./configure`, then `make`. If `./configure` does not exist (you downloaded from Github), run `autoreconf -i` first. `./configure` accepts the usual options; see `INSTALL` for more details. To build without gifview (for example, if you don't have X11), use `./configure --disable-gifview`. To build without gifdiff, use `./configure --disable-gifdiff`. `make install` will build and install Gifsicle and its manual page (under /usr/local by default). Building Gifsicle on Windows ---------------------------- To build Gifsicle on Windows using Visual C, change into the `src` directory and run nmake -f Makefile.w32 Gifview will not be built. The makefile is from Emil Mikulic with updates by Eddie Kohler and Steven Marthouse . To build Gifsicle on Windows using Borland C++, change into the `src` directory and run nmake -f Makefile.bcc Stephen Schnipsel provided `Makefile.bcc`. You will need to edit one of these Makefiles to use a different compiler. You can edit it with any text editor (like Notepad). See the file for more information. Contact ------- Please write me if you have trouble building or running Gifsicle, or if you have suggestions or patches. Eddie Kohler, ekohler@gmail.com http://www.read.seas.harvard.edu/~kohler/ The GIF Patents and UnGIFs -------------------------- Patents formerly restricted use of the Lempel-Ziv-Welch compression algorithm used in GIFs. As of October 1, 2006, it is believed (by the Software Freedom Law Center and the Free Software Foundation, among others) that there are no significant patent claims interfering with employment of the GIF format. For that reason, Gifsicle is completely free software. Nonetheless, Gifsicle can be configured to write run-length-encoded GIFs, rather than LZW-compressed GIFs, avoiding these obsolete patents. This idea was first implemented independently by Toshio Kuratomi and Hutchison Avenue Software Corporation (http://www.hasc.com/, ). Turn this on by giving `./configure` the `--enable-ungif` switch. Now that the patents have expired there is no good reason to turn on this switch, which can make GIFs a factor of 2 larger or more. If your copy of Gifsicle says `(ungif)` when you run `gifsicle --version`, it is writing run-length-encoded GIFs. Copyright/License ----------------- All source code is Copyright (C) 1997-2013 Eddie Kohler. IF YOU PLAN TO USE GIFSICLE ONLY TO CREATE OR MODIFY GIF IMAGES, DON'T WORRY ABOUT THE REST OF THIS SECTION. Anyone can use Gifsicle however they wish; the license applies only to those who plan to copy, distribute, or alter its code. If you use Gifsicle for an organizational or commercial Web site, I would appreciate a link to the Gifsicle home page on any 'About This Server' page, but it's not required. This code is distributed under the GNU General Public License, Version 2 (and only Version 2). The GNU General Public License is available via the Web at or in the 'COPYING' file in this directory. The following alternative license may be used at your discretion. Permission is granted to copy, distribute, or alter Gifsicle, whole or in part, as long as source code copyright notices are kept intact, with the following restriction: Developers or distributors who plan to use Gifsicle code, whole or in part, in a product whose source code will not be made available to the end user -- more precisely, in a context which would violate the GPL -- MUST contact the author and obtain permission before doing so. Authors ------- Eddie Kohler http://www.read.seas.harvard.edu/~kohler/ He wrote it. Anne Dudfield http://www.frii.com/~annied/ She named it. David Hedbor Many bug reports and constructive whining about the optimizer. Emil Mikulic Win32 port help. Hans Dinsen-Hansen http://www.danbbs.dk/~dino/ Adaptive tree method for GIF writing. gifsicle-1.78/Makefile.in0000644000175000017500000007153312251251264012235 00000000000000# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = . DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.h.in COPYING INSTALL NEWS depcomp install-sh \ missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 am__installdirs = "$(DESTDIR)$(man1dir)" NROFF = nroff MANS = $(man_MANS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GIFWRITE_O = @GIFWRITE_O@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MALLOC_O = @MALLOC_O@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ OTHERMANS = @OTHERMANS@ OTHERPROGRAMS = @OTHERPROGRAMS@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ WERROR = @WERROR@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign check-news SUBDIRS = src man_MANS = gifsicle.1 @OTHERMANS@ EXTRA_DIST = COPYING README.md gifsicle.spec \ include/lcdf/clp.h include/lcdf/inttypes.h \ include/lcdfgif/gif.h include/lcdfgif/gifx.h \ gifsicle.1 gifview.1 gifdiff.1 logo.gif logo1.gif all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @if test ! -f $@; then rm -f stamp-h1; else :; fi @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 install-man1: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) @case `sed 15q $(srcdir)/NEWS` in \ *"$(VERSION)"*) : ;; \ *) \ echo "NEWS not updated; not releasing" 1>&2; \ exit 1;; \ esac $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(MANS) config.h installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-man install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-man1 install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-man uninstall-man: uninstall-man1 .MAKE: $(am__recursive_targets) all install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-generic distclean-hdr \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-man1 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags \ tags-am uninstall uninstall-am uninstall-man uninstall-man1 gifsicle: @cd src && $(MAKE) gifsicle gifdiff: @cd src && $(MAKE) gifdiff gifview: @cd src && $(MAKE) gifview srclinks: cd $(top_srcdir); sh ./sourcecheckout.sh versionize: perl -pi -e "s/^\\.ds V.*/.ds V $(VERSION)/;" $(top_srcdir)/gifsicle.1 $(top_srcdir)/gifview.1 $(top_srcdir)/gifdiff.1 perl -pi -e "s/^Version:(\s+).*/Version:"'$$'"{1}$(VERSION)/; s/$(PACKAGE)-[\w.]+\.tar\.gz/$(PACKAGE)-$(VERSION).tar.gz/;" $(top_srcdir)/gifsicle.spec perl -pi -e "s/gifsicle [\d.]+/gifsicle $(VERSION)/; s/VERSION \"[\w.]+/VERSION \"$(VERSION)/;" $(top_srcdir)/src/win32cfg.h rpm: dist buildarch=`rpm --showrc | awk '/^build arch/ { print $$4; }'` ; \ mkdir -p /tmp/rpm-gfs/SOURCES /tmp/rpm-gfs/RPMS/$$buildarch \ /tmp/rpm-gfs/BUILD ; \ echo 'include: /usr/lib/rpm/rpmrc' > /tmp/rpm-gfs/rc ; \ echo 'macrofiles: /usr/lib/rpm/macros:/tmp/rpm-gfs/macros' >> /tmp/rpm-gfs/rc ; \ echo '%_topdir /tmp/rpm-gfs' > /tmp/rpm-gfs/macros ; \ cp logo1.gif $(PACKAGE)-$(VERSION).tar.gz /tmp/rpm-gfs/SOURCES ; \ rpmbuild --rcfile /tmp/rpm-gfs/rc -bb gifsicle.spec ; \ cp /tmp/rpm-gfs/RPMS/$$buildarch/*.rpm . rm -rf /tmp/rpm-gfs rpm-ungif: dist buildarch=`rpm --showrc | awk '/^build arch/ { print $$4; }'` ; \ mkdir -p /tmp/rpm-ugfs/SOURCES /tmp/rpm-ugfs/RPMS/$$buildarch \ /tmp/rpm-ugfs/BUILD ; \ echo 'include: /usr/lib/rpm/rpmrc' > /tmp/rpm-ugfs/rc ; \ echo 'macrofiles: /usr/lib/rpm/macros:/tmp/rpm-ugfs/macros' >> /tmp/rpm-ugfs/rc ; \ echo '%_topdir /tmp/rpm-ugfs' > /tmp/rpm-ugfs/macros ; \ cp logo1.gif $(PACKAGE)-$(VERSION).tar.gz /tmp/rpm-ugfs/SOURCES ; \ GIFSICLE_UNGIF=yes rpmbuild --rcfile /tmp/rpm-ugfs/rc -bb gifsicle.spec ; \ cp /tmp/rpm-ugfs/RPMS/$$buildarch/*.rpm `echo /tmp/rpm-ugfs/RPMS/$$buildarch/*.rpm | sed 's/.*gifsicle/ungifsicle/'` rm -rf /tmp/rpm-ugfs dist-ungif: dist $(AMTAR) xzf gifsicle-$(VERSION).tar.gz @rm gifsicle-$(VERSION)/src/gifwrite.c rm -rf ungifsicle-$(VERSION) mv gifsicle-$(VERSION) ungifsicle-$(VERSION) GZIP=$(GZIP_ENV) $(AMTAR) chozf ungifsicle-$(VERSION).tar.gz ungifsicle-$(VERSION) rm -rf ungifsicle-$(VERSION) .PHONY: srclinks versionize rpm dist-ungif rpm-ungif # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: